var get_holidays_path = "fxtrade.oanda.com/cgi/wl/fxmarkethours/get_market_holidays.pl";

var market = new Array (
	new Market(0,  "SYDNEY", 22*60+0,  7*60+0, 3, 'AUD'),
	new Market(1,   "TOKYO",  0*60+0,  9*60+0, 0, 'JPY'),
	new Market(2,  "LONDON",  8*60+0, 17*60+0, 1, 'GBP'),
	new Market(3,"NEW YORK", 13*60+0, 22*60+0, 2, 'USD') 
);

var timeZoneOffset = (new Date()).getTimezoneOffset(); //default timeZone
var op1;
var op2;

//****************************************************//
function Market(id, marketName, openTime, closeTime, observeDST, currencyName) {
  this.id = id;
  this.name = marketName;
  this.GMTopenTime = openTime;//in minutes (from 12am)
  this.GMTcloseTime = closeTime;
  this.openTime = 0; //open time in the specific time zone
  this.closeTime = 0;
  this.observeDST = observeDST;
  this.timeA_closed = 0; // close or open status of market at timeA
  this.timeB_closed = 0; // close or open status of market at timeB
  this.isClosed = isMarketClosed; //function

  // local holidays market is closed
  this.holidays = ''; //'01.01.2006 ~New Year~ 25.12.2006 ~Christmas~ ';

  var mk = this;
  this.initHolidays = function initMarketHolidays() {
    //process AJAX response and init market holidays
    var myajax = mk.ajaxpack.ajaxobj;
    var myfiletype = mk.ajaxpack.filetype;
    if (myajax.readyState == 4) { //request of file completed
      if (myajax.status == 200 || window.location.href.indexOf("http") == -1){ 
        //request was successful or running script locally
        if (myfiletype == "xml") {
	      var xmlDoc = myajax.responseXML;
  	      mk.holidays += xmlDoc.getElementsByTagName(currencyName).item(0).firstChild.data;
	      //alert(mk.holidays); 
  	    }
        else { // by accident
  	        //alert(mk.name+": Holiday data has the wrong format."); //myajax.responseText
        } 
      }
      else {
        //AJAX request failed
        //alert("Could not acquire list of bank holidays for "+mk.name+ " market.");
      }
    }
  } //end function initMarketHolidays

  this.ajaxpack = createAjaxPack();

  var d = new Date();
  var day  = d.getDate();
  var month= d.getMonth()+1;
  var year = d.getFullYear();
  var fromDate = day + "." + month + "." + year;

  var postRequest = "currencyName="+currencyName+"&fromDate="+fromDate;
  try {
     this.ajaxpack.postAjaxRequest("http://"+get_holidays_path, postRequest, this.initHolidays, "xml");
  } catch(e) {
     //alert("Could not acquire list of bank holidays for "+this.name+ " market.");
  }
}

//****************************************************//
function isMarketClosed(date) {
  // markets are closed on Saturdays and Sundays
  if (date.getDay() == 0) {return 1;}
  if (date.getDay() == 6) {return 1;}

  var holidays = this.holidays;
  var dateStr = dateToStr(date);
  
  // no local holiday for the specified market
  if (holidays.indexOf(dateStr) == -1) {
    return 0;
  } else {
    return 1;
  }
}

//****************************************************//
function computeDST_diff(observeDST) {
  //difference between current time and std time. If it is Daylight Saving Time (DST),
  //and the market observes it, the difference is 60 minutes otherwise 0.

  if (!observeDST) { return 0; } //when market dosen't observe DST

  var dst_start = new Date(); 
  var dst_end   = new Date();
  var current   = new Date();
  
  if (observeDST == 2) {
    // compute 2nd Sunday of March (for NYC in 2007)
    dst_start.setMonth(2); // Set from month 0-11
    dst_start.setDate(1);
    var wday = dst_start.getDay();// what weekday is 1st?
    if ( wday == 0 /* as in sunday */) { wday = 7; }
    dst_start.setDate(15-wday); // subtract from the highest possible value of the second sunday

    // compute first Sunday of November
    dst_end.setMonth(10); // pick November
    dst_end.setDate(1);
    wday = dst_end.getDay(); // what weekday is 1st?
    if ( wday == 0 /* as in sunday */) { wday = 7; }
    dst_end.setDate(8-wday); // go back until last Sunday

	} else 
  	if (observeDST == 3) {  
    // compute first Sunday of October for previous year
    // Australia in southern hemisphere observe daylight savings 
    // time opposite seasons of US
    dst_start.setMonth(9);
    dst_start.setDate(1);
    dst_start.setFullYear(dst_start.getFullYear()-1);
    var wday = dst_start.getDay(); // what weekday is 1st?
    if ( wday == 0 /* as in sunday */) { wday = 7; }
    dst_start.setDate(8-wday); // go back until last Sunday
    
    // compute first Sunday of April
    dst_end.setMonth(3);
    dst_end.setDate(1);
    wday = dst_end.getDay(); // what weekday is 1st?
    if ( wday == 0 /* as in sunday */) { wday = 7; }
    dst_end.setDate(8-wday); // go back until last Sunday

  	} else {
    // compute last Sunday of March
    dst_start.setMonth(2);
    dst_start.setDate(31);
    var wday = dst_start.getDay(); // what weekday is 31st?
    dst_start.setDate(31-wday); // go back until last Sunday

    // compute last Sunday of October
    dst_end.setMonth(9);
    dst_end.setDate(31);
    wday = dst_end.getDay(); // what weekday is 31st?
    dst_end.setDate(31-wday); // go back until last Sunday
  }

  if (current >= dst_start && current < dst_end) { return 60; } else { return 0; }
}

//****************************************************//
function adjustMarketHours() {
  // convert GMT times to the timeZone time
  
  for (var row=0; row<market.length;row++) {
    // difference in minutes
    var DST_diff = computeDST_diff(market[row].observeDST);
    market[row].openTime = (market[row].GMTopenTime - timeZoneOffset - DST_diff + 24*60)%(24*60);
    market[row].closeTime = (market[row].GMTcloseTime - timeZoneOffset - DST_diff + 24*60)%(24*60);
    //alert("opentime for "+ market[row].name + " is " + market[row].openTime + " " + market[row].GMTopenTime + " " + timeZoneOffset + " " + DST_diff);
  }
}

//****************************************************//
function isHoliday(current_date) {
  // current_date is the local time for the seleted time-zone

  var time_tmp;
  var num_rows = market.length;
  for (var row = 0 ; row < num_rows; row++) {
    var opday = new Date();
    opday.setTime(opday.getTime());
    opday.setHours(0);
    opday.setMinutes(0);
    opday.setSeconds(0);
//if (row == 0) op1 = { var b = new Date(); b.setTime(b.getTime()); b.setHours(0); b.setMinutes(0); b.setSeconds(0); }
//if (row == 0) op2 = opday;
    if ( current_date > opday && current_date.getDay() != opday.getDay() ) {
      // open date is the next day - +24 hours
      opday.setTime( opday.getTime() + 24*60*60*1000 );
    }

    //compute local opening time of market in minutes from 12am
    time_tmp = market[row].openTime;

    opday.setTime( opday.getTime() + time_tmp*60*1000 );
    market[row].timeA_closed = market[row].isClosed(opday);

    //check market closure on the previous day
    opday.setTime(opday.getTime() - 24*3600*1000);
    market[row].timeB_closed = market[row].isClosed(opday);
  }
}

//****************************************************//
function genStatus(current_date) {
  // generate html code for the status section

  // current_time is the local time for the seleted time-zone
  var htmlCode='<div><table><tr>';

  var current = current_date.getHours()*60 + current_date.getMinutes();
  var num_rows = market.length;

  for (var row=0; row < num_rows; row++) {
    if ( (current < market[row].closeTime) &&
         ( (current >= market[row].openTime && !market[row].timeA_closed) || (market[row].openTime > market[row].closeTime && !market[row].timeB_closed) ) ) {
	      htmlCode += '<td class="statOpen">';
    }
    else if (current >= market[row].openTime && market[row].openTime > market[row].closeTime && !market[row].timeA_closed) {
      htmlCode += '<td class="statOpen">';
    }
    else {
      htmlCode += '<td class="statClose">'; 
    }
    htmlCode += market[row].name + '</td>';
  }

  htmlCode += '<td class="statOpen">(Open)</td><td class="statClose">(Closed)</td>';
//htmlCode += '<td class="statOpen">' + op1 + ' ' + op2 + '</td>';
  htmlCode += '</tr></table></div>';
//htmlCode = '';
  return htmlCode;
}

//****************************************************//
function setTimer() {
  // refresh status every minute
  if ((new Date()).getSeconds() == 0) { 
    refreshStat();
  }
  
  // set timer for 1 sec
  setTimeout("setTimer();", 1*1000); 
}

//****************************************************//
function refreshStat() {
  var current_date = new Date();

  // convert time for the selected timeZone
  var time_tmp = current_date.getTimezoneOffset() - timeZoneOffset;
  current_date.setTime(current_date.getTime() + time_tmp*60*1000);

  // markets closed because of a holiday or weekend 
  isHoliday(current_date);

  // update markets status section
  refreshDiv('mhStatus', genStatus(current_date));
}

//****************************************************//
function initMarket() {
  adjustMarketHours();
  refreshStat(); 
}

//****************************************************//
function dateToStr(mydate) { 
  // output example: "01.01.2010" - used as input to market[].isClosed
  var d = mydate.getDate();
  if (d < 10) { d = '0' + d;} //make a 2-digit day
  
  var m = mydate.getMonth()+1;
  if (m < 10) { m = '0' + m;} //make a 2-digit month
  
  var str = d +"."+ m +"."+ mydate.getFullYear();
  return str;
}

function refreshDiv(div, html) {
  if (document.getElementById) {
  	var a = document.getElementById(div);
  }
  
  if (document.all) {
  	var a = document.all[div];
  }

  if (!a) {
    window.alert("An error has occurred (refreshDiv)");
    return;
  }

  if (a.innerHTML) {
    a.innerHTML = html;
  } else { 
    if (a.document && a.document != window.document){
      a.document.open();
      a.document.write(html);
      a.document.close();
    } else {
      window.alert("An error has occurred (refreshDiv)");
    }
  }
}

