var RAKUSCRIPT = {};
/*
 * param {period: [2010, 9, 21, 13, 47],
 *        nodeid:{day: 'day', hour: 'hour', min: 'min', sec: 'sec'},
 *        html:{root:'root',
 *              before:'<span id="day"></span>日<span id="hour"></span>時<span id="min"></span>分<span id="sec"></span>秒', 
 *              after:'<h1>\'END\'</h1>',
 *              timetext:['<img src="0.gif",<img src="1.gif",…]}}
 */
RAKUSCRIPT.CountDownTimer = function(params) {
  var DAY_TIME = 1000*60*60*24;
  var HOUR_TIME = 1000*60*60;
  var MIN_TIME = 1000*60;
  var SEC_TIME = 1000;
  if (!params.html.timetext) {
    params.html.timetext = ['0','1','2','3','4','5','6','7','8','9'];
  }

  var that = {};
  that.format0 = function(str, len) {
    return ('_' + Math.pow(10, len) + str).slice(-len);
  };
  //数字numを指定した文字charsに置き換える
  that.num_to_str = function(num, chars) {
    //if (typeof(num) != 'string') { num = '' + num; }
    var result = '';
    for (var i = 0; i < num.length; ++i) {
      result += chars[parseInt(num.charAt(i))];
    }
    return result;
  };
  that.get_datetime = function(ptime) {
    var cnt = {};
    cnt.day = Math.floor(ptime / DAY_TIME);
    ptime = ptime - (cnt.day * DAY_TIME);
    cnt.hour = Math.floor(ptime / HOUR_TIME);
    ptime = ptime - (cnt.hour * HOUR_TIME);
    cnt.min = Math.floor(ptime / MIN_TIME);
    ptime = ptime - (cnt.min * MIN_TIME);
    cnt.sec = Math.floor(ptime / SEC_TIME);
    return cnt;
  };
  that.format_time = function(cnt) {
    return { day: cnt.day.toString(),
             hour: cnt.hour.toString(),
             min: that.format0(cnt.min, 2),
             sec: that.format0(cnt.sec, 2) };
  };
  that.countdown = function(ptime, nodes) {
    var cnt = that.format_time(that.get_datetime(ptime));
    for (var node in nodes) {
      if (nodes.hasOwnProperty(node)) {
        nodes[node].innerHTML = that.num_to_str(cnt[node], that.timetext);
      }
    }
  };
  that.print_after_text = function(node, text) {
    if (node) {
      node.innerHTML = text;
    }
  };
  that.get_nodes = function(nodeid) {
    var nodes = {};
    for (var name in nodeid) {
      if (nodeid.hasOwnProperty(name)) {
        var node = document.getElementById(nodeid[name]);
        if (node) { nodes[name] = node; }
      }
    }
    return nodes;
  };
  that.update = function() {
    var ptime = that.xtime - new Date().getTime();
    if (ptime < 0) {
      window.clearInterval(that.timerid);
      that.print_after_text(that.rootnode, params.html.after);
    } else {
      that.countdown(ptime, that.nodes);
    }
  };
  that.run = function() {
    if (!that.rootnode) {
      return;
    }
    that.rootnode.innerHTML = params.html.before;
    that.nodes = that.get_nodes(params.nodeid);
    that.timetext = params.html.timetext;
    that.timerid = window.setInterval(that.update, 500);
  };

  var period = params.period;
  that.xtime = new Date(period[0], period[1]-1, period[2],
                        period[3], period[4], 0).getTime();
  that.rootnode = document.getElementById(params.html.root);
  
  return that;
};
/**
 * 営業日カレンダー
 * @param {Array} params カレンダーの作成に必要な情報
 *                         //定休日
 *                       { holidays: [{year:2011, month:1: day:10},
 *                                   {month:1, day:1},
 *                                   {dayOfWeek:0},],
 *                         //定休日の例外
 *                         exceptions: [{year:2011, month:4: day:1}],
 *                         //HTMLエンティティのID
 *                         html: { prevmonth:'prevmonth', //先月リンク
 *                                 nextmonth:'nextmonth', //翌月リンク
 *                                 presentmonth:'presentmonth', //当日リンク
 *                                 year:'year', //年表示
 *                                 month:'month', //月表示
 *                                 days:'days', //日付を表示するtbodyタグ
 *                       },
 */
RAKUSCRIPT.WorkingDayCalendar = function(params) {
  var that = {};
  that.calendars = [0,31,28,31,30,31,30,31,31,30,31,30,31];
  that.holidays = params.holidays; //定休日条件
  that.exceptions = params.exceptions; //定休日の例外

  /**
   * 指定した日付が休日の時はtrueを返す
   * @param {Array} today 日付
   *                {year:2010, month:2: day:3, dayOfWeek:4}
   * @param {Array} holiday 休日の条件
   *                {year:2010, month:2, day: 3}
   *                {month:2, day: 3}
   *                {dayOfWeek: 1}
   * @returns {Boolean} 休日の時はtrue
   */
  that.is_holiday = function(today, holiday) {
    for (var key in holiday) {
      if (holiday[key] !== today[key]) {
        return false;
      }
    }
    return true;
  };
  /**
   * 指定した日付がいずれからの休日条件を満たすときはtrue
   * @param {Array} today 日付
   *                {year:2010, month:2: day:3, dayOfWeek:4}
   * @param {Array} holidays 休日条件の配列
   *                [{year:2010, month:2, day: 3},
   *                 {month:2, day: 3}
   *                 {dayOfWeek: 1}]
   * @param {Array} exceptions 定休日の例外の配列
   *                [{year:2010, month:4, day: 3},]
   * @returns {Boolean} 休日の時はtrue
   */
  that.is_in_holiday = function(today, holidays, exceptions) {
    for (var i = 0; i < exceptions.length; ++i) {
      if (that.is_holiday(today, exceptions[i])) {
        return false;
      }
    }
    for (var i = 0; i < holidays.length; ++i) {
      if (that.is_holiday(today, holidays[i])) {
        return true;
      }
    }
    return false;
  };
  /**
   * 指定した日付の曜日を取得する
   * @param {Number} year 年
   * @param {Number} month 月
   * @param {Number} day 日
   * @returns {Number} 日付の曜日を示す値。0.日曜日〜6.土曜日
   */
  that.get_day_of_week = function(year, month, day) {
    return new Date(year, month-1, day).getDay();
  };
  /**
   * 指定した年が閏年のときはtrue
   */
  that.is_leep_year = function(year) {
    return (year % 4 === 0);
  };
  /**
   * 指定したタグIDのHTMLエレメントの取得する
   * @param {Array} nodeid タグIDの配列
   * @returns {Array} タグIDのHTMLエレメントの配列
   */
  that.get_nodes = function(nodeid) {
    var nodes = {};
    for (var name in nodeid) {
      if (nodeid.hasOwnProperty(name)) {
        var node = document.getElementById(nodeid[name]);
        if (node) { nodes[name] = node; }
      }
    }
    return nodes;
  };
  /**
   * 指定月の日付の配列を返す
   * @param {Number} year 年
   * @param {Number} month 月
   */
  that.get_cal = function(year, month) {
    var weeks = [];
    var dayOfWeek = that.get_day_of_week(year, month, 1);
    var lastday = that.calendars[month];
    for (var day = (dayOfWeek * -1 + 1); day <= lastday; ) {
      var week = [];
      for (var j = 0; j < 7; ++j) {
        if (day < 1 || lastday < day) { week.push(0); }
        else { week.push(day); }
        ++day;
      }
      weeks.push(week);
    }
    return weeks;
  };
  
  /**
   * 指定年月の曜日情報を取得する
   * @param {Number} year 年
   * @param {Number} month 月
   * @param {Date} today 処理日の年月日。
   * @param {Array} holidays 休日条件の配列
   *                [{year:2010, month:2, day: 3},
   *                 {month:2, day: 3}
   *                 {dayOfWeek: 1}]
   * @param {Array} exceptions 定休日の例外の配列
   *                [{year:2010, month:4, day: 3},]
   * @returns {String} tbodyタグ内部のtrエレメント。<tr><td>…</td></tr><tr>…
   */
  that.get_days = function(year, month, today, holidays, exceptions) {
    //TODO:日付の描画
    var days = [];
    var result = [];
    var weeks = that.get_cal(year, month);
    var today_year = today.getFullYear();
    var today_month = today.getMonth() + 1;
    var today_date = today.getDate();
    for (var week = 0; week < weeks.length; ++week) {
      var tr = document.createElement('tr');
      result.push(tr);
      for (var i = 0; i < weeks[week].length; ++i) {
        var day = weeks[week][i];
        var td = document.createElement('td');
        tr.appendChild(td);
        if (day == 0) {
          td.appendChild(document.createTextNode(' '));
          continue;
        }
        var cls = [];
        if (today_year === year &&
            today_month === month &&
            today_date === day) {
          cls.push('today');
        } 
        if (that.is_in_holiday({year:year, month:month, day:day, dayOfWeek:i},
                                holidays, exceptions)) {
          cls.push('holiday');
        }
        if (cls.length > 0) {
          td.className = cls.join(' ');
        }
        td.appendChild(document.createTextNode(day));
      }
    }
    return result;
  };
  /**
   * カレンダーを描画する
   * @param {Number} year 年
   * @param {Number} month 月
   */
  that.write_cal = function(year, month) {
    that.nodes['year'].innerHTML = year;
    that.nodes['month'].innerHTML = month;
    //先月リンク
    that.nodes['prevmonth'].onclick = function() {
      var date = new Date(year, month - 2);
      that.write_cal(date.getFullYear(), date.getMonth() + 1);
    };
    //翌月リンク
    that.nodes['nextmonth'].onclick = function() {
      var date = new Date(year, month);
      that.write_cal(date.getFullYear(), date.getMonth() + 1);
    };
    //日付
    var daysnode = that.nodes['days'];
    while (daysnode.hasChildNodes()) {
      daysnode.removeChild(daysnode.firstChild);
    }
    var days = that.get_days(year, month, new Date(), that.holidays, that.exceptions);
    for (var i = 0; i < days.length; ++i) {
      that.nodes['days'].appendChild(days[i]);
    }
  };
  that.run = function() {
    that.nodes = that.get_nodes(params.html);
    var today = new Date();
    that.nodes['presentmonth'].onclick = function() { 
      that.write_cal(today.getFullYear(), today.getMonth() + 1);
    };
    that.write_cal(today.getFullYear(), today.getMonth() + 1);
  };
  return that;
};
//互換性のための関数
function CountDownTimer(params) {
  RAKUSCRIPT.CountDownTimer(params).run();
}

