
function Globals() { // Done this way to be visible on the Web page
  FZ = document.forms.FrmZ // abbreviation
  Running = false
  TZobj = 0 // To be replaced by TZ Objects
  // OldYr = 0000
  // GMTBeg = 0 ; RemBeg = 0 ; GMTEnd = 0 ; RemEnd = 0
  }



function SetRegExps() { // Used in parsing a TZ string
  RE1 = /^M(\d+)\.(\d+)\.(\d+)\/(\d+):(\d+)\s*$/i   /* Times */
  RE2 = /^([a-z]+)([0-9:+-]+)([a-z]*)([0-9:+-]*)$/i /* Names */ }



function YMDhm(Dob) { return Dob.utcDYMDHMSstr().substr(0, 21) }

function MParse(MField) { var mo, wk // MField is Remote Time
  if (!RE1.test(MField)) return {}
  with (RegExp) { mo = +$1 ; wk = +$2
    if (wk==5) { mo++ ; wk = 0 } // 5th => last -> 0th of next
    return {MO:mo, WK:wk, DY:+$3, HR:+$4, MN:+$5} } }


function Minutes(St) { var x
  x = /([+-]?)([^:]+):([^:]+)/.test(St+":0") // Sign, Mins, Secs
  with (RegExp) return ($1+"1")*(60*$2 + +$3) }


function TZparse(TZS) { // To parse TZS to {A O A O {M} {M}}
  if (TZS=="") return {TZbad:"TZ Empty"}
  var Arr = (TZS).split(",")
  if (Arr.length!=1 && Arr.length!=3)
    return {TZbad:Arr.length+" Fields"}
  if (!RE2.test(Arr[0])) return {TZbad:Arr[0]}
  with (RegExp) var Ob = { Abbr:$1, ZWin:$2, AbrS:$3, ZSum:$4 }
  Ob.ZWin = Minutes(Ob.ZWin)
  if (Ob.AbrS > "") {
    if (Arr.length!=3) return {TZbad:"No Dates"}
    Ob.ZSum = Ob.ZSum=="" ? Ob.ZWin-60 : Minutes(Ob.ZSum) }
  if (Arr.length>1) {
    if (!Arr[1] || !Arr[2]) return {TZbad:"Blank Date"}
    if (!(Ob.DTbeg = MParse(Arr[1])).MO) return {TZbad:Arr[1]}
    if (!(Ob.DTend = MParse(Arr[2])).MO) return {TZbad:Arr[2]}
    var ST = Ob.DTbeg.MO
    var WT = Ob.DTend.MO // 2 changes in month ?
    Ob.Hemi = ST < WT ? "North" : ST > WT ? "South" : "Dodgy" }
  return Ob }


function ChangeDate(MObj, Year, Mins) { var dt // Mins optional
  with (MObj)
    with (dt = new Date(Date.UTC(Year, MO-1, 1, HR, MN))) {
      setUTCDate(7*WK - 6 + (7+DY-getUTCDay())%7 ) // Civil time
      if (Mins) setUTCMinutes(getUTCMinutes()+Mins) } // if, to GMT
  return dt /* M-field to Date Object in Year */ }


function ZoneStr(mins) { var T = Math.abs(mins), mn = T % 60
  T = (T-mn)/60 ; return (mins>0?"-":"+") + LZ(T) + ":" + LZ(mn) }


function GetAdj(Dob, Rtrn, TZo, XX) { // XX optionally empty object
  var Yr = Dob.getUTCFullYear()               // Year cache useful?
  var Qbeg = ChangeDate(TZo.DTbeg, Yr, XX.ZWin)
  var Qend = ChangeDate(TZo.DTend, Yr, XX.ZSum)
//  Rtrn.Sbeg = Qbeg.utcDYMDHMSstr() ; Rtrn.Send = Qend.utcDYMDHMSstr()
  Rtrn.Sbeg = YMDhm(Qbeg) ; Rtrn.Send = YMDhm(Qend)
  var Hot = ((Dob >= Qbeg) == (Dob < Qend)) == (Qbeg < Qend)
  if (Hot) Rtrn.Abbr = TZo.AbrS
  Rtrn.Tide = Hot ? "Summer" : "Winter"
  return Hot ? TZo.ZSum : TZo.ZWin }




function DOtoRT(DTobj, TZo) { // for Date Object to Remote Time, &c
  // Date Object, parsed TZ String to Remote Date/Time Object
  var Adj=TZo.ZWin, Rtrn={Abbr:TZo.Abbr, Hemi:TZo.Hemi}
  if (TZo.AbrS > "") Adj = GetAdj(DTobj, Rtrn, TZo, TZo)
  with (new Date(+DTobj)) { setUTCMinutes( getUTCMinutes() - Adj )
    Rtrn.RsAb = (Rtrn.Rslt = utcDYMDHMSstr().substr(5, 21))}
  return Rtrn } // DOtoRT


function RStoUT(DTstr, TZo) { // for Remote Time to Proper Time
  // Date String, parsed TZ String to Object with Info Fields
  var Adj=TZo.ZWin,
    Rtrn={Abbr:TZo.Abbr, Hemi:TZo.Hemi, Zone:ZoneStr(TZo.ZWin)}
  Rtrn.Rslt = ParseWithUTC(DTstr) // for ISO
  if (isNaN(Rtrn.Rslt)) return {DTbad:"Bad Date"} // Rtrn
  if (TZo.AbrS > "") Adj = GetAdj(Rtrn.Rslt, Rtrn, TZo, {})
  with (Rtrn.Rslt) setUTCMinutes( getUTCMinutes() + Adj )
  return Rtrn } // RStoUT


function SetTZstring() { with (FZ) {
  TZS.value = Places.options[Places.selectedIndex].value
  TZobj = TZparseShow(TZS.value) } }




function TZshow(TZo) { with (FZ) {
    if (TZo.TZbad) {
      Zown.value = "Error :" ; Hemy.value = TZo.TZbad ; return }
    else {
      Zown.value = ZoneStr(TZo.ZWin) ; Hemy.value = TZo.Hemi } } }


function TZparseShow(TZS) {
  var TZo = TZparse(TZS)
  TZshow(TZo)
  return TZo }


function ShowFwds(Oj) { with (FZ) {
    if (Oj.DTbad) {
      Wbeg.value = Wend.value = RAbr.value = Tyde.value = ""
      RTim.value = Oj.DTbad ; return }
    Wbeg.value = Oj.Send ; Wend.value = Oj.Sbeg
    RTim.value = Oj.Rslt ; RAbr.value = Oj.Abbr
    Tyde.value = Oj.Tide } }


function ShowBack(Oj) { with (FZ) { var S = "   "
    if (Oj.DTbad) { Rvrs.value = Oj.DTbad
      STon.value = STof.value = Far1.value = Far2.value = ""
      return }
    STon.value = Oj.Sbeg ; STof.value = Oj.Send
    Far1.value = Oj.Zone + S + Oj.Hemi
    Far2.value = Oj.Abbr + S + Oj.Tide
    Rvrs.value = Oj.Rslt.utcDYMDHMSstr() } }


function DoBack() { with (FZ) {
    ShowBack(RStoUT(RTim.value, TZobj))
    var T = RTtoUT(RTim.value+" "+RAbr.value, TZS.value)
    RNew.value = isNaN(T) ? T : T.utcDYMDHMSstr()
    } }


function Process(D) { with (FZ) { var Oj
    ShowFwds({DTbad:"#"}) ; ShowBack({DTbad:"#"}) // Wipe lest fail
    RNew.value = "#"
    if (!TZobj.TZbad) {
      Oj = DOtoRT(D, TZobj)
      Wryt("RemTim", Oj.RsAb)
      ShowFwds(Oj)
      DoBack() } } }


function Convert() { with (FZ) { var A, D // read Y M D h m s
    A = DT.value.split(/\D+/)
    D = Date.UTC(A[0],
                (A[1]-1)||0, A[2]||1, A[3]||0, A[4]||0, A[5]||0)
    if (isNaN(D)) { RNew.value = ""
      ShowFwds({DTbad:"Date Error"})
      ShowBack({DTbad:"-"})
      return }
    Process(new Date(D)) } }


function EverySecond() { if (!Running) return
  setTimeout("EverySecond()", 1000-(new Date()).getTime()%1000)
  Set_Now() ; Convert() }


function Set_Now() { // for test
  FZ.DT.value = (new Date()).utcDTstr() }


function RunOff() { Running = !Running ; EverySecond()
  FZ.Go.value = Running ? " Off " : " Run " }

function ReadBox() { var A, J, K=0, T, X
  Arr = []
  
 
  var myString = "Москва   WinT-3SumT,M3.5.0/2:00,M10.5.0/3:00*Владивосток WinT-9SumT,M3.5.0/2:00,M10.5.0/3:00"
  A = myString.split("*")
 // A = document.getElementById("DataBox").value.split(/[\r\n]+/)
  for (J=0 ; J < A.length ; J++) { T = A[J].split(/\s+/)
    if (T[0]!='#') { X = T.length-1 ;
      Arr[K++] = {At:T.slice(0,X).join(" "), TZ:TZparse(T[X])} } } }

function Tick() { var D = new Date(), J, S
  S = [""]
  for (J=0 ; J < Arr.length ; J++) with (Arr[J])
    S.push(At + ": " + DOtoRT(D, TZ).RsAb)
  Wryt("CloxM", S[1].replace(/-/g,"/"))
  Wryt("CloxV", S[2].replace(/-/g,"/"))
  setTimeout("Tick()", 1000-D.getTime()%1000) }

 function DoThemAll() { ReadBox() ; setTimeout("Tick()", 300) }
