// JavaScript Document
/* This script and many more are available free online at
The JavaScript Source :: http://javascript.internet.com
Created by: Michael O'Connell :: http://wunder-ful.com */

/**
* Invocation represents a function call in a specific object context with a list of parameters
* This is a very powerful object that allows code to be executed in it's intended context
* from any other context (context = the 'this' for that function).
* There is a perfomance hit to use this (takes about 5x more time)
* WARNING in IE if you try to use invoke on an object that is in a window that is no longer loaded it will throw "can't execute code in freed script"
* @constructor
* @param targetObj object to invoke a method on (functions not on an object are attached to the window object)
* @param functionName string containing the name of the function to invoke on targetObj
* @param arguments an Array of arguments to invoke the function with (optional)
* @author Mike O'Connell
*/
function Invocation(targetObj, functionName, arguments) {
  this.targetObj = targetObj;
  this.functionName = functionName;
  this.arguments = arguments;
}

/**
* Actually invoke the function call defined by this instance of Invocation.
* If the object doesn't exist, or the function does not exist it will not try to execute
* @param arguments an Array of arguments to invoke the function with (will be appended to the end of the predefined argument Array)
* @return The return value of the function invoked.
*/
Invocation.prototype.invoke = function(arguments) {
  if(this.targetObj && typeof this.targetObj[this.functionName] == "function") {
    var args = this.arguments;
    if(!args)
      args = new Array();
    if(arguments)
      args = args.concat(arguments);
    return this.targetObj[this.functionName].apply(this.targetObj, args);
  }
}

/**
* @return the sum of all the offsetTop values from this element to the body
*/
function getTotalOffsetTop(element) {
  var offset = 0;
  for(var i = element; i && i.tagName != "BODY"; i = i.offsetParent)
    offset+=i.offsetTop;
  return offset;
}

/**
* @return the sum of all the offsetLeft values from this element to the body
*/
function getTotalOffsetLeft(element) {
  var offset = 0;
  for(var i = element; i && i.tagName != "BODY"; i = i.offsetParent)
    offset+=i.offsetLeft;
  return offset;
}

/**
* Positions a absolutely positioned element over the anchor.  It will detect body clipping
* and move the right side of the element to the right of the anchor.  The element cannot
* have
* @param element the element to position
* @param anchor the anchor to position element over
* @param positionVertical position on "top" or "bottom" edge of the anchor
* @param positionHorizontal position on "left" or "right" edge of the anchor
*/
function positionAtAnchor(element, anchor, positionVertical, positionHorizontal) {
  var left = getTotalOffsetLeft(anchor);

  if(positionHorizontal == "right")
    left = left + anchor.offsetWidth + 1;

  //horizontal clip
  if(left + element.offsetWidth > document.body.scrollWidth && left - element.offsetWidth > 0) {
    left = left - element.offsetWidth;
    if(positionHorizontal == "right")
      left = left - anchor.offsetWidth;
    else
      left = left + anchor.offsetWidth + 1;
  }

  var top = getTotalOffsetTop(anchor);
  if(positionVertical == "bottom")
    top = top + anchor.offsetHeight + 1;

  //vertical clip
  if(top + element.offsetHeight > document.body.scrollHeight && top - element.offsetHeight > 0) {
    top = top - element.offsetHeight;
    if(positionVertical == "bottom")
      top = top - anchor.offsetHeight;
    else
      top = top + anchor.offsetHeight + 1;
  }

  element.style.top = top+"px";
  element.style.left = left+"px";
}


// ===========================

//map of dynaCalendars by name
var dynaCalendars = {};

/**
* Opens / closes the dynacalendar at the specified anchor
* @param name The unique name for the calendar to open.
* @param anchor A element to open the calendar under
**/
function openDynaCalendar(name, anchor) {
  var calendar = dynaCalendars[name];
  if(!calendar.isOpen)
    calendar.open(anchor);
  else
    calendar.close();
}

/**
* Constructor for the DynaCalendar
* @param name A unique name for this calendar
* @param invocation The function to pass the date when a date is selected.
* @param year Year to start calendar.
* @param month Month to start calendar.
* @param day Day to start calendar.
* @see Invocation
**/
function DynaCalendar(name, invocation, year, month, day) {
  //populate day of week and month name constants if not previously created...
  if(!DynaCalendar.MONTHS) {
    var MONTHS = [];
    var DOW = [];
    DynaCalendar.MONTHS = MONTHS;
    DynaCalendar.DOW = DOW;

    var tmpDate = new Date(2000, 0, 1);
    for(var i = 0; i < 12; i++) {
      tmpDate.setMonth(i);
      var dateStr = tmpDate.toLocaleString();
      var monthname = dateStr.match(/\s[a-zA-Z]+\s/)[0];
      monthname = monthname.substring(1,monthname.length-1);
      MONTHS[i] = monthname;
    }

    for(var i = 1; i < 8; i++) {
      tmpDate.setDate(i);
      var dateStr = tmpDate.toLocaleString();
      var dow = dateStr.substring(0,3);
      DOW[tmpDate.getDay()] = dow;
    }
  }

  if(year && month && day)
    this.date = new Date(year, month, day);
  else
    this.date = new Date();

  this.invocation = invocation;
  this.name = name;
  this.isOpen = false;
  this.rendered = false;
  this.bodyRendern = false;

  dynaCalendars[name] = this;
}

/**
* Displays the dynacalendar at the specified anchor.
* @param anchor A element to open the calendar under
*/
DynaCalendar.prototype.open = function(anchor) {
  if(!this.rendered)
    this.render();
  if(!this.bodyRendern)
    this.renderBody();
  this.calendarDiv.style.display = "block";
  positionAtAnchor(this.calendarDiv, anchor, "bottom", "left");
  this.isOpen = true;
}

/**
* Closes the dynaCalendar
*/
DynaCalendar.prototype.close = function() {
  this.calendarDiv.style.display = "none";
  this.isOpen = false;
}
var weekday = new Array(7)
weekday[0] = 'Sun'
weekday[1] = 'Mon'
weekday[2] = 'Tue'
weekday[3] = 'Wed'
weekday[4] = 'Thu'
weekday[5] = 'Fri'
weekday[6] = 'Sat'
/**
* Fills the calendarDiv with actual date spans
**/
DynaCalendar.prototype.render = function() {
  var calendarDiv = document.createElement("DIV");
  var calendarTable = document.createElement("TABLE");
  var calendarHead = document.createElement("THEAD");
  var calendarHeadTR = document.createElement("TR");
  var calendarHeadWeekTR = document.createElement("TR");
  var calendarBY = document.createElement("TH");
  var calendarBM = document.createElement("TH");
  var calendarTitle = document.createElement("TH");
  var calendarFM = document.createElement("TH");
  var calendarFY = document.createElement("TH");
  var calendarBody = document.createElement("TBODY");

  calendarDiv.className = "dynaCalendarDiv";
  calendarTable.className = "dynaCalendarTable";
  calendarTitle.colSpan = 3;

  calendarBY.className = "BF";
  calendarBM.className = "BF";
  calendarFM.className = "BF";
  calendarFY.className = "BF";
  calendarBY.innerHTML = "<<<";
  calendarBM.innerHTML = "<<";
  calendarFM.innerHTML = ">";
  calendarFY.innerHTML = ">>";
  calendarBY.onclick = dynaCalendarBackYearOnClick;
  calendarBM.onclick = dynaCalendarBackMonthOnClick;
  calendarFM.onclick = dynaCalendarForwardMonthOnClick;
  calendarFY.onclick = dynaCalendarForwardYearOnClick;

  calendarDiv.dynaCalendar = this;
  calendarHead.dynaCalendar = this;
  calendarBody.dynaCalendar = this;
  calendarBY.dynaCalendar = this;
  calendarBM.dynaCalendar = this;
  calendarTitle.dynaCalendar = this;
  calendarFM.dynaCalendar = this;
  calendarFY.dynaCalendar = this;

  this.calendarTitle = calendarTitle;
  this.calendarBody = calendarBody;
  this.calendarDiv = calendarDiv;

  //populate week header
  for(var i = 0; i < 7; i++) {
    var dowTH = document.createElement("TH");
    dowTH.innerHTML = weekday[i];
    calendarHeadWeekTR.appendChild(dowTH);
  }

  calendarHeadTR.appendChild(calendarBY);
  calendarHeadTR.appendChild(calendarBM);
  calendarHeadTR.appendChild(calendarTitle);
  calendarHeadTR.appendChild(calendarFM);
  calendarHeadTR.appendChild(calendarFY);
  calendarHead.appendChild(calendarHeadTR);
  calendarHead.appendChild(calendarHeadWeekTR);
  calendarTable.appendChild(calendarHead);
  calendarTable.appendChild(calendarBody);
  calendarDiv.appendChild(calendarTable);
  document.body.appendChild(calendarDiv);

  this.rendered = true;
}

/**
* Renders the actual month.
**/
DynaCalendar.prototype.renderBody = function() {
  //title
  var title = DynaCalendar.MONTHS[this.date.getMonth()]+ " " + this.date.getFullYear();
  this.calendarTitle.innerHTML = title;

  //clear table body
  while(this.calendarBody.hasChildNodes())
    this.calendarBody.removeChild(this.calendarBody.lastChild);

  //generate new table body
  var tmpDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1);

  var row = document.createElement("TR");
  this.calendarBody.appendChild(row);

  //blanks
  for(var i = 0; i < tmpDate.getDay(); i++) {
    var td = document.createElement("TD");
    row.appendChild(td);
  }

  while(tmpDate.getMonth() == this.date.getMonth()) {
    var td = document.createElement("TD");
    var date = tmpDate.getDate();
    if(date == this.date.getDate())
      td.className = "daySelected";
    else
      td.className = "day";

    td.innerHTML = date;
    td.dynaCalendar = this;
    td.onclick = dynaCalendarSelectDayOnClick;
    row.appendChild(td);

    if(tmpDate.getDay() == 6) {
      row = document.createElement("TR");
      this.calendarBody.appendChild(row);
    }

    tmpDate.setDate(date + 1);
  }

  //blanks
  for(var i = tmpDate.getDay(); i < 7; i++) {
    var td = document.createElement("TD");
    row.appendChild(td);
  }

  this.bodyRendern = true;
}

/**
* Set the day of the month
* @param date The date of the month to set the calandar to.
**/
DynaCalendar.prototype.setDate = function(date) {
  this.date.setDate(date);
  this.bodyRendern = false;
}

/**
* Moves back a year
**/
DynaCalendar.prototype.backYear = function() {
  this.setDate(1);
  this.date.setFullYear(this.date.getFullYear() - 1);
  this.renderBody();
}

/**
* Moves back a month
**/
DynaCalendar.prototype.backMonth = function() {
  this.setDate(1);
  this.date.setMonth(this.date.getMonth() - 1);
  this.renderBody();
}

/**
* Moves forward a month
**/
DynaCalendar.prototype.forwardMonth = function() {
  this.setDate(1);
  this.date.setMonth(this.date.getMonth() + 1);
  this.renderBody();
}

/**
* Moves forward a year
**/
DynaCalendar.prototype.forwardYear = function() {
  this.setDate(1);
  this.date.setFullYear(this.date.getFullYear() + 1);
  this.renderBody();
}

// Event handlers -------------------------------------------------------------
/**
* onclick to select a day
*/
function dynaCalendarSelectDayOnClick(event) {
  //IE
  if(window.event) {
    var srcElement = window.event.srcElement;
  }
  //MOZ
  else {
    var srcElement = event.currentTarget;
  }

  var calendar = srcElement.dynaCalendar;
  calendar.setDate(srcElement.innerHTML);
  if(calendar.invocation)
    calendar.invocation.invoke([calendar.date]);
  srcElement.dynaCalendar.close();

  return false;
}

/**
* onclick to go back one year
*/
function dynaCalendarBackYearOnClick(event) {
  //IE
  if(window.event) {
    var srcElement = window.event.srcElement;
  }
  //MOZ
  else {
    var srcElement = event.currentTarget;
  }

  srcElement.dynaCalendar.backYear();
  return false;
}

/**
* onclick to go back one month
*/
function dynaCalendarBackMonthOnClick(event) {
  //IE
  if(window.event) {
    var srcElement = window.event.srcElement;
  }
  //MOZ
  else {
    var srcElement = event.currentTarget;
  }

  srcElement.dynaCalendar.backMonth();
  return false;
}

/**
* onclick to go forward one month
*/
function dynaCalendarForwardMonthOnClick(event) {
  //IE
  if(window.event) {
    var srcElement = window.event.srcElement;
  }
  //MOZ
  else {
    var srcElement = event.currentTarget;
  }

  srcElement.dynaCalendar.forwardMonth();
  return false;
}

/**
* onclick to go forward one year
*/
function dynaCalendarForwardYearOnClick(event) {
  //IE
  if(window.event) {
    var srcElement = window.event.srcElement;
  }
  //MOZ
  else {
    var srcElement = event.currentTarget;
  }

  srcElement.dynaCalendar.forwardYear();
  return false;
}
// ===================================
function jm_datemask(t)
{var donepatt = /^(\d{2})\/(\d{2})\/(\d{4})$/;
var patt = /(\d{2}).*(\d{2}).*(\d{4})/;
var str = t.value;
if (!str.match(donepatt))
{result = str.match(patt);
if (result!= null)
{t.value = t.value.replace(/[^\d]/gi,'');
str = result[1] + '/' + result[2] + '/' + result[3];
t.value = str;
}else{
if (t.value.match(/[^\d]/gi))
t.value = t.value.replace(/[^\d]/gi,'');
}}}
// ===================================

