// CalendarDateSelect version 1.6.0 - a small prototype based date picker
// Questions, comments, bugs? - email the Author - Tim Harper <"timseeharper@gmail.seeom".gsub("see", "c")> 
if (typeof Prototype == 'undefined')
  alert("ご使用のブラウザーでは利用できません。");

Element.addMethods({
  purgeChildren: function(element) { $A(element.childNodes).each(function(e){$(e).remove();}); },
  build: function(element, type, options, style) {
    newElement = Element.build(type, options, style);
    element.appendChild(newElement);
    return newElement;
  }
});

Element.build = function(type, options, style)
{
  e = $(document.createElement(type));
  $H(options).each(function(pair) { eval("e." + pair.key + " = pair.value" ); });
  if (style) 
    $H(style).each(function(pair) { eval("e.style." + pair.key + " = pair.value" ); });
  return e;
};
nil=null;

Date.one_day = 24*60*60*1000;
Date.weekdays = $w("日 月 火 水 木 金 土");
Date.months = $w("1 2 3 4 5 6 7 8 9 10 11 12" );
Date.padded2 = function(hour) { padded2 = hour.toString(); if (parseInt(hour) < 10) padded2="0" + padded2; return padded2; }
Date.prototype.getPaddedMinutes = function() { return Date.padded2(this.getMinutes()); }
Date.prototype.getAMPMHour = function() { hour=this.getHours(); return hour;}
Date.prototype.stripTime = function() { return new Date(this.getFullYear(), this.getMonth(), this.getDate());};
Date.prototype.daysDistance = function(compare_date) { return Math.round((compare_date - this) / Date.one_day); };
Date.prototype.toFormattedString = function(include_time){
//フッター
  str = this.getFullYear() + "年 " + Date.months[this.getMonth()] + "月 " + this.getDate() + "日";
  if (include_time) { hour=this.getHours(); str += " " + this.getAMPMHour() + ":" + this.getPaddedMinutes() }
  return str;
}
Date.parseFormattedString = function(string) { return new Date(string);}
window.f_height = function() { return( [window.innerHeight ? window.innerHeight : null, document.documentElement ? document.documentElement.clientHeight : null, document.body ? document.body.clientHeight : null].select(function(x){return x>0}).first()||0); }
window.f_scrollTop = function() { return ([window.pageYOffset ? window.pageYOffset : null, document.documentElement ? document.documentElement.scrollTop : null, document.body ? document.body.scrollTop : null].select(function(x){return x>0}).first()||0 ); }

_translations = {
  "OK": "OK",
  "Now": "Now",
  "Today": "Today"
}
CalendarDateSelect = Class.create();
CalendarDateSelect.prototype = {
  initialize: function(target_element, options) {
    // initialize the date control
    this.options = $H({
      embedded: false,
      time: false,
      buttons: true,
      year_range: 10,
      calendar_div: nil,
      close_on_click: nil,
      minute_interval: 5,
      onchange: nil
    }).merge(options || {});
    
    this.target_element = $(target_element); // make sure it's an element, not a string
    this.selection_made = $F(this.target_element)!="";
    
    if (this.target_element.calendar_date_select)
    {
      this.target_element.calendar_date_select.close();
      return false;
    }
    this.target_element.calendar_date_select = this;
    
    this.calendar_div = $(this.options['calendar_div']);
    if (!this.target_element) { alert("Target element " + target_element + " not found!"); return false;}
    
    this.parseDate();
    
    // by default, stick it by the target element (if embedded, that's where we'll want it to show up)
    if (this.calendar_div == nil) { this.calendar_div = $( this.options.embedded ? this.target_element.parentNode : document.body ).build('div'); }
    if (!this.options.embedded) {
      this.calendar_div.setStyle( { position:"absolute", visibility: "hidden" } )
      this.positionCalendarDiv();
    }
    
    this.calendar_div.addClassName("calendar_date_select");
    
    if (this.options["embedded"]) this.options["close_on_click"]=false;
    // logic for close on click
    if (this.options['close_on_click']===nil )
    {
      if (this.options['time'])
        this.options["close_on_click"] = false;
      else
        this.options['close_on_click'] = true;
    }
    
    // set the click handler to check if a user has clicked away from the document
    if(!this.options["embedded"]) Event.observe(document.body, "mousedown", this.bodyClick_handler=this.bodyClick.bindAsEventListener(this));
    
    this.initFrame();
    
    if(!this.options["embedded"]) { this.positionCalendarDiv(true) }//.bindAsEventListener(this), 1);
  },
  positionCalendarDiv: function(post_painted) {
    above=false;
    c_pos = Position.cumulativeOffset(this.target_element); c_left = c_pos[0]; c_top = c_pos[1]; c_dim = this.calendar_div.getDimensions(); c_height = c_dim.height; c_width = c_dim.width; 
    w_top = window.f_scrollTop(); w_height = window.f_height();
    e_dim = Position.cumulativeOffset(this.target_element); e_top = e_dim[1]; e_left = e_dim[0];
    
    if ( (post_painted) && (( c_top + c_height ) > (w_top + w_height)) && ( c_top - c_height > w_top )) above=true;
    left_px = e_left.toString() + "px";
    top_px = (above ? (e_top - c_height ) : ( e_top + this.target_element.getDimensions().height )).toString() + "px";
    
    this.calendar_div.style.left = left_px;  this.calendar_div.style.top = top_px;
    
    // draw an iframe behind the calendar -- ugly hack
    if (post_painted)
    {
      this.iframe = $(document.body).build("iframe", { frameBorder: "0", src:"javascript:false" }, { position:"absolute", left: left_px, top: top_px, height: c_height.toString()+"px", width: c_width.toString()+"px", border: "0px"})
      this.calendar_div.setStyle({visibility:""});
    }
  },
  monthBtn: function() {
    this.month_select_button.value = " " + Date.months[this.date.getMonth()] + "月 ";
  },
// フレーム 作成
  initFrame: function() {
    that=this;
    // create the divs
    $w("header body time buttons").each(function(name) {
      eval(name + "_div = that." + name + "_div = that.calendar_div.build('div', { className: 'cds_"+name+"' }, { clear: 'left'} ); ");
    });
    
    this.initButtonsDiv();
    birth_flg = this.options["year_range"];
    this.next_month_button = header_div.build("input", { type: "button", value : ">", className: "next" });
    this.prev_month_button = header_div.build("input", { type: "button", value : "<", className: "prev" });
    this.year_select_button = header_div.build("input", { type: "button", value : " " + this.date.getFullYear() + "年 ", className: "year"});
    header_div.build("span", { className: "space", innerHTML: "　" });
    this.month_select_button = header_div.build("input", { type: "button", size: "100" ,value : " " + Date.months[this.date.getMonth()] + "月 ", className: "month"});
    
    Event.observe(this.prev_month_button, 
        'mousedown', 
        function () { this.navMonth(this.date.getMonth() - 1 ), 
                      this.year_select_button.value = " " + this.date.getFullYear() + " 年",
                      this.monthBtn() }.bindAsEventListener(this));
    Event.observe(this.next_month_button, 
        'mousedown', 
        function () { this.navMonth(this.date.getMonth() + 1 ), 
                      this.year_select_button.value = " " + this.date.getFullYear() + " 年",
                      this.monthBtn() }.bindAsEventListener(this));
    Event.observe(this.year_select_button, 'click', (
        function () { this.hideAll(),
                      birth_flg == "birthday" ? Element.show(age_table) : Element.show(year_table)
                    }).bindAsEventListener(this));
    Event.observe(this.month_select_button, 'click', (
        function () { this.hideAll(),
                      Element.show(month_table)
                    }).bindAsEventListener(this));
                    
    this.initDayTable();Element.hide(days_table);
    this.initMonthTable();Element.hide(month_table);
    this.initAgeTable();
    this.initYearTable();Element.hide(year_table);
    this.refresh();
  },
  hideAll: function()
  {
    Element.hide(days_table);
    Element.hide(month_table);
    Element.hide(year_table);
    Element.hide(age_table);
  },
// 年代 テーブル作成
  initAgeTable: function()
  {
    d = new Date();
    nowYear = d.getFullYear()/10;
    nowYear = Math.floor(nowYear)*10 -10;
    //body_div.build("div", { className: "comment", width: "100%", innerHTML: "誕生日の年代を選択してください"} );
    age_table = body_div.build("table", { cellPadding: "0px", cellSpacing: "0px", width: "100%" }, {className: "age_table"}).build("tbody");
    for(i=0; i<8; i++)
    {
      if(i==0){
        age_table.build("tr", {}).build("th", { colSpan: "4", width: "100%"})
        .build("div", { className: "comment", width: "100%", innerHTML: "誕生日の年代を選択してください"} );
        
      }
        if(i %4==0) age_row = age_table.build("tr", {className: "age_list"});
        age_row.build("td",{
          calendar_date_select: this,
          innerHTML: nowYear - i * 10 + " 年代",
          onmouseover: function () { this.addClassName("hover"); },
          onmouseout: function () { this.removeClassName("hover"); },
          onclick: function() {
          yearStr = this.innerHTML.replace(" 年代","");
          this.calendar_date_select.navYear(yearStr);
          this.calendar_date_select.year_select_button.value = " " + this.calendar_date_select.date.getFullYear() + " 年";
          Element.hide(age_table);
          this.calendar_date_select.initYearTable();
          Element.show(year_table);
         }});
    }
  },
// 年 テーブル作成
  initYearTable: function()
  {
    range=this.options["year_range"];
    nowYear = this.date.getFullYear();

    year_table = body_div.build("table", { cellPadding: "0px", cellSpacing: "0px", width: "100%" }, {className: "year_table"}).build("tbody");
    for(i=0; i<10; i++)
    {
      if(i==0){
        year_table.build("tr", {}).build("th", { colSpan: "5", width: "100%"})
        .build("div", { className: "comment", width: "100%", innerHTML: "誕生日の年を選択してください"} );
      }
        if(i %5==0) year_row = year_table.build("tr", {className: "year_list"});
        year_row.build("td",{
          calendar_date_select: this,
          innerHTML: nowYear + i,
          onmouseover: function () { this.addClassName("hover"); },
          onmouseout: function () { this.removeClassName("hover"); },
          onclick: function() {
          yearStr = this.innerHTML.replace("","");
          this.calendar_date_select.navYear(yearStr);
          this.calendar_date_select.year_select_button.value = " " + this.calendar_date_select.date.getFullYear() + " 年";
          Element.hide(year_table);
          this.calendar_date_select.initMonthTable();
          Element.show(month_table);
         }});
    }
  },
// 月 テーブル作成
  initMonthTable: function()
  {
    month_table = body_div.build("table", { cellPadding: "0px", cellSpacing: "0px", width: "100%" }).build("tbody");
    for(month_count=0;month_count<=11;month_count++)
    {
      if(month_count==0){
        month_table.build("tr", {}).build("th", { colSpan: "3", width: "100%"})
        .build("div", { className: "comment", width: "100%", innerHTML: "誕生日の月を選択してください"} );
      }
      
        if(month_count %3==0) month_row = month_table.build("tr", {className: "month_list"});
        month_row.build("td",{
          calendar_date_select: this,
          innerHTML: (month_count + 1) + "月",
          onmouseover: function () { this.addClassName("hover"); },
          onmouseout: function () { this.removeClassName("hover"); },
          onclick: function() {
          monthStr = this.innerHTML.replace("月","");
          this.calendar_date_select.navMonth(monthStr - 1);
          this.calendar_date_select.monthBtn();
          Element.hide(month_table);
          Element.show(days_table);
         }});
    }
  },
// 日付 テーブル作成
  initDayTable: function()
  {
    this.calendar_day_grid = [];
    days_table = body_div.build("table", { cellPadding: "0px", cellSpacing: "0px", width: "100%" }).build("tbody");

    // make the weekdays!
    weekdays_row = days_table.build("tr", {className: "weekdays"});
    Date.weekdays.each( function(weekday) { 
      weekdays_row.build("td", {innerHTML: weekday});
    });
    
    for(cell_index=0; cell_index<42; cell_index++)
    {
      weekday=cell_index%7;
      if ( cell_index %7==0 ) days_row = days_table.build("tr", {className: "days"});
      (this.calendar_day_grid[cell_index] = days_row.build("td", {
          calendar_date_select: this,
          onmouseover: function () { this.calendar_date_select.dayHover(this); },
          onmouseout: function () { this.calendar_date_select.dayHoverOut(this) },
          onclick: function() { this.calendar_date_select.updateSelectedDate(this);
                                if (this.calendar_date_select.options["time"])
                                this.calendar_date_select.close();
                              },
          className: (weekday==0) || (weekday==6) ? " weekend" : "" //clear the class
        },
        { cursor: "pointer" }
      )).build("div");
      this.calendar_day_grid[cell_index];
    }
  },
  initButtonsDiv: function()
  {
    buttons_div = this.buttons_div;
    if (!this.options["buttons"]) { Element.remove(buttons_div); return false; };
    
    b=buttons_div.build("input", {
      onclick: this.today.bindAsEventListener(this), 
      type: "button"
    });
    b.value = (this.options["time"] ? _translations["Now"] : _translations["Today"] );
    
    if (this.allowCloseButtons()) {
      b=buttons_div.build("input", {
        onclick: this.close.bindAsEventListener(this),
        type: "button"
      });
      b.value = _translations["OK"];
    }
  },
  allowCloseButtons: function() { return ( !this.options["embedded"] && this.options["time"]); },
  dateString: function() {
    return (this.selection_made) ? this.selected_date.toFormattedString(this.options['time']) : "&nbsp;";
  },
  navMonth: function(month) {
    prev_day = this.date.getDate();
    this.date.setMonth(month);
    
    this.refresh();
  },
  navYear: function(year) {
    this.date.setYear(year);
    this.refresh();
  },
  refresh: function ()
  {
    this.beginning_date = new Date(this.date).stripTime();
    this.beginning_date.setDate(1);
    pre_days = this.beginning_date.getDay() // draw some days before the fact
    if (pre_days < 3) pre_days+=7;
    this.beginning_date.setDate(1 - pre_days);
    
    iterator = new Date(this.beginning_date);
    
    today = new Date().stripTime();
    this_month = this.date.getMonth();
    for (cell_index=0;cell_index<42; cell_index++)
    {

      day = iterator.getDate(); month = iterator.getMonth();
      cell = this.calendar_day_grid[cell_index];
      Element.remove(cell.childNodes[0]); div = cell.build("div", {innerHTML:day});
      if (month!=this_month) div.className = "other";
      cell.day=day; cell.month = month; cell.year = iterator.getFullYear();
      iterator.setDate( day + 1);
    }
    
    if (this.today_cell) this.today_cell.removeClassName("today");
    
    if ( $R(0,42).include(days_until = this.beginning_date.daysDistance(today)) ) {
      this.today_cell = this.calendar_day_grid[days_until];
      this.today_cell.addClassName("today");
    }
    this.setSelectedClass();
    //this.updateFooter();
  },
  dayHover: function(element) {
    element.addClassName("hover");
    hover_date = new Date(this.selected_date);
    hover_date.setYear(element.year); hover_date.setMonth(element.month); hover_date.setDate(element.day);
    //this.updateFooter(hover_date.toFormattedString(this.options['time']));
    //this.target_element.value = hover_date.toFormattedString(this.options['time']);
  },
  dayHoverOut: function(element) { 
    element.removeClassName("hover");
    //this.updateFooter(); 
  },
  setSelectedClass: function() {
    if (!this.selection_made) return;
    
    // clear selection
    if (this.selected_cell) this.selected_cell.removeClassName("selected");
    
    if ($R(0,42).include( days_until = this.beginning_date.daysDistance(this.selected_date.stripTime()) )) {
      this.selected_cell = this.calendar_day_grid[days_until];
      this.selected_cell.addClassName("selected");
    }
  },
  reparse: function() { this.parseDate(); this.refresh(); },
  parseDate: function()
  {
    //テキストフィールドから日付を取得、nullの場合は現日時。
    if($F(this.target_element)){
        if(this.options["time"]){
            formatAll = $F(this.target_element).match(/(\d+)年 (\d+)月 (\d+)日 (\d+):(\d+)/);
            formatAll = new Date(RegExp.$1,RegExp.$2 - 1,RegExp.$3,RegExp.$4,RegExp.$5);
        }else{
            formatAll = $F(this.target_element).match(/(\d+)年 (\d+)月 (\d+)日/);
            formatAll = new Date(RegExp.$1,RegExp.$2 - 1,RegExp.$3);
        }
    }else{
        formatAll = "";
    }

    this.date = Date.parseFormattedString(this.options['date'] || formatAll);
    if (isNaN(this.date)) this.date = new Date();
    this.selected_date = new Date(this.date);
    this.date.setDate(1);
  },
  //updateFooter:function(text) { if (!text) text=this.dateString(); this.footer_div.purgeChildren(); this.footer_div.build("text", {innerHTML: text }); },
  updateSelectedDate:function(parts) {
    //if (this.target_element.disabled || this.target_element.readOnly) return false;
    if (parts.day) {
      this.selection_made = true;
      for (x=0; x<=1; x++) {
      this.selected_date.setDate(parts.day);
      this.selected_date.setMonth(parts.month);
      this.selected_date.setYear(parts.year);}
    }
    
    if (parts.hour) this.selected_date.setHours(parts.hour);
    if (parts.minute) this.selected_date.setMinutes(parts.minute);
    
    //this.updateFooter();
    this.setSelectedClass();
    
    if (this.selection_made) this.updateValue();
    new validate('check',this.target_element);
    if (this.options.close_on_click) { this.close(); }
    
  },
  updateValue: function() {
    this.target_element.value = this.dateString();
    if (this.target_element.onchange) { this.target_element.onchange(); }
  },
  today: function() {
    this.date = new Date();
    d=new Date(); this.updateSelectedDate( { day: d.getDate(), month: d.getMonth(), year: d.getFullYear(), hour: d.getHours(), minute: d.getMinutes() } );
    this.refresh();
  },
  close: function() {
    this.target_element.calendar_date_select = nil;
    Event.stopObserving(document.body, "mousedown", this.bodyClick_handler);
    this.calendar_div.remove();
    if (this.iframe) this.iframe.remove();
    this.target_element.focus();
  },
  bodyClick: function(e) { // checks to see if somewhere other than calendar date select grid was clicked.  in which case, close
    if (! $(Event.element(e)).descendantOf(this.calendar_div) ) this.close();
  }
}