############################################################################
#
#	File:     tgrprep.icn
#
#	Subject:  Program to prepare TIGER line chains
#
#	Authors:  Gregg M. Townsend and William S. Evans
#
#	Date:     June 9, 2000
#
############################################################################
#
#  Tgrprep writes files of "line chain" data extracted from Census Bureau
#  TIGER/Line data files.  The main purpose of this is to prepare
#  input for the "tgrmap" program.
#
#  Usage:  tgrprep rec1file rec2file
#
#	rec1file:  tgr*.rt1 file containing Type 1 (chain) data
#	rec2file:  tgr*.rt2 file containing Type 2 (shape point) data
#
############################################################################
#
#  Output consists of:
#
#  Line 1: the smallest longitude and latitude found in the Type 1 file
#  Line 2: the largest  longitude and latitude found in the Type 1 file
#  Line 3-n: chain specifications, one per line, in the following format
#
#	(3 chars)  census feature class code (CFCC)
#	(1 char)   boundary code (see below)
#	(varies)   optional feature name, delimted by '|' (see below)
#	(4 chars)  max dimension (latitude or longitude units), max 9999
#	(7 chars)  starting longitude, fraction E of Greenwich meridian
#	(7 chars)  starting latitude, fraction S of North Pole
#	(4 chars)  delta longitude to first point, same units, plus 5000
#	(4 chars)  delta latitude to first point, same units, plus 5000
#  followed by any number (zero or more) of additional delta pairs. 
#  Output lines may be arbitrarily long.
#
#  Boundary codes are:
#	9	national boundary  (not used)
#	8	state boundary  (not used)
#	7	county boundary
#	5	city limits
#	0	other, unknown, not a boundary
#
#  Feature name is the concatenation of the following TIGER fields
#	"Feature Direction, Prefix"
#	"Feature Name"
#	"Feature Type"
#	"Feature Direction, Suffix"
#  The concatenation is surrounded by vertical bars "|" unless it is empty
#  (all spaces).  Any "|" within a TIGER field is replaced by "!".
#
#  For input formats and the definition of CFCC codes, see
#	TIGER/Line Files, 1998 Technical Documentation
#	Bureau of the Census, Washington, DC, 1998.
#	http://www.census.gov/geo/www/tiger/tiger98.pdf
############################################################################


global minlon, maxlon	# min/max longitude seen (in input terms)
global minlat, maxlat	# min/max latitude seen (in input terms)

global curlon, curlat	# current longitude/latitude for output
global deltas		# string of deltas for output


procedure main(args)
   local details, file1, file2, n

   *args = 2 | stop("usage: ", &progname, " rec1file rec2file")
   file1 := open(args[1]) | stop("can't open ", args[1])
   file2 := open(args[2]) | stop("can't open ", args[2])

   write(&errout, "prescanning ", args[1])
   n := llrange(file1)
   write(&errout, right(n, 10), " chain records")
   write("        ", rz(cvlon(minlon)), rz(cvlat(maxlat)))
   write("        ", rz(cvlon(maxlon)), rz(cvlat(minlat)))

   write(&errout, "prescanning ", args[2])
   details := dtindex(file2)
   write(&errout, right(*details, 10), " supplemental sets")

   write(&errout, "scanning ", args[1])
   n := scan(file1, file2, details)
   write(&errout, right(n, 10), " supplements used")
   write(&errout, "done")
end


#  scan(file1, file2, details) -- scan records and write output.
#
#  returns the number of supplements referenced.

procedure scan(file1, file2, details)
   local line, tlid, cfcc, lon, lat, n, l, r
   local startlon, startlat, endlon, endlat, dim, bound, fename

   n := 0
   seek(file1, 1)
   while line := read(file1) do line ? {
      ="1" | next
      tab(6)
      tlid := move(10)
      tab(18)

      fename := ""
      fename ||:= " " || ("" ~== trim(move(2) \ 1))	# direction prefix
      fename ||:= " " || ("" ~== trim(move(30) \ 1))	# name
      fename ||:= " " || ("" ~== trim(move(4) \ 1))	# type
      fename ||:= " " || ("" ~== trim(move(2) \ 1))	# direction prefix
      if fename ~== "" then 
         fename := "|" || map(fename[2:0], "|", "!") || "|"

      tab(56)
      cfcc := move(3)
      bound := "0"

      tab(135)
      l := move(3)		#left county code
      r := move(3)		#right county code
      if l ~== r then		#different --> county boundary
         bound := "7"
      else {
         tab(161)
         l := move(5)		#left city code
         r := move(5)		#right city code
         if l ~== r then	#different --> city boundary
            bound := "5"
         }

      tab(191)
      startlon := curlon := minlon := maxlon := cvlon(move(10))
      startlat := curlat := minlat := maxlat := cvlat(move(9))
      endlon := cvlon(move(10))
      endlat := cvlat(move(9))

      deltas := ""
      if seek(file2, \details[tlid]) then {
         n +:= 1
         while line := read(file2) do line ? {
            tab(6)
            =tlid | break
            tab(19)
            every 1 to 10 do
               drawto(cvlon(0 ~= move(10)), cvlat(0 ~= move(9)))
            }
         }
      drawto(endlon, endlat)

      dim := startlon - minlon
      dim <:= maxlon - startlon
      dim <:= startlat - minlat
      dim <:= maxlat - startlat
      dim >:= 9999

      write(cfcc, bound, fename,
         right(dim, 4), rz(startlon), rz(startlat), deltas)
      }
   return n
end


#  drawto(lon, lat) -- append deltas, updating curlon/curlat

procedure drawto(lon, lat)
   local dlon, dlat

   dlon := lon - curlon
   dlat := lat - curlat

   if abs(dlon | dlat) >= 5000 then {
      drawto(curlon + dlon / 2, curlat + dlat / 2)
      drawto(lon, lat)
      }
   else {
      deltas ||:= rz(dlon + 5000, 4)
      deltas ||:= rz(dlat + 5000, 4)
      curlon := lon
      curlat := lat
      minlon >:= lon
      maxlon <:= lon
      minlat >:= lat
      maxlat <:= lat
      }
   return
end



#  rz(v, n) -- right-justify value in n digits with zero fill

procedure rz(v, n)
   /n := 7
   return right(v, n, "0")
end



#  cvlon(n) -- convert longitude to output form
#
#  (Fraction of circle east of Greenwich, as 0000000 to 9999999).

procedure cvlon(n)
   static m
   initial m := 9999999 / 360.0 / 1000000

   n := integer(n)
   if n < 0 then
      n +:= 360000000
   return integer(m * n)
end


#  cvlat(n) -- convert latitude to output form
#
#  (Fraction of semicircle south of North Pole, as 0000000 to 9999999).

procedure cvlat(n)
   static m
   initial m := 9999999 / 180.0 / 1000000
   return integer(m * (90000000 - n))
end



#  dtindex(f) -- return table of record indices by TLID from file f

procedure dtindex(f)
   local details, line, w

   details := table()
   seek(f, 1)
   while (w := where(f)) & (line := read(f)) do line ? {
      ="2" | next
      tab(6)
      /details[move(10)] := w
   }
   return details
end



#  llrange(f) -- scan f to set min/max lon/lat, returning record count

procedure llrange(f)
   local line, n, lon, lat

   minlon := +180000000
   maxlon := -180000000
   minlat := +90000000
   maxlat := -90000000
   n := 0

   seek(f, 1)
   while line := read(f) do line ? {
      ="1" | next
      n +:= 1
      tab(191)
      every 1 | 2 do {
         lon := integer(move(10))
         lat := integer(move(9))
         minlon >:= lon 
         maxlon <:= lon 
         minlat >:= lat 
         maxlat <:= lat 
         }
      }
   return n
end
