/*
Copyright (c) 2008, KIMI. All rights reserved.
Code licensed under the BSD License:
http://ocal.jp/javascripts/bsd-license.txt

部分的にYUIのコードを含みます
Copyright (c) 2006, Yahoo! Inc. All rights reserved.
Code licensed under the BSD License:
http://developer.yahoo.net/yui/license.txt
*/

/**
 * エスケープ
 * @return {String} [&amp; &lt; &gt; &quot;] ≫ [&amp;amp; &amp;lt; &amp;gt; &amp;quot;]
 */
String.prototype.E = function(){
  return this.replace(/\&/g, '&amp;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;').replace(/\"/g, '&quot;');
};
/**
 * 日にちを進める(マイナスなら戻す)
 * @param {Number} i 日数
 */
Date.prototype.add = function(i){
  if(i) this.setTime(this.getTime() + (1000*60*60*24)*i);
};
/**
 * 日本語で曜日を返す
 * @return {String} 0:日, ... ,6:土
 */
Date.prototype.getLocalDay = function(){
  switch(this.getDay()){
  case 0: return '日'; break;
  case 1: return '月'; break;
  case 2: return '火'; break;
  case 3: return '水'; break;
  case 4: return '木'; break;
  case 5: return '金'; break;
  case 6: return '土'; break;
  }
  return null;
};
/**
 * 英語の曜日を先頭2文字で返す
 * @return {String} 0:SU, ... , 6:SA
 */
Date.prototype.getEnDay = function(){
  switch(this.getDay()){
  case 0: return 'SU'; break;
  case 1: return 'MO'; break;
  case 2: return 'TU'; break;
  case 3: return 'WE'; break;
  case 4: return 'TH'; break;
  case 5: return 'FR'; break;
  case 6: return 'SA'; break;
  }
  return null;
};
/**
 * @param {String} s 区切り文字(デフォルト '-')
 * @return {String} 年月
 */
Date.prototype.toYYYYMM = function(s){
  if(s==undefined)s='-';
  return this.getFullYear()+s+(this.getMonth()<9?"0"+(this.getMonth()+1):(this.getMonth()+1));
};
/**
 * @param {String} s 区切り文字(デフォルト '-')
 * @return {String} 月日
 */
Date.prototype.toMMDD = function(s){
  if(s==undefined)s='-';
  return (this.getMonth()<9?"0"+(this.getMonth()+1):(this.getMonth()+1))+s+(this.getDate()<10?"0"+this.getDate():this.getDate());
};
/**
 * @param {String} s 区切り文字(デフォルト '-')
 * @return {String} 時分
 */
Date.prototype.toHHMM = function(s){
  if(s==undefined)s=':';
  return (this.getHours()<10?"0"+this.getHours():this.getHours())+s+(this.getMinutes()<10?"0"+this.getMinutes():this.getMinutes());
};
/**
 * @param {String} s 区切り文字(デフォルト '-')
 * @return {String} 年月日
 */
Date.prototype.toYYYYMMDD = function(s){
  if(s==undefined)s='-';
  return this.getFullYear()+s+(this.getMonth()<9?"0"+(this.getMonth()+1):(this.getMonth()+1))+s+(this.getDate()<10?"0"+this.getDate():this.getDate());
};
/**
 * @param {Date} d 比較するDate
 * @return {Boolean} 引数より昔
 */
Date.prototype.before = function(d){
  return (this.getTime() < d.getTime());
};
/**
 * @param {Date} d 比較するDate
 * @return {Boolean} 引数より昔 or 同じ
 */
Date.prototype.beforeEquals = function(d){
  return (this.getTime() <= d.getTime());
};
/**
 * @param {Date} d 比較するDate
 * @return {Boolean} 引数より未来
 */
Date.prototype.after = function(d){
  return (this.getTime() > d.getTime());
};
/**
 * @param {Date} d 比較するDate
 * @return {Boolean} 引数より未来 or 同じ
 */
Date.prototype.afterEquals = function(d){
  return (this.getTime() >= d.getTime());
};
/**
 * afterEquals()な点に注意
 * @param {Date} from 比較するDate
 * @param {Date} to 比較するDate
 * @return {Boolean} afterEquals() かつ before()
 */
Date.prototype.between = function(from, to){
  return (this.afterEquals(from) && this.before(to));
};
/**
 * @return {Boolean} 閏年？
 */
Date.prototype.isLeapyear = function(){
  return (this.getFullYear()%4==0&&(this.getFullYear()%100!=0||this.getFullYear()%400==0));
};
/**
 * eom (End Of Month)
 * @return {Number} 最終日
 */
Date.prototype.eom = function(){//end of the month
  var a=[31,28,31,30,31,30,31,31,30,31,30,31];
  if(this.isLeapyear)a[1]++;
  return a[this.getMonth()];
};
/**
 * 週初めに戻す
 * TODO: 週の初めが日曜日固定なのでなんとかしたい
 */
Date.prototype.weekStart = function(){
  if(this.getDay() == 0)return;
  this.add(-this.getDay());
};
/**
 * @return {Number} 週数
 */
Date.prototype.weekNumber = function(){
  var d = Date.paddingZeroTime(this);
  var nearestThurs = new Date(d.getTime() + (4*1000*60*60*24) - (d.getDay() * 1000*60*60*24));
  var jan1 = new Date(nearestThurs.getFullYear(),0,1);
  var time = ((nearestThurs.getTime() - jan1.getTime()) / (1000*60*60*24)) - 1;
  return Math.ceil(time/7);
};
/**
 * 来月に進める
 * 1/31の来月は2/28(もしくは2/29)
 */
Date.prototype.nextMonth = function(){
  var d = this.getDate();
  this.setDate(1);
  var m = this.getMonth()+1;
  if(m==12){
    this.setFullYear(this.getFullYear() + 1);
    this.setMonth(0);
  }else{
    this.setMonth(m);
  }
  if(d>this.eom())d=this.eom();
  this.setDate(d);
};
/**
 * 先月に戻す
 * 3/31の先月は2/28(もしくは2/29)
 */
Date.prototype.lastMonth = function(){
  var d = this.getDate();
  this.setDate(1);
  var m = this.getMonth()-1;
  if(m==-1){
    this.setFullYear(this.getFullYear() - 1);
    this.setMonth(11);
  }else{
    this.setMonth(m);
  }
  if(d>this.eom())d=this.eom();
  this.setDate(d);
};
/**
 * @return {Number} 第N,X曜日 のN
 */
Date.prototype.getDayNumber = function() {
  var tmpDate=new Date(this.getTime());
  for(var i=1; i<6; i++){
    tmpDate.add(-7);
    if(tmpDate.getMonth() != this.getMonth()){
      return i;
    }
  }
};
/**
 * @return {Array} map do |i| i.to_i end
 */
Array.prototype.to_i=function(){
  var len = this.length, ret = new Array(len);
  for(var i=0; i<len; i++)
    ret[i] = isNaN(this[i]) ? this[i] : parseInt(this[i], 10);
  return ret;
};

//
// static method
//

/**
 * 減算
 * @static
 * @param {Date} s 開始日
 * @param {Date} e 終了日
 * @param {Number} type 計算単位 1:日, 2:週, 3月, 4:年
 * @return 
 */
Date.sub = function(s, e, type){
  switch(type){
  case 1://DAY
    var sDate = Date.paddingZeroTime(s);
    var eDate = Date.paddingZeroTime(e);
    return (eDate.getTime() - sDate.getTime())/(1000*60*60*24); break;
  case 2://WEEK
    var sDate = Date.paddingZeroTime(s);
    var eDate = Date.paddingZeroTime(e);
    sDate.weekStart(); eDate.weekStart();
    return Math.floor(eDate.getTime() - sDate.getTime())/(1000*60*60*24)/7; break;
  case 3://MONTH
    return e.getMonth() - s.getMonth(); break;
  case 4://YEAR
    return e.getFullYear() - s.getFullYear(); break;
  }
  return null;
};
/**
 * @static
 * @param {Date} s 調べたいDate
 * @param {Date} e 調べたいDate
 * @return 両方とも0時0分か？
 */
Date.isZeroHourZeroTime = function(s, e){
  return (s.getHours() == 0 && s.getMinutes() == 0 && s.getHours() == e.getHours() && s.getMinutes() == e.getMinutes());
};
/**
 * @static
 * @param {Date} d 0時0分0秒にしたい日付
 * @return {Date} 新しいオブジェクトを返す点に注意
 */
Date.paddingZeroTime = function(d){
  if(d)return new Date(d.getFullYear(), d.getMonth(), d.getDate());
  var ret=new Date();
  ret.setHours(0);ret.setMinutes(0);ret.setSeconds(0);ret.setMilliseconds(0)
  return ret;
};
/**
 * @static
 * @param {String} s SU, ... ,SA
 * @return {Number} 0, ... ,6
 */
Date.en2day=function(s){
  switch(s){
  case 'SU': return 0; break;
  case 'MO': return 1; break;
  case 'TU': return 2; break;
  case 'WE': return 3; break;
  case 'TH': return 4; break;
  case 'FR': return 5; break;
  case 'SA': return 6; break;
  }
  return null;
};
/**
 * @static
 * @param {String} s SU, ... ,SA
 * @return {String} 日, ..., 土
 */
Date.en2localday=function(s){
  switch(s){
  case 'SU': return '日'; break;
  case 'MO': return '月'; break;
  case 'TU': return '火'; break;
  case 'WE': return '水'; break;
  case 'TH': return '木'; break;
  case 'FR': return '金'; break;
  case 'SA': return '土'; break;
  }
  return null;
};
