############################################################################
#
#	File:     fullimag.icn
#
#	Subject:  Procedures to produce complete image of structured data
#
#	Author:   Robert J. Alexander
#
#	Date:     May 23, 1996
#
############################################################################
#
#   This file is in the public domain.
#
############################################################################
#
#  fullimage() -- enhanced image()-type procedure that outputs all data
#  contained in structured types.  The "level" argument tells it how far
#  to descend into nested structures (defaults to unlimited).
#
############################################################################

global fullimage_level,fullimage_maxlevel,fullimage_done,fullimage_used,
      fullimage_indent

procedure fullimage(x,indent,maxlevel)
   local tr,s,t
   #
   #  Initialize
   #
   tr := &trace ; &trace := 0    # turn off trace till we're done
   fullimage_level := 1
   fullimage_indent := indent
   fullimage_maxlevel := \maxlevel | 0
   fullimage_done := table()
   fullimage_used := set()
   #
   #  Call fullimage_() to do the work.
   #
   s := fullimage_(x)
   #
   #  Remove unreferenced tags from the result string, and even
   #  renumber them.
   #
   fullimage_done := table()
   s ? {
      s := ""
      while s ||:= tab(upto('\'"<')) do {
	 case t := move(1) of {
	    "\"" | "'": {
	       s ||:= t
	       while (s ||:= tab(find(t) + 1)) \ 1 & s[-2] ~== "\\"
	       }
	    "<": {
	       t := +tab(find(">")) & move(1)
	       if member(fullimage_used,t) then {
		  /fullimage_done[t] := *fullimage_done + 1
		  s ||:= "<" || fullimage_done[t] || ">"
		  }
	       }
	    }
	 }
      s ||:= tab(0)
      }
   #
   #  Clean up and return.
   #
   fullimage_done := fullimage_used := &null     # remove structures
   &trace := tr                  # restore &trace
   return s
end


procedure fullimage_(x,noindent)
   local s,t,tr
   t := type(x)
   s := case t of {
      "null" | "string" | "integer" | "real" | "co-expression" | "cset" |
      "file" | "window" | "procedure" | "external": image(x)
      default: fullimage_structure(x)
      }
   #
   #  Return the result.
   #
   return (
      if \fullimage_indent & not \noindent then
	 "\n" || repl(fullimage_indent,fullimage_level - 1) || s
      else
	    s
   )
end

procedure fullimage_structure(x)
   local sep,s,t,tag,y
   #
   #  If this structure has already been output, just output its tag.
   #
   if \(tag := fullimage_done[x]) then {
      insert(fullimage_used,tag)
      return "<" || tag || ">"
      }
   #
   #  If we've reached the max level, just output a normal image
   #  enclosed in braces to indicate end of the line.
   #
   if fullimage_level = fullimage_maxlevel then
	 return "{" || image(x) || "}"
   #
   #  Output the structure in a style indicative of its type.
   #
   fullimage_level +:= 1
   fullimage_done[x] := tag := *fullimage_done + 1
   if (t := type(x)) == ("table" | "set") then x := sort(x)
   s := "<" || tag || ">" || if t == "list" then "[" else t || "("
   sep := ""
   if t == "table" then every y := !x do {
      s ||:= sep || fullimage_(y[1]) || "->" || fullimage_(y[2],"noindent")
      sep := ","
      }
   else every s ||:= sep || fullimage_(!x) do sep := ","
   fullimage_level -:= 1
   return s || if t == "list" then "]" else ")"
end
