// ----------------------------------------------------------------------------
// advance_date.js
// Advance Date
// Varsion 4.1
// 拡張 Date オブジェクト
// Copyright (C) 2003-2005 Taku Watabe
// Time-stamp: <2007-09-09T00:10:07+09:00>
// ----------------------------------------------------------------------------
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// ----------------------------------------------------------------------------
// GNU 一般公衆利用許諾契約書の複製物は http://eof.my-sv.net/data/gpl に存在し
// ます。
// ----------------------------------------------------------------------------
// 意見・バグ報告は taku.eof@gmail.com まで。
// Subject に必ず「Advance Date」という文字列を含めてください。
// 存在しない場合は単にメールを無視します。
// ----------------------------------------------------------------------------

// ----------------------------------------------------------------------------
// Number
// ----------------------------------------------------------------------------
//
// public static
//
// digit 長未満の数値先頭に plusStr 文字を不足分だけ付与
Number.prototype.toPreString = function(digit, plusStr) {
  var value = this.toString();
  var sub = digit - value.length;

  if (plusStr == undefined) { plusStr = "0"; }
  while(sub--) {
    value = plusStr + value;
  }
  return value;
};


// ----------------------------------------------------------------------------
// Date
// ----------------------------------------------------------------------------
//
// private static
//
Date.prototype._defaultInterval = 1000;
Date.prototype._defaultMinimumInterval = 1;

// getter ---------------------------------------------------------------------
// 整形済(Preformatted : Pre)時刻取得クロージャ生成関数
Date.prototype._getPreTimeClosure = function(type, digit) {
  var fullType = "get" + type;

  return function() {
    return this[fullType]().toPreString(digit);
  }
};

Date.prototype.setFormat = function() {
  var arr  = this._format[type].split("'");
  var narr = arr.length;

  // 細分化 format 文字列解析
  // 奇数要素に存在するセパレータ文字列はスキップ
  for (var i = 0; i < narr; i += 2) {
    if (arr[i] == '') {
      continue;
    }
    // セパレータ挿入 (奇数要素)
    if (i+2 < narr) {
      functionStr += "+\""+arr[i+1]+"\"+";
    }
  }
};


//
// private non-static
//
Date.prototype.insertVariable = function() {
  // 拡張更新関数
  this._eventFunc = null;
  this._activeId = null;

  this._interval = this._defaultInterval;
  this._minimumInterval = this._defaultMinimumInterval;

  // Count UP / DOWN 変数
  this._count = {down : 0, up : 0, end : 0, start : 0};
};

Date.prototype.insertVariable();
delete Date.prototype.insertVariable;


//
// public static
//

// getter ---------------------------------------------------------------------
// 整形済(Preformatted : Pre)時刻
Date.prototype.getPreFullYear =
  Date.prototype._getPreTimeClosure("FullYear", 2);
Date.prototype.getPreMonth =
  Date.prototype._getPreTimeClosure("Month", 2);
Date.prototype.getPreDate =
  Date.prototype._getPreTimeClosure("Date", 2);
Date.prototype.getPreHours =
  Date.prototype._getPreTimeClosure("Hours", 2);
Date.prototype.getPreMinutes =
  Date.prototype._getPreTimeClosure("Minutes", 2);
Date.prototype.getPreSeconds =
  Date.prototype._getPreTimeClosure("Seconds", 2);
Date.prototype.getPreMilliseconds =
  Date.prototype._getPreTimeClosure("Milliseconds", 3);

// 更新間隔返却
Date.prototype.getActiveInterval = function() {
  return this._interval;
};

// 内部時間動的更新状態確認
// true : 停止、false : 動作
Date.prototype.getActiveCondition = function() {
  return this._activeId == null;
};

// 内部時間動的更新間隔返還
Date.prototype.getActiveInterval = function() {
  return this._interval;
};


// setter ---------------------------------------------------------------------
// 拡張更新関数定義
Date.prototype.setEvent = function(eventFunc) {
  if (typeof eventFunc != 'function') return;
  this._eventFunc = eventFunc;
};

// 更新間隔設定
Date.prototype.setInterval = function(i) {
  // 小数点以下 & 最低動作間隔未満は認めない
  if (isNaN(time = parseInt(i) ) || i < this._minimumInterval) {
    return;
  }
  this._interval = i;
};


// method ---------------------------------------------------------------------
// 明示的内部時間更新
Date.prototype.renew = function() {
  var t = (new Date()).getTime();
  // 更新 & 更新時間基準誤差修正
  this.setTime(t - t % this._interval);
  // 拡張更新関数実行
  if (this._eventFunc != null) { this._eventFunc(this); }
};

// 内部時間動的更新開始
Date.prototype.active = function(time) {
  // 動作中に更新インターバルを変える目的で呼び出した場合、
  // 停止しないと二つのプロセスが同時実行されている状態になる。
  // だからとりえあえず停止（状態判別は stop メソッドが行う）
  this.stop();
  // non-static なプロパティでないと
  // 二つ以上の Date インスタンスが存在する場合に競合してしまう
  // time の正当性は setInterval メソッドが判別
  this.setInterval(time);
  // active 動作用関数
  var obj = this;
  function activeEvent() {
    obj.renew();
    // setInterval では Gecko で競合みたいなものが発生
    obj._activeId = setTimeout(activeEvent, obj._interval);
  } activeEvent();
};

// 内部時間動的更新停止
Date.prototype.stop = function() {
  clearTimeout(this._activeId);
  this._activeId = null;
  this.renew();
};


//
// Count Timer メソッドグループ
//
Date.prototype.getCountUpTime = function() {
  return this.getTime() - this._count.start;
};

Date.prototype.getCountDownTime = function() {
  return this._count.end - this.getTime();
};

// 直接プロパティを操作しない & させないように
// 終了時刻取得
Date.prototype.getEndDate = function() {
  return new Date(this._count.end);
};

// 開始時刻取得
Date.prototype.getStartDate = function() {
  return new Date(this._count.start);
};

// 終了時刻セット
Date.prototype.setEndDate = function(set) {
  if (set instanceof Date) { this._count.end = set.getTime(); }
};

// 開始時刻セット
Date.prototype.setStartDate = function(set) {
  if (set instanceof Date) { this._count.start = set.getTime(); }
};

