var UserOptions = null;

function Repeat (template, arraylist)
{
   for (var i in arraylist)
   {
      var tc = template;
      var items = arraylist[i];
      for (var j in items)
      {
          tc = tc.replace ("{" + j + "}", items[j]);
      }
      document.write(tc);
   }
}

function Dump(obj)
{
   var r = "";
   
   for (var item in obj)
   {
       var iob = obj[item];
       var t   = typeof(iob);
       
       if (t != "object" && t != "function")
       {
          r += item + " : " + iob + "<br>";
       }
       else
       {
          r += item + " : " + t + "<br>";
       }
   }
   document.getElementById("debug").innerHTML = r;
}


function GetUserOptions()
{
   var uo = UserOptions;

   if (!uo)
   {
       uo = Page.DefaultUserOptions;
       var results = document.cookie.match (/(^|;) ?UsrOpt=([^;]+)(;|$)/);
        
       if (results)
       {
          try
          {
             uo = eval (unescape(results[2]));
             if (typeof(uo.Time24) == 'undefined') uo.Time24 = Page.DefaultUserOptions.Time24;
             if (typeof(uo.Units)  == 'undefined') uo.Units = Page.DefaultUserOptions.Units;
             if (typeof(uo.AngFormat) == 'undefined') uo.AngFormat = Page.DefaultUserOptions.AngFormat;
          }
          catch (err)
          {
             uo = Page.DefaultUserOptions;
          }
       }
   }

   UserOptions = uo;
   return uo;
}

function PageLoaded()
{
   MouseInfoElem = document.getElementById ("MouseInfo");
   document.onmousemove = OnMouseMove;
   document.onmouseup = OnMouseUp;
   setTimeout ("FirstMinute()", (61 - (Now() % 60)) * 1000);
   var uo = GetUserOptions();
   
   if (!uo.FBack || ((new Date().getTime() / 86400000) - uo.FBack) >= 1.0)  // One feedback a day.
   {
      var fboc = document.getElementById("Feedback_oc");
      
      if (fboc) fboc.style.display = "block";
   }
   
   var always = GetUserOptions().InfoAlways;
   document.getElementById("InfoAlways").checked = always;
   
   if (always)
   {
      OnMouseGridOver();
   }
}

function FirstMinute()
{
   OnMinute();
   setInterval ("OnMinute()", 60000);
}

function OnMinute()
{
   UserOptions = false;   // Force a cookie reload every minute.

   if (Page.TimeIsNow)
   {
      var now = Now();
   
      if (now >= 86400)
      {
         window.location.reload();   // Change of day, reload the page.
      }
      else
      {
         UpdateClock(now);
         UpdateNowPointer(now); 
      }  
   }
}

function UpdateClock(now)
{
   var mins = now / 60;
   var clock = document.getElementById ("Clock");
   clock.innerHTML = MinToStrAP(mins);
}

function UpdateNowPointer(now)
{
   var nowp = document.getElementById ('NowPointer');
   
   if (nowp)
   {
      var pix = now * Page.PixPerDay / 86400 + Page.YAxisLabelsWidth;
      
      nowp.style.left = pix.toFixed(0) + "px";
   }

   if (CurrentInfoBoxMins < 0 || Math.abs(CurrentInfoBoxMins - now / 60) < 5) // ie, showing current time...
   {
      ShowInfoBoxAt (now / 60);
   }
}

// Return place local time as seconds of day.
function Now()
{
    var now = new Date();
    var delta = (now - Page.LoadJsTime) / 1000;
    var loadT = Page.LoadSvrTime % 86400;
    return loadT + delta;
}


//////////////////////


var DraggingInfoBox = false;
var DragStartX;
var DragStartY;
var MouseOverGrid = false;
var CurrentInfoBoxMins = -1;
var MouseInfoElem;
var MoonInfoBox = null;



function NoBubble(ev)
{
   ev.cancelBubble = true
   ev.returnValue = false;
   if (ev.stopPropagation) ev.stopPropagation();
}

// Return scroll position in pixels.
function GraphScrollPos()
{
   return document.getElementById("GraphScroller").scrollLeft;
}

function MouseHitTest(ev, elem)
{
   var Xoff = 0;
   var Yoff = 0;
   
   var par = elem;
    
   while (par != null)
   {
       Xoff += par.offsetLeft;
       Yoff += par.offsetTop;
       par = par.offsetParent;
   }
   
   if (ev.pageX == null)
   {
      var d = (document.documentElement && document.documentElement.scrollLeft != null) ?
                 document.documentElement : document.body;
      var docX = ev.clientX + d.scrollLeft;
      var docY = ev.clientY + d.scrollTop;
   }
   else
   {
      var docX = ev.pageX;
      var docY = ev.pageY;
   }
   
   //Dump({docX:docX,docY:docY,Xoff:Xoff,Yoff:Yoff});
   
   // We use Page.GraphVisibleWidth because of horiz scrolling, the elem width is naff.
   return (docX >= (Xoff - Page.InfoWinTargetX) &&
           docY >=  Yoff &&
           docX <  (Xoff + Page.GraphVisibleWidth + Page.InfoWinTargetX) &&
           docY <   Yoff + elem.clientHeight);
}


function OnMouseGridOver(ev)
{
   if (CurrentInfoBoxMins >= 0)
   {
       (CurrentInfoBoxMins);
   }
   else
   {
      ShowInfoBoxAt (Now() / 60);
   }   
   MouseInfoElem.style.display = "block";
}

function OnMouseGridOut(ev)
{
   MouseInfoElem.style.display = "none";
   HideMoonInfoBox();
}

function OnMouseGridUp(ev)
{
   if (!ev) ev = windows.event;
   
   if (typeof(ev.layerX) == "undefined")
   {
      var mins = (ev.x + GraphScrollPos()) / Page.PixPerMin;
   }
   else
   {
      var mins = (ev.layerX + GraphScrollPos()) / Page.PixPerMin;
   }
   ShowInfoBoxAt (mins);
   MouseInfoElem.style.display = "block";
}


function OnInfoBoxMouseUp(ev)
{
   if (DraggingInfoBox)
   {
      DraggingInfoBox = false;
      ShowInfoBoxAt (CurrentInfoBoxMins);
   }
}

function OnMouseUp(ev)
{
   HideMoonInfoBox();
   
   if (DraggingInfoBox)
   {
      DraggingInfoBox = false;
   }
}

function OnInfoBoxMouseDown(ev)
{
   HideMoonInfoBox();
   
   if (!ev) ev = window.event;
   
   DragStartX = ev.screenX;
   DragStartY = ev.screenY; 
   
   DraggingInfoBox = true;
}


function OnMouseMove(ev)
{
   if (!ev) ev = window.event;
   
   if (DraggingInfoBox)
   {
      var gX   = MouseInfoElem.offsetLeft + Page.InfoWinTargetX + GraphScrollPos();
      var gY   = MouseInfoElem.offsetTop  + Page.InfoWinTargetY;
      
      var boxTop  = MouseInfoElem.offsetTop  + ev.screenY - DragStartY;
      var boxLeft = MouseInfoElem.offsetLeft + ev.screenX - DragStartX;
      
      var bTop    = 0 - Page.InfoWinTargetY;
      var bLeft   = 0 - Page.InfoWinTargetX - 1;
      var bBottom = Page.GraphVisibleHeight - Page.InfoWinTargetY;
      var bRight  = Page.GraphVisibleWidth  - Page.InfoWinTargetX;
      
      if (boxLeft >= bLeft && boxLeft < bRight && boxTop >= bTop && boxTop < bBottom)
      {
         ShowInfoBox (gX, gY, boxLeft, boxTop);

         DragStartX = ev.screenX;
         DragStartY = ev.screenY; 
      }
      
      NoBubble(ev);
      return false;
   }
   else
   {
      if (MouseHitTest(ev, document.getElementById("MouseGrid")))
      {
         var moon = MoonHitTest(ev);
         
         if (moon)
         {
            DisplayMoonInfoBox(moon);
         }
         else
         {
            HideMoonInfoBox();
            
            if (!MouseOverGrid) 
            {
               OnMouseGridOver(ev);
               MouseOverGrid = true;
            }
         }
      }
      else  // Mouse is outside graph area.
      {
         HideMoonInfoBox();
         
         if (!GetUserOptions().InfoAlways)
         {
            if (MouseOverGrid) OnMouseGridOut(ev);
            MouseOverGrid = false;
         }
      }
   }
   return true;
}

function DisplayMoonInfoBox(moon)
{
   if (MoonInfoBox == null)
   {
      var minfo = document.getElementById('MoonInfoBox');
      minfo.innerHTML = moon.html;
      minfo.style.display = 'block';
      
      var left = moon.moonX - minfo.clientWidth / 2 - GraphScrollPos();
      
      if (left < 0)
      {
         left = 0;
      }
      else if (left + minfo.clientWidth > Page.GraphVisibleWidth)
      {
         var left = Page.GraphVisibleWidth - minfo.clientWidth - 3;
      }  
      minfo.style.left = '' + left + 'px';
      
      var top = 6 - minfo.clientHeight;
      minfo.style.top = '' + top + 'px';
      
      MoonInfoBox = minfo;
   }
}

function HideMoonInfoBox()
{
   if (MoonInfoBox != null)
   {
      MoonInfoBox.style.display = 'none';
      MoonInfoBox = null;
   }
}

function OnGraphScroll()
{
   if (CurrentInfoBoxMins >= 0)
   {
      ShowInfoBoxAt (CurrentInfoBoxMins);
   }
}


function ShowInfoBoxAt (mins)
{
   var gX   = Math.round(Page.PixPerMin * mins);
   var gY   = 0;
   var scrl = GraphScrollPos();      
   
   var boxLeft = gX - Page.InfoWinTargetX - scrl;
   
   ShowInfoBox (gX, gY, boxLeft, "tide", mins);
}


function ShowInfoBox(graphX, graphY, boxLeft, boxTop, mins)
{
   if (mins == null) mins = graphX / Page.PixPerDay * 1440;

   var uopts = GetUserOptions();

   var day  = Math.floor(mins / 1440);
   var min  = mins % 1440;
   var suns = Page.SunRiseSet[day];
   var posn = min / 1440;     // Mouse pos as fraction of day.
   var sunHtml = "";
   
   CurrentInfoBoxMins = mins;
    
   if (suns && min > suns.R - 10 && min < suns.S + 10)
   {
      var sspan  = suns.S - suns.R;
      var dspan  = sspan / 1440;
      var dratio = sspan / 720;  // Ratio of sunup time to 6 hours.
      var rise   = suns.R / 1440;
       
      var sunTop  = Page.InfoWinClipHeight - 10 - Math.floor(Math.sin(Math.PI * 2 * (posn - rise) / dratio) * (Page.InfoWinClipHeight - 15)); 
      var sunLeft = 0;
       
      sunHtml = "<div class='AniSunMoon' style='top:" + sunTop + "px; left:" + sunLeft + "px;'>" + 
                  "<img src='/images/Sun.png' width='100%' />" +
                "</div>";
   }
    
   var mouseTime = Page.UnixStartTime + mins * 60;
   var moonHtml  = "";
   var mrise = null;
   var mset  = null;
   var mzen  = {Thumb : "/images/Moon_Full.png"};
    
   for (var moon in Page.MoonRiseSet)
   {
      var mrs = Page.MoonRiseSet[moon];
       
      if (mrs.RS == 'Rise')
      {
         mrise = mrs;
         if (mrise.Time > mouseTime) break;  // No moon up.
      }
      else if (mrs.RS == 'Set')
      {
         mset = mrs;
      }
      else if (mrs.RS == 'Zenith')
      {
         mzen = mrs;
      }
       
      if (mrise && mset && mouseTime >= mrise.Time && mouseTime < mset.Time)
      {
         var mmfract  = (mouseTime - mrise.Time) / (mset.Time - mrise.Time);
         var moonTop  = Page.InfoWinClipHeight - 5 - Math.floor(Math.sin(Math.PI * mmfract) * (Page.InfoWinClipHeight - 20));
         var moonLeft = Page.InfoWinClipWidth - 20;
         var moonHtml = "<div class='AniSunMoon' style='top:" + moonTop + "px; left:" + moonLeft + "px;'>" + 
                        "<img src='" + mzen.Thumb + "' width='50%' /></div>"; 
                         
         break;
      }
   }
    
   var tide = Page.Tides[graphX];
   var height = tide[2].toFixed(2) + uopts.Units;
   var dayPart = "";
    
   switch (tide[0])
   {
      case 'NA' : case 'NB': dayPart = "Night"; break;
      case 'TA' : case 'TB': dayPart = "Civil twilight"; break;
      case 'DA' : case 'DB': dayPart = "Day"; break;
   }
      
   if (boxTop == "tide") boxTop = tide[1] - Page.InfoWinTargetY;    // Box vertically to follow the tide 
   
   MouseInfoElem.style.top  = boxTop.toFixed(0) + "px";
   MouseInfoElem.style.left = boxLeft.toFixed(0) + "px";
    
   MouseInfoElem.innerHTML =
     "<div class='InfoBoxSunMoonClip'>" +
       sunHtml +
       moonHtml +
       "<div class='t_InfoBoxDate InfoBoxDate'>" + suns.DD + " " + suns.Dj + suns.DS + "</div>" +
       "<div class='t_InfoBoxTime InfoBoxTime'>" + MinToStrAP(mins) + "</div>" +
       "<div class='t_InfoBoxTideHeight InfoBoxTideHeight'>" + height + "</div>" +
       "<div class='t_InfoBoxDayPart InfoBoxDayPart'>" + dayPart + "</div>" +
     "</div>" +
     "<div id='MouseInfoDrag' onmousedown='OnInfoBoxMouseDown(event)' onmouseup='OnInfoBoxMouseUp(event)'></div>";
         
   return false;
}

function MoonHitTest(ev)
{
   if (!ev) ev = windows.event;
   
   if (typeof(ev.srcElement) == "undefined")
   {
      var elem = ev.target;
   }
   else
   {
      var elem = ev.srcElement;
   }
   
   if (elem && elem.id == 'GridImage')
   {
      if (typeof(ev.layerX) == "undefined")
      {
         var mX = ev.x + GraphScrollPos();
      }
      else
      {
         var mX = ev.layerX + GraphScrollPos();
      }
      
      if (typeof(ev.layerY) == "undefined")
      {
         var mY = ev.y;
      }
      else
      {
         var mY = ev.layerY;
      }
      
      if (mY < Page.MoonAreaBottom && mY > Page.MoonAreaTop)
      {
         var hmw  = Page.MoonWidth / 2;

         for (var mx in Page.MoonArr)
         {
            var moon = Page.MoonArr[mx];
            
            if (mX > (moon[2] - hmw) && mX < (moon[2] + hmw))
            {
               return {moonX:moon[2], html:moon[4] + '<br>' + moon[5], mouseX:mX, mouseY:mY};
            }
            
         }
      }
   }
   return false;
}

function MinToStr(mins)
{
    var hour = Math.floor(mins / 60 % 24);
    var min  = Math.floor(mins % 60);
    var ms   = (min < 10) ? "0" + min : min.toFixed(0);
    
    if (GetUserOptions().Time24 > 0)
    {
       var hs = (hour >= 10) ? hour.toFixed(0) : "0" + hour;
       return hs + ms + "<sup>h</sup>";
    }
    else
    {
       hour = hour % 12;
       var hs = (hour == 0) ? "12" : hour.toFixed(0);
       return hs + ":" + ms;
    }
}

function MinToStrAP(mins)
{
    if (GetUserOptions().Time24)
    {
       return MinToStr(mins);
    }  
    else if (mins % 1440 >= 720)
    {
       return MinToStr(mins) + "pm";
    }
    else
    {
       return MinToStr(mins) + "am";
    }
}

function WriteHeightSettings()
{
   document.write(
      HtmlSetting("Displays heights in feet.", "ft", "Units", "ft") + ' &nbsp; &nbsp;' +
      HtmlSetting("Displays heights in metres.", "m", "Units", "m"));
}

function WriteTimeSettings()
{
   document.write(
      HtmlSetting("Display 12-hour times.", "11:55pm", "Time24", 0) + ' &nbsp; &nbsp;' +
      HtmlSetting("Display 24-hour times.", "2355", "Time24", 1));
}

function WriteAngleDisplaySettings()
{
   document.write(
      HtmlSetting("Display angles and lat/long in degrees.", "&deg;", "AngFormat", "D") + ' &nbsp; &nbsp; ' + 
      HtmlSetting("Display angles and lat/long in degrees and minutes.", " &deg; ' ", "AngFormat", "DM") + ' &nbsp; &nbsp; ' +
      HtmlSetting("Display angles and lat/long in degrees, minutes, and seconds.", "&deg; ' &quot; ", "AngFormat", "DMS"));
}

function HtmlSetting (title, text, ident, value)
{
   var html = '<span title="' + title + '">' + text + '</span>';

   if (GetUserOptions()[ident] != value)
   {
       var valueStr = (typeof(value) == 'string') ? '\\\'' + value + '\\\' ' : value.toString();

       html = '<a href="javascript:void(0)" onclick="SettingClick(\'uo.' + ident + "=" + valueStr + '\')">' + html + '</a>';
   }
   else
   {
       html = '<b>' + html + '</b>';
   }
   return html;
}

function SettingClick (makeSetting)
{
    var uo = GetUserOptions();
    eval (makeSetting);
    SaveUserOptions(uo);
    window.location.replace (window.location.href);  // minimal page reload.
}

function OnInfoBoxAlwaysClick()
{
   var uopt = GetUserOptions();
   
   uopt.InfoAlways = document.getElementById("InfoAlways").checked;
   
   if (uopt.InfoAlways)
   {
      OnMouseGridOver();
   }
   else
   {
      OnMouseGridOut();
   }
   SaveUserOptions(uopt);
}



function SaveUserOptions (uopts)
{
    var newc = "";
        
    for (uopt in uopts)
    {
        if (newc != "") newc += ",";
            
        if (typeof (uopts[uopt]) == "string")
        {
            newc += uopt + ':"' + uopts[uopt] + '"';
        }
        else
        {
            newc += uopt + ':' + uopts[uopt];
        }
    }
    newc = "({" + newc + "})";
    expires = new Date();
    expires.setMonth (expires.getMonth() + 12);
    
    document.cookie = "UsrOpt=" + escape(newc) + "; path=/; expires=" + expires.toGMTString();
    
    // Dump(GetUserOptions()); // Trying to debug IE cookies. Turns out it uses domain, not subdomain.
}
 

function ClickOpenClose(ev,elemId)
{
   if (!ev) ev = window.event;
   var elem = document.getElementById(elemId);
   var oce  = document.getElementById(elemId + "_oc");
   var img = "url('/images/collapse.png')";

   if (elem.style.display == "block")
   {
      elem.style.display = "none";
      img = "url('/images/openclose.png')";
   }
   else
   {
      elem.style.display = "block";
   } 
   oce.style.backgroundImage = img;
}




var FeedbackCount; 

function SubmitFeedback()
{
   FeedbackCount = 0;
   var inputs = document.getElementById("Feedback").getElementsByTagName("INPUT");
   
   for (var inp in inputs)
   {
      inelem = inputs[inp];
      
      if (inelem.type == "checkbox" && inelem.checked)
      {
         FeedbackCount++;
         pageTracker._trackEvent ("OpFeedback", "Tick", "OP: " + inelem.name);
      }
   }
   
   if (FeedbackCount == 0)
   {
      alert("You don't seem to have much to say. Please tick relevant checkboxes before submitting.");
   }
   else
   {
      pageTracker._trackEvent ("OpFeedback", "Submit", "OP: Submit", FeedbackCount);
      
      var uo = GetUserOptions();
      uo.FBack = (new Date().getTime() / 86400000).toFixed(3);
      SaveUserOptions(uo);
      document.getElementById("Feedback").style.display = "none";      
      document.getElementById("Feedback_oc").style.display = "none";      
      
      alert ("Thanks.  Your feedback is appreciated.\nYou can do the same again tomorrow, if you want.");
   }
}

