function Clock(id, city, timeZone, dst, cityLat, cityLong) {
  this.id = id;
  this.city = city;
  if (city == null) {
    this.city = "Home";
  }  
  this.cityLat = cityLat;
  if (cityLat == null) {
    this.cityLat = 0;
  }
  this.cityLong = cityLong;
  if (cityLong == null) {
    this.cityLong = -getTimezoneOffset(new Date()) / 12 / 60 * 180;
  }  

  this.timeZone = timeZone;
  if (timeZone == null) {
    this.timeZone = -(getTimezoneOffset(new Date)) / 60;
  }
  this.dst = dst;
  if (dst == null) {
    dst = false;
  }  
  this.sunrise = 6 * 60;
  this.sunset = 18 * 60;

  this.isNight = true;
  this.lastDay = -1;
  this.infoIndex = 0;
  this.show12Clock = false;  

  this.testmin = 0;
  this.testh = 24;
  this.isTest = false;

  this.loc = document.getElementById("Location" + id);
  this.time = document.getElementById("Time" + id);
  this.date = document.getElementById("Date" + id);
  this.pane = document.getElementById("BackPane" + id);
  this.stars = document.getElementById("StarsPane" + id);
  this.glow = document.getElementById("GlowPane" + id);
  this.sun = document.getElementById("Sun" + id);
  this.moon = document.getElementById("Moon" + id);
  this.santa = document.getElementById("Santa" + id);
  this.clouds = document.getElementById("CloudsPane" + id);
  this.clock = document.getElementById("ClockPane" + id);

  this.startTest = function(event) {
    if (this.testh < 24 || this.sunset < 0) {
      this.testh = 24;
    }
    else {
      //onhide();
      if (event != null && event.shiftKey) {
        this.testh = (this.sunset - dawn) / 60;
      }
      else {  
        this.testh = (this.sunrise - dawn) / 60;
      }  
      this.testmin = 0;
    }  
    this.test();    
  }
  
  var _self = this;
  
  this.updateSunTimes = function() {
    var date = new Date();
    var dstValue = this.dst ? 1 : 0;    
    date.setTime(date.getTime() + (getTimezoneOffset(date) + (this.timeZone + this.dst) * 60) * 60000);
    this.calcSun(daysAfterMonth[date.getMonth()] + date.getDate(), this.timeZone + this.dst, this.cityLat, this.cityLong);  
  }
  
  this.calcSun = function(day, zone, lat, lng) {
    // Formula from http://mathforum.org/library/drmath/view/56478.html
    var test = 0.39795 * Math.cos(0.2163108 + 2*Math.atan(0.9671396 * Math.tan(0.00860 * (day-186))));
    var p = Math.asin(test);
    
    var nom = Math.sin(0.83333*Math.PI/180) + Math.sin(lat*Math.PI/180)*Math.sin(p);
    var denom = Math.cos(lat*Math.PI/180)* Math.cos(p);
  
    test = nom/denom;
    
    if (Math.abs(test) > 1) {
      if (test > 0) {
        this.sunrise = -60;
        this.sunset = 25 * 60; //never
      }
      else {
        this.sunrise = 25 * 60;
        this.sunset = -60; //never      
      }  
      return;
    }
  
    var d = 24 - (24/Math.PI) * Math.acos(test);
    
    var shift = (zone*15 - lng) / 360.0 * 24 + 12;
    //alert((shift - d / 2) + " " + (shift + d / 2));
    this.sunrise = (shift - d / 2) * 60;
    this.sunset = (shift + d / 2) * 60;
  }

  this.test = function() {
    this.isTest = true;
  	var date = new Date();
    date.setHours(this.testh);
    date.setMinutes(this.testmin);
    this.backPane(date);
    this.testmin++;
    if (this.testmin >= 60) {
      this.testmin = 0;
      this.testh++;
    }
    if (this.testh < Math.min(24, (this.sunset + dawn) / 60 + 1)) {
      var _self = this;
      setTimeout(function() {_self.test()}, 100);
    }
    else {
      this.isTest = false;
      //this.readPrefs();
    }  
  }  
  
  this.changeInfo = function() {
	this.toggleTimeFormat();
    this.infoIndex++;
    if (this.infoIndex > 2) {
      this.infoIndex = 0;
    }
    //widget.setPreferenceForKey(this.infoIndex, widget.identifier + "-info");
    this.updateInfo();
    //saveClock(this);
  }
  
  this.updateInfo = function(date) {
    if (date == null) {
      date = new Date();
    }
    var info = date.toLocaleDateString();
    if (this.infoIndex == 1) {
      this.updateSunTimes();
      if (this.sunrise < 0) {
        info = "No Sunset";
      }
      else if (this.sunset < 0) {
        info = "No Sunrise";
      }
      else {
        info = "\u2191 " + this.formatTime2(parseInt(this.sunrise / 60), 
                                       parseInt(this.sunrise % 60), 
                                       parseInt((this.sunrise - Math.floor(this.sunrise)) * 60)) 
               + " - \u2193 " + this.formatTime2(parseInt(this.sunset / 60), 
                                       parseInt(this.sunset % 60), 
                                       parseInt((this.sunset - Math.floor(this.sunset)) * 60)); 
      }
      /*
      if (this.sunrise < 0) {
        info = "No Sunset";
      }
      else if (this.sunset < 0) {
        info = "No Sunrise";
      }
      else {
        var riseDate = new Date();
        riseDate.setHours(this.sunrise / 60);
        riseDate.setMinutes(this.sunrise % 60);
        riseDate.setSeconds((this.sunrise - Math.floor(this.sunrise)) * 60);
        var setDate = new Date();
        setDate.setHours(this.sunset / 60);
        setDate.setMinutes(this.sunset % 60);
        setDate.setSeconds((this.sunset - Math.floor(this.sunset)) * 60);
        info = "\u2191 " + this.formatTime(riseDate) + " - \u2193 " + this.formatTime(setDate); 
      }
      */
    }
    else if (this.infoIndex == 2) {
      var zone = this.timeZone;
      var min = Math.abs(parseInt((zone - parseInt(zone)) * 60));
      if (min == 0) {
        min = "00";
      }
      var gmt = this.dst ? "DST" : "GMT";
      if (zone == 0) {
        info = gmt;      
      }
      else if (zone > 0) {
        info = gmt + " +" + parseInt(zone) + ":" + min;
      }
      else {
        info = gmt + " -" + (-parseInt(zone)) + ":" + min;        
      }  
    }  
    this.date.innerHTML = info;
  }
    
  this.update2 = function(date) {
    date = new Date(date.getTime());  
    this.lastSeconds = date.getTime() / 1000;
    var dstValue = this.dst ? 1 : 0;
    var offset = getTimezoneOffset(date);
    //date.setHours(date.getHours() + date.getTimezoneOffset() / 60 + this.timeZone + dstValue);
    date.setTime(date.getTime() + (offset / 60 + timeZone + dstValue) * 60 * 60000);
    this.backPane(date);
  }
  
  this.backPane = function(date) {  
    this.time.innerHTML = this.formatTime(date);
    if (this.infoIndex == 0 || this.infoIndex == 2) {
      this.updateInfo(date);
    }
    if (this.lastDay != date.getDay()) {
      this.updateInfo(date);
      this.lastDay = date.getDay();
    }
    var minutes = date.getHours() * 60 + date.getMinutes();
    var night = minutes < this.sunrise || minutes >= this.sunset;
    if (night) {
      if (!this.isNight) {
        this.changeBorder("backb");
        this.updateSunTimes();
      }  
      this.setTextColorArray(nightTextColor);
      //this.stars.style.opacity = 1.0;
      //this.glow.style.opacity = "0.0";
      this.sun.style.visibility = "hidden";
	  this.sun.style.height= "0px";
      this.moon.style.visibility = "visible";
	  this.moon.style.height="36px";
      var mins = minutes;
      if (mins < this.sunrise) {
        mins += 24 * 60;
      }
      var moonx = (mins - this.sunset) / (this.sunrise + (24*60 - this.sunset));
      //this.moon.style.left = parseInt(15 + moonx * 240) + "px";
      //this.moon.style.bottom = parseInt(-25 + 87 * Math.sin(moonx * Math.PI)) + "px"; 
      if (moonx > 0.3 && moonx < 0.7) {
        //this.clock.style.overflow = "visible";
      }
      else {
        //this.clock.style.overflow = "hidden";
      }
      var isSunrise = true;
      var dawnColor = dawnColorRise;
      var diff = minutes - this.sunrise;
      if (diff > 0) {
        diff = this.sunset - minutes;
        isSunrise = false;
        dawnColor = dawnColorSet;
      }
      if (diff > -dawn) {
        //this.glow.style.opacity = "" + (1.0 + diff / dawn);
        //this.stars.style.opacity = "" + (-diff / dawn);
      }
      //this.pane.style.backgroundColor = "rgb(" + nightColor[0] + "," + nightColor[1] + "," + nightColor[2] + ")";
      if (diff < 0 && diff > -dawn2) {
        //this.pane.style.backgroundColor = getColor(nightColor, dawnColor, dawn2 + diff, dawn2);
        //setTextColor(getColor(nightTextColor, dawnTextColorRise, dawn2 + diff, dawn2));
        if (!isSunrise) {
          //this.clouds.style.opacity = 1+diff/dawn2;
        }  
      }
      if ((date.getDate() == 24 && date.getMonth() == 11 && !isSunrise) || 
          (date.getDate() == 25 && date.getMonth() == 11 && isSunrise)) {
        this.moon.style.display = "none";
        //this.santa.style.left = parseInt(this.moon.style.left) - 25 + "px";
        //this.santa.style.bottom = this.moon.style.bottom;
        //this.santa.style.display = "block";
      }
      else {
        this.moon.style.display = "block";
        //this.santa.style.display = "none";
      }  
    }
    else {
      if (this.isNight) {
        this.changeBorder("back");
        this.updateSunTimes();
      }
      this.setTextColorArray(dayTextColor);  
      //this.stars.style.opacity = "0.0";
      //this.glow.style.opacity = "0.0";
      this.moon.style.visibility = "hidden";
	  this.moon.style.height= "0px";
      this.sun.style.visibility = "visible";
	  this.sun.style.height= "36px";
      var sunx = (minutes - this.sunrise) / (this.sunset - this.sunrise);
      //this.sun.style.left = parseInt(15 + sunx * 240) + "px";
      //this.sun.style.bottom = parseInt(-25 + 87 * Math.sin(sunx * Math.PI)) + "px"; 
      if (sunx > 0.3 && sunx < 0.7) {
        //this.clock.style.overflow = "visible";
      }
      else {
        //this.clock.style.overflow = "hidden";
      }  
      var isSunrise = true;
      var dawnColor = dawnColorRise;
      var diff = minutes - this.sunrise;
      if (diff > dawn) {
        diff = this.sunset - minutes;
        isSunrise = false;
        dawnColor = dawnColorSet;
      }
      if (diff < dawn) {
        //this.glow.style.opacity = "" + (1.0 - diff / dawn);
      }
      //this.pane.style.backgroundColor = "rgb(" + dayColor[0] + "," + dayColor[1] + "," + dayColor[2] + ")";
      if (diff < dawn2) {
        //this.pane.style.backgroundColor = getColor(dayColor, dawnColor, dawn2 - diff, dawn2);
        //setTextColor(getColor(dayTextColor, dawnTextColorRise, dawn2 - diff, dawn2));
        if (!isSunrise) {
          //this.clouds.style.opacity = 1 - diff/dawn2;
        }  
      }    
    }
    if (isSunrise) {
      //this.glow.style.backgroundPosition = "left";
    }
    else {
     // this.glow.style.backgroundPosition = "right";      
    }
    this.isNight = night;
	//this.toggleTimeFormat();
  }

  this.formatTime = function(date) {
    var hours = date.getHours();
    var minutes = date.getMinutes() + "";
    var seconds = lastSeconds % 60 + "";
    return this.formatTime2(date.getHours(), date.getMinutes(), parseInt(date.getTime() / 1000 % 60));
  }

  this.formatTime2 = function(hours, minutes, seconds) {
    var isPM = hours >= 12;
    if (this.show12Clock) {
      hours = hours % 12;
      if (hours == 0) {
        hours = 12;
      }
    }
    hours = hours + "";
    if (hours.length < 2 && !this.show12Clock) {
      hours = "0" + hours;
    }    
    minutes = minutes + "";
    if (minutes.length < 2) {
      minutes = "0" + minutes;
    }
    seconds = seconds + "";
    if (seconds.length < 2) {
      seconds = "0" + seconds;
    }
    var result = hours + ":" + minutes + ":" + seconds;
    if (this.show12Clock) {
      if (isPM) {
        result += "<span class='timeExt'>PM</span>";
      }
      else {
        result += "<span class='timeExt'>AM</span>";
      }
    }
    return result;
  }
  
  this.toggleTimeFormat = function() {
    this.show12Clock = !this.show12Clock;
    this.updateInfo();
    this.update2(new Date());
    //saveClock(this);
  }

  this.changeBorder = function(prefix) {
    for (var i = 0; i < tableTd.length; i++) {
    	//var element = document.getElementById("Table_" + tableTd[i] + this.id);
    	//element.setAttribute("background", prefix + "_" + tableTd[i] + ".png");
    }
    for (var i = 0; i < tableImg.length; i++) {
    	//var element = document.getElementById("Table_" + tableImg[i] + this.id);
    	//element.src = prefix + "_" + tableImg[i] + ".png";
    }
    if (prefix == "backb") {
      //document.getlementById("Table_c" + this.id).setAttribute("bgcolor", "black");
      //document.getElementById("Table_c" + this.id).style.backgroundColor = "black";
    }
    else {
      //document.getElementById("Table_c" + this.id).setAttribute("bgcolor", "white");      
      //document.getElementById("Table_c" + this.id).style.backgroundColor = "white";
    }  
   // document.getElementById("Mask" + this.id).style.backgroundImage = "url(mask_" + prefix + ".png)";
  }

  this.setTextColorArray = function(colorArray) {
    var color = "rgb(" + colorArray[0] + "," + colorArray[1] + "," + colorArray[2] + ")";
    this.setTextColor(color);
  }
  
  this.setTextColor = function(color) {
    this.time.style.color = color;
    this.date.style.color = color;      
    this.loc.style.color = color;        
  }

  

  var date = new Date();
  if (navigator.language) {
    this.show12Clock = navigator.language.toLowerCase().indexOf("en") >= 0 
        || date.toLocaleTimeString().toLowerCase().indexOf("am") >= 0
        || date.toLocaleTimeString().toLowerCase().indexOf("pm") >= 0;
  }
  else {
    this.show12Clock = date.toLocaleTimeString().toLowerCase().indexOf("am") >= 0
        || date.toLocaleTimeString().toLowerCase().indexOf("pm") >= 0;    
  }      
  
  this.calcSun(13, -5, 38.833333, -77);
  this.updateSunTimes();

  this.loc.innerHTML = this.city;
  this.updateInfo();
    
}

var backWidth = 220;
var backHeight = 220;
var frontWidth = 322;
var frontHeight = 111;
var backShown = false;
var interval = null;
var lastSeconds = 0;

var dawn = 60;
var dawn2 = 15;
var nightColor = [0, 0, 0];
var dayColor = [255, 255, 255];
var dawnColorRise = [20, 20, 180];
var dawnColorSet = [160, 128, 100];
var dayTextColor = [255, 255, 255];//"#202020";
var dawnTextColorRise = [160, 160, 160];
var dawnTextColorSet = [160, 160, 160];
var nightTextColor = [120, 120, 120];//"#E0E0E0";


var tableTd = ["tc", "tr", "lc", "rc", "bl", "bc"];
var tableImg = ["tl", "br"];

var daysAfterMonth = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
var specials = [-9.5, -3.5, 3.5, 4.5, 5.5, 5.75, 6.5, 8.75, 9.5, 10.5, 11.5, 12.75];

var nextId = 0;
var clocks = new Object();

var map = null;
var marker = null;
var geocoder = null;

var clocksCookie;



function parseParameters() {
  try {
    var search = location.search;
    if (search != null && search.length > 0) {
      var city = getParameter(search, "city", null);
      if (city != null) {
        var timeZone = parseFloat(getParameter(search, "timeZone", null));
        if (timeZone != null) {
          var lat = parseFloat(getParameter(search, "lat", null));
          if (lat != null) {
            var lng = parseFloat(getParameter(search, "long", null));
            if (lng != null) {
              var dst = getParameter(search, "dst", "false") == "true";
              createNewClock(city, timeZone, dst, lat, lng);
              location.search = "";
            }
          }
        }
      }
    }
  }
  catch (e) {
    alert("Failed to parse URL parameters: " + e);
  }
}

function getParameter(src, key, defaultValue) {
  if (src.indexOf("&amp;") >= 0) {
    src = src.replace(/\&amp\;/g, "&");
  }
  var index = src.indexOf("&" + key + "=");
  if (index < 0) {
    index = src.indexOf("?" + key + "=");
  }
  if (index >= 0) {
    var index2 = src.indexOf("&", index + 1);
    if (index2 >= 0) {
      return decode(src.substring(index + key.length + 2, index2));
    }
    return decode(src.substring(index + key.length + 2));
  }
  return defaultValue;   
}

function decode(value) {
  var result = decodeURIComponent(value);
  return result.replace(/(\+)/g, " ");
}



function createDefaultClocks() {
  if (interval) {
      clearInterval(interval);
    }
    interval = setInterval(update, 100);
  
  
  var clock;
  
  clock = createNewClock("Papeete", -10, false, -17.535021,-149.569595);
  clock.changeInfo();
  
  
  clock = createNewClock("Paris", 2, true, 48.8566667, 2.3509871);
  clock.changeInfo();
 
  clock = createNewClock("Noum&eacute;a", 11, false, -22.2758333, 166.4580556);
  clock.changeInfo();
 
 
  clock = createNewClock("Mata'Utu", 12, false, -13.283, 179.983);
  clock.changeInfo();
  
  
 
}

function reloadClocks(ids) {
  for (var i = 0; i < ids.length; i++) {
  	var cookie = new Cookie("Clock" + ids[i]);
  	try {
  	  var text = cookie.get();
    	if (text != null) {
    	  var settings = eval("new Object(" + text + ")");
    	  if (!settings.dst) {
    	    settings.dst = false;
    	  }    	      	      	    	  
    	  clock = createClock(ids[i], settings.city, settings.timeZone, settings.dst, settings.cityLat, settings.cityLong);
    	  clock.infoIndex = settings.infoIndex;
    	  clock.show12Clock = settings.show12Clock;
    	  clock.cookie = cookie;
    	  clock.updateInfo();
    	}
    	nextId = Math.max(nextId, ids[i]);
  	}
  	catch (e) {
  	  alert("Reloading clock " + ids[i] + " failed: " + e);
  	  cookie.remove();
  	}  
  }
  saveClockIds();
  nextId++;
}






  
function update() {
  var date = new Date();
  if (lastSeconds == date.getTime() / 1000) {
    return;
  }
  lastSeconds = date.getTime() / 1000;
  for (var id in clocks) {  	
  	if (!clocks[id].isTest) {
  	  clocks[id].update2(date);
  	}  
  }
}      



function createNewClock(city, timeZone, dst, cityLat, cityLong) {
  var id = nextId++;
  var clock = createClock(id, city, timeZone, dst, cityLat, cityLong);
  return clock;
}  

function createClock(id, city, timeZone, dst, cityLat, cityLong) {
  var clock = document.createElement("div");
  clock.id = "Clock" + id;
  clock.style.display = "inline";
  clock.onmouseover = function() {
    clockMouseOver(this);
  }   
  clock.onmouseout = function() {
    clockMouseOut(this);
  }  
  var template = document.getElementById("ClockTemplate").innerHTML;
  clock.innerHTML = template.replace(/\$ID\$/g, id);
  document.getElementById("Clocks").appendChild(clock);  
  //document.getElementById("DstButton" + id).className = dst ? "dstButton dstOn" : "dstButton dstOff";
  var clockObj = setupClock(id, city, timeZone, dst, cityLat, cityLong);
  clock.clock = clockObj;
  return clockObj;
}

function setupClock(id, city, timeZone, dst, cityLat, cityLong) {
  var clock = new Clock(id, city, timeZone, dst, cityLat, cityLong);
  clocks["" + id] = clock;
  return clock;
}

function getTimezoneOffset(date) {
  var offset = date.getTimezoneOffset();
  var diff = -(date.getHours() - date.getUTCHours()) * 60;
  if (Math.abs(diff) != Math.abs(offset)) {
    if (diff > 0) {
      diff -= 24 * 60;
    }
    else {
      diff += 24 * 60;
    }  
  }
  if (diff != offset) {
    offset = -offset;
  }
  return offset;
}

  

