// URLの定義
urls = [
    'p30a4bnqb72n6770kh5j186ni8@group.calendar.google.com',
    'd7o380g4ahg81vqbsth0o2j64s@group.calendar.google.com',
    'lig50kfiivfuign1lgobdvdnrk@group.calendar.google.com',
    'u7k7derfi8uc3oc9k1b33vrtuo@group.calendar.google.com',
    ];
categoryId = 0;


// GData クラスの読み込み
google.load("gdata", "2.x");
targetDate = new Date(
    new Date().getFullYear(),
    new Date().getMonth(),
    1);
calendarUrl = 'https://www.google.com/calendar/feeds/' + urls[0] + '/public/full';
calendarStructs = new Array(6);

// 初期化処理
function init() {
  google.gdata.client.init(handleGDError);
}

/**
 * カレンダー情報の読み込みを行います。
 * 非同期通信のため、続きの描画処理は listEvents 関数にて定義されています
 */
function loadCalendar(calUrl, newDate) {
  // 情報取得処理 //{{{
  // 引数チェック
  if (calUrl != undefined && calUrl != null) {
    calendarUrl = calUrl;
  }

  if (newDate != undefined && newDate != null) {
    targetDate = new Date(newDate);
  }

  // Gdata のインスタンス生成
  var service = new 
      google.gdata.calendar.CalendarService('gdata-js-client-samples-simple');
  var query = new google.gdata.calendar.CalendarEventQuery(calendarUrl);
  var d = null;

  yy = targetDate.getFullYear();
  this_mm = targetDate.getMonth() + 1;
  next_mm = this_mm + 1;
  if (this_mm < 10) { this_mm = "0" + this_mm; }
  if (next_mm < 10) { next_mm = "0" + next_mm; }

  minimumStart =  yy + "-" + this_mm + "-01"
  maximumStart =  yy + "-" + next_mm + "-01";

  query.setOrderBy('starttime');
  query.setSortOrder('ascending');
  query.setSingleEvents(true);
  query.setMinimumStartTime(minimumStart);
  query.setMaximumStartTime(maximumStart);
  query.setMaxResults(62);

  service.getEventsFeed(query, listEvents, handleGDError);
}//}}}

/**
 * カレンダー情報を受け取り、スケジュールの埋込みを行います
 */
function listEvents(feedRoot) {
  // スケジュール挿入処理//{{{
  insertDate();

  var entries = feedRoot.feed.getEntries();
  var len = entries.length;

  var weekIndex = 0;
  for (var i = 0; i < len; i++) {
    var entry = entries[i];
    var title = entry.getTitle().getText();
    var times = entry.getTimes();
    var startDateTime = null;
    var startJSDate = null;
    var eventDate = null;

    if (times.length < 1) { continue; }

    startDateTime = times[0].getStartTime();
    startJSDate = startDateTime.getDate();
    eventDate = startJSDate.getDate();

    do {
      // 6週目(0オリジナルなので値は5)なら、6週目で決め打ち
      if (weekIndex == 5) {
        insertSchedule(title, times[0], weekIndex);
        break;
      }
      if (calendarStructs[weekIndex] <= eventDate && calendarStructs[(weekIndex + 1)] > eventDate) {
        insertSchedule(title, times[0], weekIndex);
        break;
      }
      weekIndex++;
    } while(weekIndex < 6);
  }

  // mouseOver イベントを追加
  jQuery('div.schedule p').hover(
      function () {
        jQuery('div.sche_detail').remove();
        var position = jQuery(this).position();
        var detail = jQuery('<div>').css('position', 'absolute');
        detail.css('z-index','10');
        detail.css('top', (position.top - 2));
        detail.css('left', (position.left + 3));
        detail.addClass('category'+categoryId);
        detail.addClass('sche_detail');
        detail.text(jQuery(this).text());
        detail.hover(
          function() {},
          function() {
            jQuery(this).remove();
            }
          );
        jQuery(jQuery(this).parent().parent().get(0)).append(detail);
      },
      function () {
        //jQuery('div#sche_detail').remove();
      }
  );

  var hoge = 1;

  /*
  jQuery('table td').hover(
    function() {
      jQuery('div.sche_detail').remove();
    },
    function() { }
  );
  */
}//}}}

/**
 * カレンダーIDをもとに、一連の勝利を実行します。
 * 通常はこの関数の呼び出しから始まります。
 */
function setCalendar(id) {
  // カレンダーを判別して処理を開始 //{{{
  clearCalendar();
  setDateLabel();
  jQuery('div.tabArea ul.tab li.on').removeClass('on');
  calendarUrl = urls[id];
  categoryId = id + 1;
  jQuery('div.tabArea ul.tab li.menu'+categoryId).addClass('on');
  loadCalendar('https://www.google.com/calendar/feeds/'+ calendarUrl + '/public/full');
} //}}}

/**
 * カレンダーの表示を消す
 */
function clearCalendar() {
  // まとめて子要素を削除する//{{{
  jQuery('div.schedule table tbody').children().remove();
}//}}}

/**
 * カレンダーの年月ラベルを再描画する
 */
function setDateLabel() {
  // targetDate 変数をもとにする//{{{
  jQuery('span#cal_year').text(targetDate.getFullYear());
  jQuery('span#cal_month').text((targetDate.getMonth() + 1));
}//}}}


/**
 * カレンダーの対象日付を1月すすめる
 */
function nextMonth() {
  // 内部で保持しているDate型の変数に時間を足す//{{{
  clearCalendar();
  if (targetDate.getMonth() < 11) {
    targetDate.setMonth(targetDate.getMonth() + 1);
  } else {
    targetDate.setMonth(0);
    targetDate.setFullYear(targetDate.getFullYear() + 1);
  }
  setDateLabel();
  loadCalendar();
}//}}}

/**
 * カレンダーの対象日付を1月戻す
 */
function beforMonth() {
  // 内部で保持しているDate型の変数に時間を引く//{{{
  clearCalendar();
  if (targetDate.getMonth() == 0) {
    targetDate.setMonth(11);
    targetDate.setFullYear(targetDate.getFullYear() - 1);
  } else {
    targetDate.setMonth(targetDate.getMonth() - 1);
  }
  setDateLabel();
  loadCalendar();
}//}}}

/**
 * 指定された月を基に、カレンダーの日付を設定していきます。
 */
function insertDate() {
  // 日付挿入 //{{{
  var dateOfMonth = 1;
  var lastMonthPeriod = targetDate.firstDayOfMonth();
  // 週の開始を月曜日にするための調整
  if (lastMonthPeriod == 0) {
    lastMonthPeriod = 6;
  } else {
    lastMonthPeriod--;
  }
  var lastMonthStart = targetDate.lastDateOfLastMonth() - lastMonthPeriod + 1;
  var week = jQuery('div#cal_week1 table tbody');
  var tableRow = jQuery('<tr>');

  calendarStructs[0] = lastMonthPeriod * -1 + 1;

  // 先月分の日付を入れていく
  for (var d = 0; d < lastMonthPeriod; d++) {
    if (d == 6) {
      tableRow.append(jQuery('<th class="d'+ (lastMonthStart + d) + 'g rightCell">&nbsp;</td>'));
    } else {
      tableRow.append(jQuery('<th class="d'+ (lastMonthStart + d) + 'g">&nbsp;</td>'));
    }
  }
  // 今月分の第1週目の日付を入れていく
  while(tableRow.children().length < 7) {
    if (dateOfMonth < 10) {
      var textDate = "0" + (dateOfMonth++);
    } else {
      textDate = (dateOfMonth++);
    }

    if (tableRow.children().length == 6) {
      tableRow.append(jQuery('<th class="d' + textDate +' rightCell">&nbsp;</td>'));
    } else {
      tableRow.append(jQuery('<th class="d' + textDate +'">&nbsp;</td>'));
    }
  }
  week.append(tableRow);

  var dateOfNextMonth = 1;
  // 2週目以降の日付を入れていく
  for (var w = 2; w <= 6; w++) {
    calendarStructs[(w - 1)] = dateOfMonth;
    week = jQuery('div#cal_week' + w + ' table tbody');
    tableRow = jQuery('<tr>');

    // 最終日まで挿入し終わるか、1週間分(7つ)の要素を挿入し終えるまで繰り返す
    while (dateOfMonth <= targetDate.lastDateOfMonth() && tableRow.children().length < 7) {
      if (dateOfMonth < 10) {
        textDate = "0" + (dateOfMonth++);
      } else {
        textDate = (dateOfMonth++);
      }

      if (tableRow.children().length == 6) {
        tableRow.append(jQuery('<th class="d' + textDate +' rightCell">&nbsp;</td>'));
      } else {
        tableRow.append(jQuery('<th class="d' + textDate +'">&nbsp;</td>'));
      }
    }

    //最終日に到達してセルが残っていたら次の月の日付を埋める
    while (tableRow.children().length < 7) {
      if (dateOfNextMonth < 10) {
        textDate = "0" + (dateOfNextMonth++);
      } else {
        textDate = (dateOfNextMonth++);
      }

      if (tableRow.children().length == 6) {
        tableRow.append(jQuery('<th class="d' + textDate +'g rightCell">&nbsp;</td>'));
      } else {
        tableRow.append(jQuery('<th class="d' + textDate +'g">&nbsp;</td>'));
      }
    }
    week.append(tableRow);
  }
} //}}}

/**
 * 実際にスケジュールを挿入する処理
 */
function insertSchedule(title, targetDate, weekIndex) {
// スケジュール挿入処理//{{{
  var startDate = targetDate.getStartTime().getDate();
  var endDate = targetDate.getEndTime().getDate();
  var cellIndex = startDate.getDate() - calendarStructs[weekIndex];
  var table = jQuery('div#cal_week' + (weekIndex + 1) +' table tbody');
  var rowIndex = 1; // 0番目は日付があるため

  while (true) {
    var rows = table.children('tr');

    // tr が足りていなければ追加する
    if (rows.length == rowIndex) {
      addRow(table);
      continue;
    }

    // 指定のセルに既にものが入っていないか確認。入っていれば次のtrへ
    var cells = jQuery(rows[rowIndex]).children('td');
    // colspan でIndexが変わってしまう現象への対応
    var defaultCellIndex = cellIndex;
    for (var si = 0; si < cellIndex; si++) {
      var colspan = jQuery(cells[si]).attr('colspan');
      if (colspan == undefined || colspan == 1) {
        continue;
      }
      cellIndex -= colspan - 1;
    }
    if (cells[cellIndex] == undefined || jQuery(cells[cellIndex]).children().length != 0) {
      rowIndex++;
      cellIndex = defaultCellIndex;
      continue;
    }

    // 何も入っていないようなら挿入
    jQuery(cells[cellIndex]).append(jQuery('<div class="category'+categoryId+'"><p>' + title + '</p></div>'));

    // 日をまたぐ場合、セルを連結して余ったセルを削除。
    var term = 0;
    var limit = 0;
    if (startDate.getDate() != endDate.getDate() && startDate < endDate) {
      term = parseInt((endDate - startDate) / (24 * 60 * 60 * 1000));
      limit = 6 - cellIndex;
    }
    if (term > 1) {
      jQuery(cells[cellIndex]).attr('colspan', term);
      for (var di = 0; di < limit; di++) {
        jQuery(rows[rowIndex]).children(':last').remove();
      }
    }

    // 週をまたぐ場合、残った分を次の週の頭から開始する
    var targetTerm = 0;
    var leastTerm = term - (limit + 1);
    while (leastTerm > 0) {
      weekIndex++;
      table = jQuery('div#cal_week' + (weekIndex + 1) +' table tbody');

      addRow(table);
      rows = table.children('tr');
      cells = jQuery(rows[1]).children('td');

      jQuery(cells[0]).append(jQuery('<div class="category'+categoryId+'"><p>' + title + '</p></div>'));

      if (leastTerm > 1 && leastTerm <= 7) {
        jQuery(cells[0]).attr('colspan', leastTerm);
        for (var di = 0; di < leastTerm; di++) {
          jQuery(rows[1]).children(':last').remove();
        }
        leastTerm = 0;
      } else {
        jQuery(cells[0]).attr('colspan', 7);
        for (var di = 0; di < 6; di++) {
          jQuery(rows[1]).children(':last').remove();
        }
        leastTerm -= 7;
      }
    }
    break;
  }

}
//}}}

/**
 * テーブルの行を追加する
 */
function addRow(table) {
  // 新しく要素を生成する//{{{
  var newRow = jQuery('<tr>');
  for (var ci = 0; ci < 7; ci++) {
    newRow.append(jQuery('<td>'));
  }
  table.append(newRow);
}//}}}

/**
 * Google GData とのやり取りで例外が発生した場合の処理を行なう
 */
function handleGDError(e) {
  // GData 例外処理//{{{
  if (e instanceof Error) {
    alert('Error at line ' + e.lineNumber +
          ' in ' + e.fileName + '\n' +
          'Message: ' + e.message);
    if (e.cause) {
      var status = e.cause.status;
      var statusText = e.cause.statusText;
      alert('Root cause: HTTP error ' + status + ' with status text of: ' + 
            statusText);
    }
  } else {
    alert(e.toString());
  }
}//}}}


google.setOnLoadCallback(init);

/* vim:set foldmethod=marker:  */

