
$(document).ready(function() {

  /** Dynamic parameters. */
  var firstDayOfWeek = 1; // The first day of week, ex. 0:sun 1:mon
  var lang = 'en'; //'ja';

  /** Initialize parameters. */
  var dayOfWeekString = new Array();
  dayOfWeekString['ja'] = new Array('日','月','火','水','木','金','土');
  dayOfWeekString['en'] = new Array('Sun','Mon','The','Wed','Thu','Fri','Sat');
  var displayingMonth = new Date();

  /**
   * Returns the first date of month.
   * @param {Date} date Basis date.
   * @return {Date} First date.
   */
  var getFirstDateOfMonth = (function(date) {
    var d = new Date(date);
    d.setDate(1);
    return d;
  });

  /**
   * Returns the previous month.
   * @param {Date} date Basis date.
   * @param {int} rollingCount Count of month for previous.
   * @return {Date} Previous month.
   */
  var rollMonth = (function(date, rollingCount) {
    var d = date; //var d = new Date(date);
    d.setMonth(d.getMonth() + rollingCount);
    return d;
  });

  /**
   * Returns the previous closest the day of week.
   * @param {Date} date Basis date.
   * @param {int} targetDayOfWeek Target day for closest day. 
   */
  var getClosestDayOfWeek = (function(date, targetDayOfWeek) {

    var d = new Date(date);
    while (d.getDay() != targetDayOfWeek) {
      d.setDate(d.getDate() -1);
    }
    return d;

    // console.log(d.getFullYear());
    // console.log(d.getMonth() + 1);
    // console.log(d.getDay()); // 1:mon
    // console.log(d.getDate());
  });

  /**
   * Format date for YYYY/M.
   * @param {Date} date Basis date.
   * @return {string} Formatted string.
   */
  var formatYYYYM = (function(date) {
    return date.getFullYear() + '/' + (date.getMonth() + 1); // + '/' + date.getDate();
  });

  /**
   * Format date for YYYY_M_D.
   * @param {Date} date Basis date.
   * @return {string} Formatted string.
   */
  var formatYYYYMDWithUnderscore = (function(date) {
    return date.getFullYear() + '_' + (date.getMonth() + 1) + '_' + date.getDate();
  });

  /**
   * Check the string for valid date.
   * @param {string} str Check string for date.
   * @see http://stackoverflow.com/questions/1353684/detecting-an-invalid-date-date-instance-in-javascript
   */
  var isValidDate = (function(str) {
    var d = new Date(str);
    if (Object.prototype.toString.call(d) === "[object Date]" ) {
      // it is a date
      if (isNaN(d.getTime())) {  // d.valueOf() could also work
        // date is not valid
        return false;
      } else {
        // date is valid
        return true;
      }
    } else {
      // not a date
      return false;
    }
  }); 

  /**
   * Remove and re-render tbody for Refleshing dates in calendar.
   * @param {Date} targetMonth Basis month for rendering.
   * @param {int} firstDayOfWeek The first day of week
   */
  var reflesh = (function(targetMonth, firstDayOfWeek) {

    var firstDate = getFirstDateOfMonth(targetMonth);
    var startDate = getClosestDayOfWeek(firstDate, firstDayOfWeek);
    var d = new Date(startDate); // loop counter

    $('#calendar tbody').empty();

    while (true) {
      if (targetMonth.getFullYear() < d.getFullYear()) {
        break;
      } else if (targetMonth.getMonth() < d.getMonth()) {
        if (targetMonth.getFullYear() == d.getFullYear()) {
          break;
        }
      }

      var $tr = $('<tr>');
      for (var i = 0; i < 7; i++) { // Loop for a week.
        $tr.append(
          $('<td>').append(d.getDate()).addClass('day').addClass('dow' + d.getDay()).attr('id', formatYYYYMDWithUnderscore(d))
        );
        d.setDate(d.getDate() + 1);
      }
      $('#calendar tbody').append($tr);
    }

    $('.current-month').text(formatYYYYM(targetMonth));
  });

  /**
   * Render thead and tbody for initializing table.
   * @param {Date} targetMonth Basis month for rendering.
   * @param {string} language Language code (in th tag) ex. 'en', 'ja'.
   */
  var initialize = (function(targetMonth, firstDayOfWeek, language) {

    var $tr = $('<tr>').attr('id', 'day_of_week_header');
    var dow = firstDayOfWeek;
    for (var d = 0; d < 7; d++) {
      if (dow == 7) {
        dow = 0;
      }
      // var dow = firstDayOfWeek;
      $tr.append($('<th>').append(dayOfWeekString[language][dow]).addClass('dow'+dow));
      dow++;
    }
    // $(dayOfWeekString[language]).each(function() {
    //   $tr.append($('<th>').append(this));
    // });
    $('#calendar thead').append($tr);

    reflesh(targetMonth, firstDayOfWeek);
  });

  initialize(displayingMonth, firstDayOfWeek, lang);


  $('#calendar').on('click', 'td', function() {
    var $this = $(this);
    var dowText = $('#day_of_week_header').children('th').eq($this.index()).text();
    alert($this.attr('id') + ' ' + dowText);
  })

  $('.prev-month').on('click', function() {
    rollMonth(displayingMonth, -1);
    reflesh(displayingMonth, firstDayOfWeek);
  })
  $('.next-month').on('click', function() {
    rollMonth(displayingMonth, 1);
    reflesh(displayingMonth, firstDayOfWeek);
  })

  $('#goto_today').on('click', function() {
      displayingMonth = new Date();
      reflesh(displayingMonth, firstDayOfWeek);
  });
  $('#goto_date').on('change', function() {
    
    if (isValidDate($(this).val())) {
      displayingMonth = new Date($(this).val());
      reflesh(displayingMonth, firstDayOfWeek);
    } else {
      console.log('not a date.');
    }
  });

  // $('input:visible, select, textarea').eq(0).focus();
});
