/**
 * Google MyMap EXPO 全般のグローバル変数
 *
 * worksheets 複数スプレッドシートのワークシートを格納する一時配列
 * plotEntries プロット数
 *
 * weeks 週毎>日毎 にワークシートを格納した配列の配列
 *
 * currentWeek 選択中の週のweeksのインデックス
 * currentDay 選択中の週の日のweeksのインデックス
 *
 * workingWeek 選択中の週のワークシートを格納した一時配列
 *
 * targetWeek 読み込む日付のワークシート情報を格納した一時オブジェクト
 *  loaded リストフィードを読み込んだかどうか
 *
 * keys 新着スプレッドシートのkey配列
 *
 * page エントリ一覧のページナンバー
 * entryLimit エントリ一覧のページあたりのエントリ数
 */
var gmymapexpo = new Object();

/**
 * mymap_new.html用の初期化関数。
 * 初期化後、新着ワークシートを読み込む。
 */
function initLatest() {
  initMap();

  var select =
      document.getElementById('items').getElementsByTagName('select')[0];
  gmymapexpo.plotEntries = select.value;
  gmymapexpo.currentWeek = 0;
  gmymapexpo.currentDay = 0;
  gmymapexpo.keys = [
                     'pZJwZdcoBTuPqChR5QFKFXA'
                     ];
  gmymapexpo.entryLimit = 10;
  gmymapexpo.worksheets = new Array();

  loadLatestWorksheets();
}

/**
 * 新着ワークシートの読み込み
 */
function loadLatestWorksheets() {
  var key = gmymapexpo.keys.shift();
  loadJson([
            'http://spreadsheets.google.com/feeds/worksheets/',
            key,
            '/public/values',
            '?alt=json-in-script',
            '&callback=setLatestWorksheets'
            ].join(''));
}

/**
 * 新着ワークシートの読み込み後、シート名が日付書式に従うシートの
 * リストフィードURLを取得。
 * ワークシート情報は 週>日 毎に整理して
 * gmymapexpo.weeksに格納。
 * プロットのため残りの処理をbuildWeekNavigationに任せる。
 * @param json 新着ワークシートフィードのjsonオブジェクト
 */
function setLatestWorksheets(json) {
  var dateExpr = new RegExp('([0-9]{4})([0-9]{2})([0-9]{2})', 'i');
  var worksheets = gmymapexpo.worksheets.concat();
  var today = new Date();
  for (var i = 0; i < json.feed.entry.length; i++) {
    var entry = json.feed.entry[i];
    if (entry.title.$t.match(dateExpr)) {
      var date = new Date(RegExp.$1, RegExp.$2-1, RegExp.$3);
      if (date.getTime() < today.getTime()) {
        var hash = new Object();
        hash.date = date;
        hash.label = [
                      date.getDate(),
                      '/',
                      (date.getMonth()+1),
                      '/',
                      date.getFullYear()
                      ].join('');
        hash.href = entry.link[0].href;
        hash.entries = new Array();
        worksheets.push(hash);
      }
    }
  }

  if (gmymapexpo.keys.length) {
    gmymapexpo.worksheets = worksheets;
    loadLatestWorksheets();
  } else {
    worksheets.sort(function(a,b){
      var at = a.date.getTime();
      var bt = b.date.getTime();
      if (at == bt) {
        return 0;
      }
      return at > bt? -1: 1;
    });

    var latest = worksheets[0].date.getTime();
    var day = 1000 * 60 * 60 * 24;
    var weeks = new Array();
    for (var i in worksheets) {
      var worksheet = worksheets[i];
      var week = Math.floor((latest - worksheet.date.getTime()) / day / 7);
      if (!weeks[week]) {
        weeks[week] = new Array();
      }
      weeks[week].push(worksheets[i]);
    }
    gmymapexpo.weeks = weeks;
    buildWeekNavigation();
  }
}

/**
 * WeekNavigationの構築を行う前に
 * gmymapexpo.weeksデータを壊さないように
 * 選択中の週ワークシートリストをコピーし、
 * その週のリストフィード読み込みを開始する。
 * loadLatestListで
 * 必要なすべてのリストフィード読み込み処理が終わった後に
 * _buildWeekNavigationへ処理が戻る。
 */
function buildWeekNavigation() {
  gmymapexpo.workingWeek = gmymapexpo.weeks[gmymapexpo.currentWeek].concat();
  loadLatestList();
}

/**
 * WeekNavigation構築の実処理。
 * 主にHTML処理。
 * ただし、選択中の日にあわせてプロット呼び出しを受け持つ。
 */
function _buildWeekNavigation() {
  var week = gmymapexpo.weeks[gmymapexpo.currentWeek].concat();
  var str = ['<ul>'];
  if (gmymapexpo.currentDay > 0 ||
      gmymapexpo.weeks[gmymapexpo.currentWeek-1]) {
    str.push('<li><a href="#mapTitle" onclick="nextDay(); return false;">');
    str.push('&laquo;&nbsp;Next');
    str.push('</a></li>');
  } else {
    str.push('<li><span class="current"></span></li>');
  }
  for (var i=0; i<week.length; i++) {
    if (i == gmymapexpo.currentDay || week[i].entries.length == 0) {
      str.push('<li><span class="current">');
      str.push(week[i].label);
      str.push('</span></li>');
      _plot();
    } else {
      str.push('<li><a href="#mapTitle" onclick="plotDate(');
      str.push(i);
      str.push('); return false;">');
      str.push(week[i].label);
      str.push('</a></li>');
    }
  }
  if ((gmymapexpo.currentDay <
       gmymapexpo.weeks[gmymapexpo.currentWeek].length - 1) ||
      gmymapexpo.weeks[gmymapexpo.currentWeek + 1]) {
    str.push('<li><a href="#mapTitle" onclick="prevDay(); return false;">');
    str.push('Prev&nbsp;&raquo;');
    str.push('</a></li>');
  } else {
    str.push('<li><span class="current"></span></li>');
  }
  str.push('</ul>');
  document.getElementById('dateList').innerHTML = str.join("");

  str = ['<a href="#mapTitle" onclick="resetZoom(); return false">Display the entire ',
         week[gmymapexpo.currentDay].label,
         '</a>'].join('');
  document.getElementById('mapListName').innerHTML = str;
}

/**
 * プロット数に応じてプロットを実行する。
 */
function _plot() {
  listEntries();
  var entries =
      gmymapexpo.weeks[gmymapexpo.currentWeek][gmymapexpo.currentDay].entries;
  if (gmymapexpo.plotEntries != 'all' &&
      entries.length > gmymapexpo.plotEntries) {
    entries = entries.concat().slice(0, gmymapexpo.plotEntries);
  }
  plotMarkers(entries);
  resetZoom();
}

/**
 * 選択された日付のインデックスにgmymapexpo.currentDayを更新し
 * 残りの処理をbuildWeekNavigationに投げる。
 * @param day gmymapexpo.weeksの選択中の週の日インデックス
 */
function plotDate(day) {
  gmymapexpo.currentDay = day;
  buildWeekNavigation();
}

/**
 * 週/日付インデックスを1つ過去に更新し、
 * 残りの処理をbuildWeekNavigationに投げる。
 */
function prevDay() {
  gmymapexpo.currentDay++;
  if (gmymapexpo.currentDay >=
      gmymapexpo.weeks[gmymapexpo.currentWeek].length) {
    gmymapexpo.currentWeek += 1;
    gmymapexpo.currentDay = 0;
  }
  buildWeekNavigation();
}

/**
 * 週/日付インデックスを1つ未来に更新し、
 * 残りの処理をbuildWeekNavigationに投げる。
 */
function nextDay() {
  gmymapexpo.currentDay--;
  if (gmymapexpo.currentDay < 0) {
    gmymapexpo.currentWeek -= 1;
    gmymapexpo.currentDay = 6;
  }
  buildWeekNavigation();
}

/**
 * 新着リストフィードを読み込む。
 * 選択中の週すべての日付のリストフィードを
 * 読み込むまで処理が繰り返される。
 * すべて読み込んだ後は
 * _buildWeekNavigationへ処理を戻す。
 */
function loadLatestList() {
  if (gmymapexpo.workingWeek.length) {
    gmymapexpo.targetWeek = gmymapexpo.workingWeek.shift();
    if (!gmymapexpo.targetWeek.loaded) {
      loadJson([
                gmymapexpo.targetWeek.href,
                '?alt=json-in-script',
                '&callback=setLatestList',
                '&orderby=position',
                '&reverse=true'
                ].join(''));
      document.getElementById('dateList').innerHTML = '<b>Loading...</b>';
      document.getElementById('entries').innerHTML =
          '<h3><a href="#mapTitle" onclick="return false;">' +
          '<b>Loading...</b></a></h3>';
    } else {
      loadLatestList();
    }
  } else {
    var week = new Array();
    for (var i=0; i<gmymapexpo.weeks[gmymapexpo.currentWeek].length; i++) {
      var day = gmymapexpo.weeks[gmymapexpo.currentWeek][i];
      if (day.entries.length) {
        week.push(day);
      }
    }
    gmymapexpo.weeks[gmymapexpo.currentWeek] = week;
    _buildWeekNavigation();
  }
}

/**
 * 新着リストフィードから行データを読み込み
 * gmymapexpo.targetWeek.entriesへ格納する。
 * その後、loadLatestListへ処理を戻す。
 * @param json 新着リストフィードのjsonオブジェクト
 */
function setLatestList(json) {
  gmymapexpo.targetWeek.loaded = true;
  if (json.feed.entry) {
    for (var i = 0; i < json.feed.entry.length; i++) {
      var entry = getRowData(json.feed.entry[i]);
      gmymapexpo.targetWeek.entries.push(entry);
    }
  }
  loadLatestList();
}

/**
 * プロット数の変更。
 * select.onchangeにアタッチする関数。
 * @param number プロット数
 */
function changePlots(number) {
  gmymapexpo.plotEntries = number;
  buildWeekNavigation();
}

/**
 * エントリ一覧を表示する
 * _plotからのみ呼ばれ、gmymapexpo.pageを0に初期化する
 * @param json 新着ワークシートフィードのjsonオブジェクト
 */
function listEntries() {
  gmymapexpo.page = 0;
  _listEntries();
}

/**
 * エントリ一覧表示のHTML処理
 */
function _listEntries() {
  var day = gmymapexpo.weeks[gmymapexpo.currentWeek][gmymapexpo.currentDay];
  var entries = day.entries;
  var str = ['<h3>'];
  if (gmymapexpo.currentDay > 0 ||
      gmymapexpo.weeks[gmymapexpo.currentWeek-1]) {
    str.push('<a href="#mapTitle" onclick="nextDay();" class="prev">');
    str.push('&laquo;</a>&nbsp;');
  }
  str.push('<a href="#mapTitle" onclick="resetZoom();">');
  str.push(day.label);
  str.push('</a>');

  if ((gmymapexpo.currentDay <
       gmymapexpo.weeks[gmymapexpo.currentWeek].length - 1) ||
      gmymapexpo.weeks[gmymapexpo.currentWeek + 1]) {
    str.push('&nbsp;<a href="#mapTitle" onclick="prevDay();" class="next">');
    str.push('&raquo;</a>');
  }
  str.push('</h3><ol>');

  var start = gmymapexpo.page * gmymapexpo.entryLimit;
  var end = start + gmymapexpo.entryLimit;
  if (end > entries.length) {
    end = entries.length;
  }
  for (var i = start; i < end; i++) {
    var entry = entries[i];
    str = str.concat([
                      '<li>',
                      '<a class="img" onclick="openEntry(',
                      i,
                      ');" href="#mapTitle">',
                      '<img alt="blue" src="images/map-icon-',
                      entry.icon,
                      '.gif"/>',
                      '</a>',
                      '<span>',
                      '<a onclick="openEntry(',
                      i,
                      ');" href="#mapTitle">',
                      entry.title,
                      '</a>',
                      '<br/>',
                      entry.nick,
                      ' ',
                      entry.date.getDate(),
                      '/',
                      entry.date.getMonth() + 1,
                      '/',
                      entry.date.getFullYear(),
                      '</span>',
                      '</li>'
                      ]);
  }
  str.push('</ol>');
  if (entries.length > gmymapexpo.entryLimit) {
    str = str.concat([
                      '<div id="pageNav">',
                      '<ul>'
                      ]);
    var end = Math.ceil(entries.length / gmymapexpo.entryLimit);
    for (var i=0; i<end; i++) {
      str.push('<li>');
      if (gmymapexpo.page == i) {
        str = str.concat([
                          '<span class="current">',
                          i+1,
                          '</span>'
                          ]);
      } else {
        str = str.concat([
                          '<a href="#mapTitle" onclick="listEntriesByPage(',
                          i,
                          ');">',
                          i+1,
                          '</a>'
                          ]);
      }
      str.push('</li>');
    }
    str = str.concat([
                      '</ul>',
                      '</div>'
                      ]);
  }
  document.getElementById('entries').innerHTML = str.join('');
}

/**
 * pageNavのa.onclickにアタッチする関数。
 * エントリ一覧をページナンバーに従って表示するための前処理。
 * エントリ一覧のインデックスは、0から割り当て直さずそのまま維持する。
 * 表示件数を超えたエントリを一覧する場合にプロットしなおす。
 * @param page 0から始まるページナンバー
 */
function listEntriesByPage(page) {
  gmymapexpo.page = page;
  var entries =
  gmymapexpo.weeks[gmymapexpo.currentWeek][gmymapexpo.currentDay].entries;
  if (gmymapexpo.plotEntries != 'all' &&
      entries.length > gmymapexpo.plotEntries) {
        var _entries = new Array();
        var start = page * gmymapexpo.entryLimit;
        var end = start + gmymapexpo.entryLimit;
        if (end > entries.length) {
          end = entries.length;
        }
        for (var i=start; i<end; i++) {
          _entries[i] = entries[i];
        }
        plotMarkers(_entries);
        resetZoom();
      }
  _listEntries();
}

/**
 * エントリ一覧のa.onclickにアタッチする関数。
 * クリックしたエントリのインフォウィンドウを表示する。
 * @param index エントリ一覧のインデックス
 */
function openEntry(index) {
  openMyMapInfo(index);
}

google.setOnLoadCallback(initLatest);

