# $Id: importNOS_TideSubs.rb 7595 2022-01-05 18:54:39Z flaterco $
# Functions for importNOS.rb:
# Tidal subordinate station import

# Messiness happens because every field wants to be fixed up using some other
# field that is also unreliable or incomplete.  Something has to go first.

def importTideSubs(db)
  if File.exist?("renamings-tidesubs.sql")
    puts "Don't want to overwrite renamings-tidesubs.sql; do something with it"
    exit
  end
  gt = readGeogroupsTidesJson()
  sbgt = readStationsByGroupTidesJson()
  stateMap = getOldStateMap(db)
  wAleutSids = getWesternAleutians(db)
  tides = readTidesJson()
  File.open("renamings-tidesubs.sql","w") {|renamings|
    tides.each_value {|tsta|

      # Avoid adding code that isn't exercised.
      raise "Notices are not null anymore" unless tsta["notices"].nil?
      raise "Disclaimers are not null anymore" unless tsta["disclaimers"].nil?

      # "type" is R = reference, S = subordinate, X = undocumented.  But
      # examination of tides.json reveals valid sub stations with type set to
      # R.  So we ignore type and just bail when refid is null or something
      # else goes wrong.
      # 2020-12 type X has gone away.
      # notes = "Station type is undocumented type X; maybe a deleted record; use with caution."
      type = tsta["type"]
      raise "Unknown type #{type}" unless "RS".include?(type)

      sid = tsta["id"]
      tname = tsta["name"]
      raise "Why, how is this nil?" if tname.nil?
      if isMaybeNotFreeData(gt, sbgt, tsta)
	print "Skipped ", sid, " ", tname, " (blacklisted)\n"
	next
      end

      lat = tsta["lat"]
      lng = tsta["lng"]
      if lng < 0 && westernAleutian?(gt, sbgt, wAleutSids, tname, sid)
	print "Fixing longitude of ", sid, " ", tname, "\n"
	lng = -lng
      end

      refid = tsta["reference_id"]
      offsets = tsta["tidepredoffsets"]
      raise "Mismatched ref IDs" if offsets["refStationId"] != refid
      raise "Mismatched types" if offsets["type"] != type

      maxl = offsets["heightOffsetHighTide"]  # multiply OR add
      minl = offsets["heightOffsetLowTide"]   # multiply OR add
      maxt = offsets["timeOffsetHighTide"]    # minutes
      mint = offsets["timeOffsetLowTide"]     # minutes
      adjtyp = offsets["heightAdjustedType"]  # R (mult) or F (add)

      # 2017: there are 125 records in tides.json where the refids are
      # missing or self-referential yet there are offsets.  For those
      # checked, tidesandcurrents.noaa.gov only brings up the reference
      # station.  If we have constants for it then treat those offsets as
      # spurious.
      if refid.empty? or sid == refid
	unless (maxl.nil? or maxl == 0) and (minl.nil? or minl == 0) and
	    (maxt.nil? or maxt == 0) and (mint.nil? or mint == 0)
	  unless type == "R" and refStationExists(db, sid)
	    print "CHECK: ", sid, " ", tname, "\n"
	    raise "Station check"
	  end
	end
	next
      end

      unless refStationExists(db, refid)
	print "Skipped ", sid, " ", tname, " (missing ref ", refid, ")\n"
	next
      end

      raise "Nil offsets" if maxl.nil? or minl.nil? or maxt.nil? or mint.nil?
      raise "Zero multiplier" if adjtyp == "R" and (maxl.zero? or minl.zero?)

      case adjtyp
      when "R"
	minla, minlm, maxla, maxlm = [nil, minl, nil, maxl]
      when "F"
	minla, minlm, maxla, maxlm = [minl, nil, maxl, nil]
      else
	raise "Unknown heightAdjustedType"
      end

      # For name/state/timezone, we have three options.
      # 1 - harmonize with existing reference station
      # 2 - keep from data_sets_old
      # 3 - guess
      newStation = false
      reftuple = getRefNameStateTz(db, sid)
      if !reftuple.nil?  # 1 - harmonize with existing reference station
	name, state, tz = reftuple  # name should already be fixed.
        name = chompname(name)
      else
        oldtuple = getOldNameStateTz(db, sid)
        if !oldtuple.nil?  # 2 - keep from data_sets_old
	  oldname, state, tz = oldtuple
          oldname = chompname(oldname)
	  name = fixname(oldname)
	  if name != oldname
	    print "#{sid} fixing up name from data_sets_old\n"
	    print "  #{oldname}\n"
	    print "  #{name}\n"
	  end
        else  # 3 - guess
	  newStation = true
	  # state a.k.a. statecode_guess
	  state = guessState(gt, sbgt, stateMap, tsta, lat, lng)
	  orig_geogroup = getTideGeogroupBySid(gt, sbgt, sid, state)
	  geogroup = fixgeogroup(orig_geogroup)
	  # Guessed statecode is more trustworthy than geogroup[0]--even when
	  # it's nil.
	  geogroup = [(state.nil? ? nil : StateName[state]), geogroup[1], geogroup[2]]
	  name = generateName(tname, nil, geogroup, nil)
	  tz = guessTimezone(state, name, lat, lng) # nil statecode OK
        end
      end

      raise "State might be nil but should not be empty" if !state.nil? and state.empty?
      country = guessCountry(state, name)
      notes = nil

      # Time warps and other meridian problems
      submerid = TZmerids[tz]
      if submerid.nil?
	print "Missing from TZmerids: ", tz, "\n"
	raise "Missing tz"
      end
      # tsta["timemeridian"] is garbage.
      reftz = getRefTimezone(db, refid)
      if reftz != tz
	refmerid = TZmerids[reftz]
	if refmerid.nil?
	  print "Missing from TZmerids: ", reftz, "\n"
	  raise "Missing tz"
	end
	if refmerid != submerid
	  print "Time warp at ", sid, " ", name, "\n"
	  print "  Ref ", refid, " is ", reftz, " (merid ", refmerid, ")\n"
	  print "  Sub is ", tz, " (merid ", submerid, ")\n"
	  adjustMin = (refmerid - submerid) * 60
	  mint += adjustMin
	  maxt += adjustMin
	  notes = append(notes, "Reference is in time zone " + reftz +
			 "; adjusted offsets " + (refmerid-submerid).to_s +
			 " hr\nto undo LST compensation.")
	end
      end

      # Resolve name clashes.
      if refStationNamed(db, name)
	name += " (sub)"
	if nameInUse(db, name)
	  # Plausibly could need (sub) (2) but wait till it happens.
	  raise "Adding sub wasn't enough"
	end
      elsif nameInUse(db, name)
	stupidSuffixNumber = 1
	begin
	  stupidSuffixNumber += 1
	  raise "Too many numbered stations" if stupidSuffixNumber >= 10
	  tryname = name + " (" + stupidSuffixNumber.to_s + ")"
	end while nameInUse(db, tryname)
	name = tryname
      end

      if newStation
	mname = db.escape_string(name)
	renamings.print "-- #{sid} #{lat} #{lng}\n"
        renamings.print "-- orig name: #{tname}\n"
        gtext = (sbgt.include?(sid) ? "geogroup" : "geogroup (GUESSED)")
        if orig_geogroup != geogroup
          renamings.print "-- orig_#{gtext}: #{orig_geogroup}\n"
        end
        renamings.print "-- #{gtext}: #{geogroup}\n"
        renamings.print "update data_sets\n"
        renamings.print "  set state = ",
          (state.nil? ? "null" : "'#{state}'"), ",\n"
        renamings.print "  name = '#{mname}'\n  where name = '#{mname}';\n"
      end

      xfields = "Credit:NOAA data processed by David Flater for XTide\n https://flaterco.com/xtide/"
      mint = mint.to_s + " minutes"
      maxt = maxt.to_s + " minutes"
      comments = nil                 # Saved for future use
      res = db.exec("insert into data_sets (name, original_name, station_id_context, station_id, lat, lng, timezone, state, country, units, source, notes, comments, restriction, xfields, ref_index, min_time_add, min_level_add, min_level_multiply, max_time_add, max_level_add, max_level_multiply) values ($1, $2, 'NOS', $3, $4, $5, $6, $7, $8, 'feet', 'CO-OPS Metadata API', $9, $10, 'Public domain', $11, $12, $13, $14, $15, $16, $17, $18)", [name, tname, sid, lat, lng, tz, state, country, notes, comments, xfields, getRefIndex(db,refid), mint, minla, minlm, maxt, maxla, maxlm])
    }
  }
end
