//Copyright 2006-2008 Simon Baird 
//Copyright 2009 NOC international

window.CoolClock = function(canvasId,displayRadius,skinId,showSecondHand,gmtOffset,colorMain) {
  return this.init(canvasId,displayRadius,skinId,showSecondHand,gmtOffset,colorMain);
}

CoolClock.findAndCreateClocks = function() {
  var canvases = document.getElementsByTagName("canvas");
  for (var i=0;i<canvases.length;i++) {
    var fields = canvases[i].className.split(" ")[0].split(":");
    if (fields[0] == "CoolClock") {
      new CoolClock(canvases[i].id,fields[2],fields[1],fields[3]!="noSeconds",fields[4],fields[5]); }
  }
}

CoolClock.addLoadEvent = function(func){
  var oldonload = window.onload;
  if (typeof window.onload != 'function')
    window.onload = func;
  else
    window.onload = function() {
      oldonload();
      func(); }
}

CoolClock.config = {
  clockTracker: {},
  tickDelay: 1000,
  longTickDelay: 15000,
  defaultRadius: 85,
  renderRadius: 100,
  defaultSkin: "standard",
  skins:  {
    standard: {
      outerBorder: { lineWidth: 1, radius:95, alpha: 1 },
      smallIndicator: { lineWidth: 2, startAt: 91, endAt: 93, alpha: 1 },
      largeIndicator: { lineWidth: 2, startAt: 85, endAt: 93, alpha: 1 },
      hourHand: { lineWidth: 6, startAt: -15, endAt: 50, alpha: 1 },
      minuteHand: { lineWidth: 4, startAt: -15, endAt: 75, alpha: 1 },
      secondHand: { lineWidth: 1, startAt: -20, endAt: 85,  alpha: 1 },
      secondDecoration: { lineWidth: 1, startAt: 0, radius: 4, fillColor: "red", color: "red", alpha: 1 }
    }
  }
};

CoolClock.prototype = { 
  init: function(canvasId,displayRadius,skinId,showSecondHand,gmtOffset,colorMain) {
    this.canvasId = canvasId;
    this.displayRadius = displayRadius || CoolClock.config.defaultRadius;
    this.skinId = skinId || CoolClock.config.defaultSkin;
    this.showSecondHand = typeof showSecondHand == "boolean" ? showSecondHand : true;
    this.tickDelay = CoolClock.config[ this.showSecondHand ? "tickDelay" : "longTickDelay"];
    this.canvas = document.getElementById(canvasId);
    this.canvas.setAttribute("width",this.displayRadius*2);
    this.canvas.setAttribute("height",this.displayRadius*2);
    this.canvas.style.width = this.displayRadius*2 + "px";
    this.canvas.style.height = this.displayRadius*2 + "px";
    this.renderRadius = CoolClock.config.renderRadius; 
    this.scale = this.displayRadius / this.renderRadius;
    this.ctx = this.canvas.getContext("2d");
    this.ctx.scale(this.scale,this.scale);
    this.gmtOffset = gmtOffset != null ? parseFloat(gmtOffset) : gmtOffset;
    this.colorMain = colorMain;
    CoolClock.config.clockTracker[canvasId] = this;
    this.tick();
    return this;
  },

  fullCircle: function(skin) {
    this.fullCircleAt(this.renderRadius,this.renderRadius,skin);
  },

  fullCircleAt: function(x,y,skin) {
    with (this.ctx) {
      save();
      globalAlpha = skin.alpha;
      lineWidth = skin.lineWidth;
      if (!document.all)
        beginPath();
      if (document.all)
        // excanvas doesn't scale line width so we will do it here
        lineWidth = lineWidth * this.scale;
      arc(x, y, skin.radius, 0, 2*Math.PI, false);
      if (document.all)
        // excanvas doesn't close the circle so let's color in the gap
        arc(x, y, skin.radius, -0.1, 0.1, false);
      if (skin.fillColor) {
        fillStyle = skin.fillColor
        fill(); }
      else {
        // XXX why not stroke and fill
        strokeStyle = this.colorMain;
        stroke(); }
      restore(); }
  },
  
  radialLineAtAngle: function(angleFraction,skin, color) {
    with (this.ctx) {
      save();
      translate(this.renderRadius,this.renderRadius);
      rotate(Math.PI * (2 * angleFraction - 0.5));
      globalAlpha = skin.alpha;
      strokeStyle = color;
      lineWidth = skin.lineWidth;
      if (document.all)
        // excanvas doesn't scale line width so we will do it here
        lineWidth = lineWidth * this.scale;
      if (skin.radius) {
        this.fullCircleAt(skin.startAt,0,skin) }
      else {
        beginPath();
        moveTo(skin.startAt,0)
        lineTo(skin.endAt,0);
        stroke(); }
      restore(); }
  },

  render: function(hour,min,sec) {
    var skin = CoolClock.config.skins[this.skinId];
    this.ctx.clearRect(0,0,this.renderRadius*2,this.renderRadius*2);
    //this.fullCircle(skin.outerBorder);
    for (var i=0;i<60;i++)
      this.radialLineAtAngle(i/60,skin[ i%5 ? "smallIndicator" : "largeIndicator"],this.colorMain);
       
    this.radialLineAtAngle((hour+min/60)/12,skin.hourHand,this.colorMain);
    this.radialLineAtAngle((min+sec/60)/60,skin.minuteHand,this.colorMain);
    if (this.showSecondHand) {
      this.radialLineAtAngle(sec/60,skin.secondHand,'red');
      if (!document.all)
        // decoration doesn't render right in IE so lets turn it off
        this.radialLineAtAngle(sec/60,skin.secondDecoration); }
  },

  nextTick: function() {
    setTimeout("CoolClock.config.clockTracker['"+this.canvasId+"'].tick()",this.tickDelay);
  },

  stillHere: function() {
    return document.getElementById(this.canvasId) != null;
  },

  refreshDisplay: function() {
    var now = new Date();
    if (this.gmtOffset != null) {
      var h = now.getHours();
      var m = now.getMonth() + 1;
      var d = now.getDate();
      var y = now.getFullYear();
      var initDay = (31 - ( Math.floor(5 * y / 4) + 4) % 7) ; 
      var endDay = (31 - ( Math.floor(5 * y / 4) + 1) % 7) ; 
      var summerTime = 0; 
      if ((m > 3 || (m == 3 && d > initDay) || (m == 3 && d == initDay && h >= 1)) && (m < 10 || (m == 10 && d < endDay) || (m == 10 && d == initDay && h <= 1))) { 
        summerTime = 1; } 
      // use GMT + gmtOffset
      var offsetNow = new Date(now.valueOf() + ((this.gmtOffset + summerTime) * 1000 * 60 * 60));
      this.render(offsetNow.getUTCHours(),offsetNow.getUTCMinutes(),offsetNow.getUTCSeconds()); }
    else {
      // use local time
      this.render(now.getHours(),now.getMinutes(),now.getSeconds()); }
  },

  tick: function() {
    if (this.stillHere()) {
      this.refreshDisplay()
      this.nextTick(); }
  }
}

CoolClock.addLoadEvent(CoolClock.findAndCreateClocks);

