/*
  (c)2010 http://byoinnavi.jp/
  (c)2010 http://haishanavi.jp/
*/

var map = {
  gmap: null,
  manager: null,

  cate: null,                /* 現在表示している診療科目 */
  numbers: {},               /* 現在表示している列挙マーカー */

  icons: {},                 /* アイコンのテーブル */

  jsons: {},                 /* 既に読み込んだ jsonファイル */
  corps: {},                 /* 既に設置したマーカー */
  geos: {},                  /* 既に設置した経緯度 */

  corps_all: false,          /* 全ての医院を表示しているか */

  /* sync MapController */
  marker_zoom_min: 13,
  marker_zoom_max: 16,
  marker_zoom_precision: 4,  /* zoom と precision(文字数) の差 */

  corp_size: 20,             /* 1ファイルあたりの corp数上限 */

  icon: new GIcon(),         /* アイコンの原型 */

  zero_padding2: function (int) {
    if (int < 10) { return '0' + int; }
    return int;
  },

  zero_padding3: function (int) {
    if (int < 10) { return '00' + int; }
    if (int < 100) { return '0' + int; }
    return int;
  }
};

map.marker_dir_prefix = map.marker_zoom_min - map.marker_zoom_precision;


/* http://queensryche.blog41.fc2.com/blog-entry-588.html */
if (typeof document.documentElement.style.maxHeight != "undefined") {
  /* IE 7.0 以上 または Gecko などモダンブラウザー */
  map.icon.shadow = '/images/map/marker_shadow.png';
} else {
  /* IE 6.0 以下 */
  map.icon.shadow = '/images/map/marker_shadow.gif';
}

map.icon.iconSize = new GSize(24, 32);
map.icon.shadowSize = new GSize(48, 32);
map.icon.iconAnchor = new GPoint(12, 32);
map.icon.infoWindowAnchor = new GPoint(24, 0);

map.init = function (lat, lng, zoom) {
  if (!GBrowserIsCompatible()) {
    return;
  }

  map.gmap = new GMap2(
    $("area_map"),
    {
      size: new GSize(680, 320)
    }
  );
  map.gmap.addControl(new GLargeMapControl3D());
  map.gmap.addControl(new GHierarchicalMapTypeControl());
  map.gmap.addControl(new GOverviewMapControl());
  map.gmap.addControl(
    new GNavLabelControl(),
    new GControlPosition(
      G_ANCHOR_BOTTOM_LEFT,
      new GSize(80, 10)
    )
  );
  map.gmap.setCenter(new GLatLng(lat, lng), zoom);

  map.init_icons();
};

map.load_single = function (lat, lng, zoom, corp_id) {
  map.init(lat, lng, zoom);
  if (!map.gmap) {
    return;
  }

  map.gmap.addOverlay(
    new GMarker(
      new GLatLng(lat, lng),
      {
        icon: map.icons['n00']
      }
    )
  );
};

map.load = function(lat, lng, zoom, cate, corp_ids){
  map.init(lat, lng, zoom);
  if (!map.gmap) {
    return;
  }

  map.manager = new MarkerManager(map.gmap);
  map.cate = cate;

  corp_ids.each(function(corp_id, i){
    map.numbers[corp_id] = 'n' + map.zero_padding2(i+1);
  });

  GEvent.addListener(map.gmap, "moveend", function(){
    if (map.gmap.getZoom() >= map.marker_zoom_min){
      map.get_corps();
    } else {
      if ($('map_about')){
        $('map_about').innerHTML = '地図をズームしていきますと、医院のマーカーが表示されます。';
        $('map_about').style.color = '#fff';
        $('map_about').style.background = '#c33';
      }
    }
  });
  map.get_corps();
};

map.init_icons = function(){
  (['b', 'f']).each(function(zoom){
    $R(0, 42, false).each(function(i){
      var str = zoom + '_' + map.zero_padding3(i);
      map.icons[str] = map.create_icon(str);
    });
    $R(0, 26, false).each(function(i){
      var str = zoom + '_n' + map.zero_padding2(i);
      map.icons[str] = map.create_icon(str);
    });
  });
};

map.create_icon = function(str){
  return new GIcon(
    map.icon,
    '/images/map/marker_' + str + '.gif'
  );
};

map.get_corps = function(){
  var center = map.gmap.getCenter();
  if (!(GeoQuad.valid_latlng({lat: center.lat(), lng: center.lng()}))) {
    return false;
  }

  var b = map.gmap.getBounds();
  if (!b) {
    return false;
  }

  map.corps_all = false;

  var sw = b.getSouthWest();  /* 日本の場合、西南は常に range_start */
  var ne = b.getNorthEast();  /* 日本の場合、東北は常に range_end */

  /* 現在の zoom(map.marker_zoom_max以上は固定) */
  var zoom = Math.min(map.gmap.getZoom(), map.marker_zoom_max);

  /* ベースとなる文字数  zoom 13..16 => precision 9..12 */
  var precision = zoom - map.marker_zoom_precision;

  /* ベースとなる基数  zoom 13..16 => divisor (0.064)..(0.008) */
  var divisor = Math.pow(2, map.marker_zoom_max - zoom) * GeoQuad.divisor;

  /* 開始・終了地点 */
  var llrange = {
    lat0: sw.lat(),
    lat1: GeoQuad.add(ne.lat(), divisor),
    lng0: sw.lng(),
    lng1: GeoQuad.add(ne.lng(), divisor)
  };

  for (var lat = llrange.lat0; lat <= llrange.lat1; lat = GeoQuad.add(lat, divisor)) {
    for (var lng = llrange.lng0; lng <= llrange.lng1; lng = GeoQuad.add(lng, divisor)) {
      var geo_quad = GeoQuad.encode(lat, lng, precision);
      var fname = geo_quad;
      if (map.cate) {
        fname += "/" + map.cate + '.json';
      } else {
        fname += '.json';
      }
      if (!map.jsons[fname]) {
        map.jsons[fname] = true;
        new Ajax.Request(
          '/parts/geo/' + geo_quad.slice(0, 5) + '/' + geo_quad.slice(5, 9) + '/' + fname,
          {
            method: 'get',
            onSuccess: map.get_markers
          }
        );
      }
    }
  }

  if ((zoom >= map.marker_zoom_max) || map.corps_all) {
    if ($('map_about')){
      $('map_about').innerHTML = '地図上のマーカー(<img src="/images/map/marker_b_000.gif" width="24" height="32" alt="内科" />など)をクリックすると、その医院の詳細が表示されます。';
      $('map_about').style.color = '#c33';
      $('map_about').style.background = '#f4f4f4';
    }
  } else {
    if ($('map_about')){
      $('map_about').innerHTML = '地図をズームしていきますと、さらに多くの医院のマーカーが表示されます。';
      $('map_about').style.color = '#fff';
      $('map_about').style.background = '#c33';
    }
  }
};

map.get_markers = function (ajax_request) {
  /* responseXMLが機能しなかったので、responseJSONに */
  var corp_nodes = ajax_request.responseJSON;
  var numbers = [];
  var markers = [];
  var zoom = map.gmap.getZoom();

  corp_nodes.each(function(node){
    /* IEでは何故か undefinedの nodeが生成される */
    if (!node){
      return false;
    }

    var corp_id = node.id;
    if (map.corps[corp_id]) {
      if (!map.numbers[corp_id]) {
        var recent = map.corps[corp_id];
        if (zoom < recent.zoom) {
          map.manager.removeMarker(recent.marker);
          map.manager.addMarker(recent.marker, zoom);
          map.corps[corp_id] = {marker: recent.marker, zoom: zoom};
        }
      }
    } else if (map.numbers[corp_id]) {
      numbers.push({
        lat: node.lat,
        lng: node.lng,
        key: map.numbers[corp_id],
        id: corp_id
      });
    } else {
      markers.push({
        lat: node.lat,
        lng: node.lng,
        key: node.cate_e,
        id: corp_id
      });
    }
  });

  if (numbers.length > 0) {
    map.manager.addMarkers(
      numbers.collect(function(a){
        map.fix_geo(a);
        return map.make_marker(new GLatLng(a.lat, a.lng), a.key, a.id);
      }),
      map.marker_zoom_min
    );
  }

  if (markers.length > 0) {
    map.manager.addMarkers(
      markers.collect(function(a){
        var latlng = map.fix_geo(a);
        var marker = map.make_marker(new GLatLng(latlng.lat, latlng.lng), a.key, a.id);
        map.corps[a.id] = {marker: marker, zoom: zoom};
        return marker;
      }),
      zoom
    );
  }

  map.manager.refresh();

  if (corp_nodes.length < map.corp_size) {
    map.corps_all = true;
  }
};

map.fix_geo = function (latlng) {
  while (map.geos[latlng.lat + '_' + latlng.lng]) {
    latlng.lat += 0.00001;
    latlng.lng += 0.00003;
  }
  map.geos[latlng.lat + '_' + latlng.lng] = true;
  return latlng;
};

map.make_marker = function (latlng, str, corp_id) {
  var v = 'f';
  var key = v + '_' + str;

  var marker = new GMarker(latlng, {icon: map.icons[key]});
  GEvent.addListener(marker, "click", function(){
    map.corp_info(marker, corp_id);
  });
  return marker;
};

map.corp_info = function (marker, corp_id) {
  new Ajax.Request(
    '/parts/marker/' + map.zero_padding3(corp_id % 1000) + '/' + corp_id + '.html',
    {
      method: 'get',
      onSuccess: function(ajax_request) {
        marker.openInfoWindowHtml(ajax_request.responseText);
      },
      onFailure: function(ajax_request) {
        marker.openInfoWindowHtml('<div>(情報を取得できませんでした)' + corp_id + '</div>');
      }
    }
  );
};

map.unload = function () {
  map.gmap = null;
  map.manager = null;

  map.cate = null;
  map.numbers = null;

  map.icons = null;

  map.jsons = null;
  map.corps = null;
  map.geos = null;
};

map.map_submit = function () {
  var b = map.getBounds();
  $('map_form_center').value = b.getCenter().toUrlValue();
  $('map_form_sw').value = b.getSouthWest().toUrlValue();
  $('map_form_ne').value = b.getNorthEast().toUrlValue();
  $('map_form_zoom').value = map.gmap.getZoom();
};
