/*
** Copyright (c) 2005 Riseburn
** 
** This software is provided 'as-is', without any express or implied warranty.
** In no event will the authors be held liable for any damages arising from
** the use of this software.
** 
** Permission is granted to anyone to use this software for any purpose,
** including commercial applications, and to alter it and redistribute it
** freely, subject to the following restrictions:
** 
** 1. The origin of this software must not be misrepresented; you must not
**    claim that you wrote the original software. If you use this software in
**    a product, an acknowledgment in the product documentation would be
**    appreciated but is not required.
** 
** 2. Altered source versions must be plainly marked as such, and must not be
**    misrepresented as being the original software.
** 
** 3. This notice may not be removed or altered from any source distribution.
*/

/*
** These 3 functions deal with the dragging of boxes
*/
	
var deltaX, deltaY;
var totalX = 0;
var totalY = 0;

function mousedown(event)
{
  //alert(evt.source.tagName);
  if (Event.element(event).tagName.toUpperCase() == "TEXTAREA")
    return false;

  deltaX = Event.pointerX(event);
  deltaY = Event.pointerY(event);
  Event.observe(this,"mousemove",mousemove,false);
  Event.observe(this,"mouseup",mouseup,false);
  Event.stop(event);
}

function mousemove(event)
{
  totalX += Event.pointerX(event) - deltaX;
  totalY += Event.pointerY(event) - deltaY;
  for (var index=0;index<this.childNodes.length;index++)
  {
    var container = this.childNodes[index];
    //setX(container,getX(container) + Event.pointerX(event) - deltaX); 
    setY(container,getY(container) + Event.pointerY(event) - deltaY);

  }
  
  deltaX = Event.pointerX(event);
  deltaY = Event.pointerY(event);
  Event.stop(event);
}

function mouseup(event) {
  totalX = 0;
  totalY = 0;
  Event.stopObserving(this,"mousemove",mousemove,false);
  Event.stopObserving(this,"mouseup",mousemove,false);
  Event.stop(event);
}

/*
** The Calendar object
*/

function Calendar(container)
{
  this.container      = container;
  this.zoomLevel      = null;
  
  this.container.style["position"] = "relative";
  this.container.style["overflow"] = "hidden";
  
  this.container.handleEvent = function (event) {alert(event.type)};
  
  Event.observe(this.container, "mousedown", mousedown, false);

  var calendar = this;
  setTimeout(function () {calendar.refreshBoxes(); setTimeout(arguments.callee, 500)}, 500);
}


Calendar.prototype.BOX_ATTRIBUTE_DATETIME = "DateTime";
Calendar.prototype.BOX_ATTRIBUTE_ZOOMLEVEL = "zoomLevel";

Calendar.prototype.BOX_ATTRIBUTE_CLASSNAME = "calendar_box";
Calendar.prototype.TITLE_ATTRIBUTE_CLASSNAME = "calendar_title";
Calendar.prototype.CELL_ATTRIBUTE_CLASSNAME = "calendar_cell";
Calendar.prototype.CELL_ENTRY_CLASSNAME = "calendar_entry";

Calendar.prototype.BOX_SEPARATION = 2;
Calendar.prototype.BOX_HEIGHT = 100;
Calendar.prototype.BOX_LIMIT = 200;

Calendar.prototype.getCenterDateTime = function()
{
  var closest;
  var box;
  for (var index=0;index<this.container.childNodes.length;index++)
  {
    var child = this.container.childNodes[index];
    var dist = Math.sqrt(Math.pow(getWidth(this.container)/2-getX(child) - getWidth(child)/2,2) + Math.pow(getHeight(this.container)/2-getY(child) - getHeight(child)/2,2));
    if (closest == null || closest>dist)
    {
      closest = dist;
      box = child;
    }
  }
  return new DateTime(box.getAttribute(this.BOX_ATTRIBUTE_DATETIME));
}

Calendar.prototype.centerAtDateTime = function(dateTime)
{
  return this.centerAndZoom(dateTime, this.getZoomLevel());
}
                     
Calendar.prototype.getZoomLevel = function()
{
  return this.zoomLevel;
}                    

Calendar.prototype.zoomTo = function(zoomLevel)
{
  return this.centerAndZoom(this.getCenterDateTime(), zoomLevel);
}
               
Calendar.prototype.centerAndZoom = function(dateTime, zoomLevel)
{
  this.zoomLevel  = zoomLevel;
  
  // Remove all the old containers
  while (this.container.childNodes.length)
    this.container.removeChild(this.container.lastChild);

  // create the centre box ...
  var central = this.container.appendChild(this.createBox(dateTime));
  
  // ... and centre it
  setY(central,(getHeight(central.parentNode) - getHeight(central))/2);

  // All the other boxes will be automatically created by the timer
  return;
}

Calendar.prototype.refreshBoxes = function()
{
  var box = this.container.firstChild;
  
  if (!box)
    return;
  
  while (box = box.nextSibling)
    setY(box, getY(box.previousSibling) + getHeight(box.previousSibling) + this.BOX_SEPARATION);
  
  //alert(getY(container));
  while (getY(this.container.firstChild) + getHeight(this.container.firstChild) + this.BOX_SEPARATION < 0 - Calendar.prototype.BOX_LIMIT)
  {
    this.container.removeChild(this.container.firstChild);
  }
  
  var box = this.container.firstChild;
  while (getY(box) > 0 - Calendar.prototype.BOX_LIMIT)
  {
    box = this.container.insertBefore(this.createBox(new DateTime(box.getAttribute(this.BOX_ATTRIBUTE_DATETIME)).modify("-1 " + this.zoomLevel)), box);
    setY(box, getY(box.nextSibling) - getHeight(box.nextSibling) - this.BOX_SEPARATION)		    
  }
  
  while (getY(this.container.lastChild) > getHeight(this.container) + Calendar.prototype.BOX_LIMITT)
  {
    this.container.removeChild(this.container.lastChild);
  }
  
  box = this.container.lastChild;
  while (getY(box) + getHeight(box) + this.BOX_SEPARATION < getHeight(this.container) + Calendar.prototype.BOX_LIMIT)
  {
    box = this.container.appendChild(this.createBox(new DateTime(box.getAttribute(this.BOX_ATTRIBUTE_DATETIME)).modify("+1 " + this.zoomLevel)));
    setY(box, getY(box.previousSibling) + getHeight(box.previousSibling) + this.BOX_SEPARATION)
  }
}

Calendar.prototype.createBox = function(dateTime)
{
  dateTime.modify("start of " + this.zoomLevel);
 
  if (this.zoomLevel == "week")
    dateTime.modify("+1 day");
  
  var box = document.createElement("TABLE");
  box.className = this.BOX_ATTRIBUTE_CLASSNAME;
  box.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
  box.setAttribute(this.BOX_ATTRIBUTE_ZOOMLEVEL, this.zoomLevel);
  box.style["position"] = "absolute";

  setX(box, this.BOX_SEPARATION);
  setWidth(box, getWidth(this.container) - this.BOX_SEPARATION*2 - 2);

  var row = box.appendChild(document.createElement("TR"));
  
  if (this.zoomLevel == "day")
  {
    var cell = document.createElement("TD");
    cell.className = this.CELL_ATTRIBUTE_CLASSNAME;
    cell.innerHTML = dateTime.getDayName() + "<br/> " + dateTime.getDay() + "." + dateTime.getMonth() + "." + dateTime.getYear();
    cell.innerHTML += "<br/><a href='' onclick='startEntry(event,true)'>add</a>";
    row.appendChild(cell);
    cell.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
  }
  else if (this.zoomLevel == "week")
  {
    for (var index=0;index<7;index++)
    {
      var cell = document.createElement("TD");
      cell.className = this.CELL_ATTRIBUTE_CLASSNAME;
      cell.innerHTML = dateTime.getDayName() + "<br/> " + dateTime.getDay() + "." + dateTime.getMonth() + "." + dateTime.getYear();
      cell.innerHTML += "<br/><a href='' onclick='startEntry(event,true)'>add</a>";
      row.appendChild(cell);
      cell.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
      dateTime = dateTime.toDateTime();
      dateTime.modify("+1 day");
    }
  }
  else if (this.zoomLevel == "month")
  {
    var cell = document.createElement("TD");
    cell.className = this.CELL_ATTRIBUTE_CLASSNAME;
    cell.innerHTML = dateTime.getMonthName() + " " + dateTime.getYear();
    cell.innerHTML += "<br/><a href='' onclick='startEntry(event,true)'>add</a>";
    row.appendChild(cell);
    cell.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
  }
  else if (this.zoomLevel == "year")
  {
    var cell = document.createElement("TD");
    cell.className = this.CELL_ATTRIBUTE_CLASSNAME;
    cell.innerHTML = dateTime.getYear();
    cell.innerHTML += "<br/><a href='' onclick='startEntry(event,true)'>add</a>";
    row.appendChild(cell);
    cell.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
  }
  else if (this.zoomLevel == "decade")
  {
    for (var index=0;index<10;index++)
    {
      var cell = document.createElement("TD");
      cell.className = this.CELL_ATTRIBUTE_CLASSNAME;
      cell.innerHTML = dateTime.getYear();
      cell.innerHTML += "<br/><a href='' onclick='startEntry(event,true)'>add</a>";
      row.appendChild(cell);
      cell.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
      dateTime = dateTime.toDateTime();
      dateTime.modify("+1 year");
    }
  }
  else if (this.zoomLevel == "century")
  {
    var cell = document.createElement("TD");
    cell.className = this.CELL_ATTRIBUTE_CLASSNAME;
    cell.innerHTML = dateTime.getYear() - dateTime.getYear() % 100;
    cell.innerHTML += "<br/><a href='' onclick='startEntry(event,true)'>add</a>";
    row.appendChild(cell);
    cell.setAttribute(this.BOX_ATTRIBUTE_DATETIME, dateTime);
  }
  else
  {
    throw new Error("Unknown zoom level: '" + this.zoomLevel + "'");
  }
  
  return box;
}

/*
** These functions deal with entries
*/

function startEntry(event,add)
{
  var cell = Event.findElement(event,"TD");
  var span;
  if (add)
  {
    span = document.createElement("DIV");
    span.className = Calendar.CELL_ENTRY_CLASSNAME;
  }
  else
  {
    span = Event.findElement(event,"DIV")
  }
  span.removeAttribute("onmousedown");

  span.oldHTML = span.innerHTML;
  span.innerHTML  = "<textarea rows='5' cols='10'>"+span.oldHTML+"</textarea>";
  span.innerHTML += "<a href='#' onclick='finishEntry(event,"+add+",true)'>done</a>";
  span.innerHTML += " <a href='#' onclick='finishEntry(event,"+add+",false)'>cancel</a>";

  if (add)
    cell.appendChild(span);
  else
    span.innerHTML += " <a href='#' onclick='finishEntry(event,null,true,true)'>remove</a>";

  span.firstChild.focus();
  
  Event.stop(event);
  return false;
}

function finishEntry(event,add,save,remove)
{
  var cell = Event.findElement(event,"TD");
  var span = Event.findElement(event,"DIV");
  if (remove)
    span.firstChild.value = "";
  if (save)
  {
    if (span.firstChild.value == "")
      span.parentNode.removeChild(span);
    else  
      span.innerHTML = span.firstChild.value;
  }
  else if (add)
  {
    span.parentNode.removeChild(span);
  }
  else  
  {
    span.innerHTML = span.oldHTML;
  }
  
  span.setAttribute("onmousedown", "startEntry(event,false)");

  cell.innerHTML = cell.innerHTML;
  Event.stop(event);
  return false;
}

/*
** These functions deal with node position and size
*/

function getX(node)
{
  return parseInt(node.style.left);
}

function getY(node)
{
  return parseInt(node.style.top);
}

function getWidth(node)
{
  return node.offsetWidth;
}

function getHeight(node)
{
  return node.offsetHeight;
}

function setX(node,x)
{
  node.style.left = x + "px";
}

function setY(node,y)
{
  node.style.top = y + "px";
}

function setWidth(node,width)
{
  node.style.width = width + "px";
}

function setHeight(node,height) 
{
  node.style.height = height + "px";
}


