function Sight(maps, url, callback) {
  this.initialize(maps, url, callback);
}

$.extend(Sight.prototype, Basic, {

  name: "Sight",
//  content: '<div class="window"><dl><dt><!--%= data.name %-->（<!--%= data.kana %-->）</dt><dd><p><!--%= data.summary %--></p><table><tr><th>正式名称</th><td><!--%= data.name %-->（<!--%= data.kana %-->）</td></tr><!--% if (data.popular_name) { %--><tr><th>通称名称</th><td><!--%= data.popular_name %-->（<!--%= data.popular_kana %-->）</td></tr><!--% } %--><!--% if (data.address) { %--><tr><th>住所</th><td><!--%= data.address %--></td></tr><!--% } %--><!--% if (data.tel || data.fax) { %--><tr><th>問い合わせ</th><td><!--% if (data.tel) { %-->TEL.<!--%= data.tel %--><!--% } %--><!--% if (data.tel && data.fax) { %-->／<!--% } %--><!--% if (data.fax) { %-->FAX.<!--%= data.fax %--><!--% } %--></td></tr><!--% } %--></table><ul><!--% if (data.url) { %--><li><a class="site" title="詳細" href="#" rel="site" target="_blank">詳細情報（京都観光Navi）</a>｜</li><!--% } %--><li><a class="zoom" title="詳細／広域" href="#zoom" rel="zoom">詳細／広域</a></li></ul></dd></dl></div>',
  content: '<div class="window"><dl><dt><!--%= data.name %-->（<!--%= data.kana %-->）</dt><dd><p><!--%= data.summary %--></p><table><tr><th>正式名称</th><td><!--%= data.name %-->（<!--%= data.kana %-->）</td></tr><!--% if (data.popular_name) { %--><tr><th>通称名称</th><td><!--%= data.popular_name %-->（<!--%= data.popular_kana %-->）</td></tr><!--% } %--><!--% if (data.address) { %--><tr><th>住所</th><td><!--%= data.address %--></td></tr><!--% } %--><!--% if (data.tel || data.fax) { %--><tr><th>問い合わせ</th><td><!--% if (data.tel) { %-->TEL.<!--%= data.tel %--><!--% } %--><!--% if (data.tel && data.fax) { %-->／<!--% } %--><!--% if (data.fax) { %-->FAX.<!--%= data.fax %--><!--% } %--></td></tr><!--% } %--></table><ul><li><a class="zoom" title="詳細／広域" href="#zoom" rel="zoom">詳細／広域</a></li></ul></dd></dl></div>',
  loadStatus: [0, 0, 0, 0],

  initialize: function(maps, url, callback) {
    this.maps = maps;
    this.markers = [];
    this.polylines = [];
    this.rect = false;
    this.areamarkers = [[], [], []];
    this.areaindex   = [[], [], []];
    this.data;
    this.searchword  = null;
    this.searchindex = [];

    $.getJSON(url, $.scope(this, function(data) {
      data.sort(function (a, b) { return b.lat - a.lat; });
      this.data = data;
      (callback || function() {}).apply(this);
    }));
  },

  _create: function(data) {

    if (this.rect && this.loadStatus[this.rect.area] == 1 && this.getAreaMarkers(this.rect.area).length > 0) {
      return;
    } else if (this.rect) {
      this.loadStatus[this.rect.area] = 1;
    } else {
      this.loadStatus[0] = 1;
    }

    $.each(data, $.scope(this, function(index, sight) {
      if (this.rect && (sight.lat > this.rect.top || sight.lat < this.rect.bottom)) return true;
      if (sight['marker']) return true;
      this.createMarker(sight, index);
    }));
  },

  createMarker: function (sight, index) {
    var marker = new google.maps.Marker(new google.maps.LatLng(sight.lat, sight.lng), {
      icon: new google.maps.Icon({
        iconAnchor: new google.maps.Point(10, 10),
        iconSize: new google.maps.Size(20, 20),
        image: "image/icon_sight" + (index < 9 ? "0" + (index + 1) : index + 1) + ".png",
        infoWindowAnchor: new google.maps.Point(10, 0),
        mozPrintImage: "image/icon_sight" + (index < 9 ? "0" + (index + 1) : index + 1) + "_print.gif",
        printImage: "image/icon_sight" + (index < 9 ? "0" + (index + 1) : index + 1) + "_print.gif"
      }),
      title: sight.name
    });
    this.maps.addOverlay(marker);
    this.getMarkers().push(marker);

    this.data[index]['marker'] = marker;
    if (this.rect) {
      this.getAreaMarkers(this.rect.area).push(marker);
      this.setAreaIndex(this.rect.area, index);
    }

    var content = $(this.content).evaluate(sight);
    content.find("a[rel=zoom]").click(this._events(this.getMarkers(), this.data[index]['marker']));
    content.find("a[rel=site]").attr("href", sight.url);
    marker.bindInfoWindowTabs([

      new google.maps.InfoWindowTab("施設概要", $.scope(this, function(content) {
        content.find("p").text($.truncate(content.find("p").text(), 80));
        content.find("p").append('［<a title="全文を表示" href="#more" rel="more">全文を表示</a>］');
        content.find("a[rel=more]").click(this._events());
        content.find("table").remove();
        return content.get(0);
      })(content.clone(true))),

      new google.maps.InfoWindowTab("施設情報", $.scope(this, function(content) {
        content.find("p").remove();
        return content.get(0);
      })(content.clone(true)))

    ], {
      maxContent: content.get(0),
      maxTitle: sight.name,
      maxWidth: 400
    });
  },

  search: function(string) {

    this.hide();
    this.rect = false;

    if (this.searchword != null && this.searchword == string) {
      $.each(this.searchindex, $.scope(this, function(index, number) {
        this.data[number]['marker'].show();
      }));
      return;
    } else {
      this.searchword  = string;
      this.searchindex = [];
    }

    string = string.replace(/([\.\\\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, "\\$1");
    string = $.trim(string);
    var regexp = new RegExp("(?=.*" + string.replace(/\s+/g, ")(?=.*") + ")");
    $.each(this.data, $.scope(this, function(index, sight) {
      var match = [sight.name, sight.kana, sight.popular_name, sight.popular_kana, sight.summary].join("").match(regexp);
      if (match) {
        if (!this.data[index]['marker']) this.createMarker(this.data[index], index);
        this.data[index]['marker'].show();
        this.searchindex.push(index);
      }
    }));
  },

  show: function() {
    $.each(this.data, function(index, overlay) { if (overlay['marker'] && !overlay['marker'].isHidden()) overlay['marker'].show(); });
  },

  showArea: function(area) {
    this.hide();
    $.each(this.getAreaMarkers(area), $.scope(this, function(index, marker) {
      marker.show();
    }));
  },

  setCenter: function(markers) {
    if (this.getMarkers().length == 0) return;
    var bounds = new google.maps.LatLngBounds();
    $.each(markers || this.getMarkers(), function(index, marker) {
      if (marker.isHidden()) return true;
      bounds.extend(marker.getLatLng());
    });
    this.maps.setCenter(bounds.getCenter(), this.maps.getBoundsZoomLevel(bounds));
    this.maps.getInfoWindow().hide();
  },

  setCenterArea: function(area) {
    var bounds = new google.maps.LatLngBounds();
    $.each(this.getAreaMarkers(area), function(index, marker) {
      bounds.extend(marker.getLatLng());
    });
//    this.maps.setCenter(bounds.getCenter(), this.maps.getBoundsZoomLevel(bounds));
    this.maps.setCenter(bounds.getCenter(), 15);
    this.maps.getInfoWindow().hide();
  },

  getAreaMarkers: function(area) {
    return this.areamarkers[area - 1];
  },

  setAreaIndex: function(area, index) {
    this.areaindex[area - 1].push(index);
  },

  getAreaIndex: function(area, index) {
    return this.areaindex[area - 1][index];
  },

  getAnchors: function() {
    return $.map(this.data, $.scope(this, function(data, index) {
      if (!data['marker'] || data['marker'].isHidden()) return null;
      var anchor = $('<a title="" href="#"><!--%= data.name %--></a>').evaluate(data);
      anchor.click(function() {
        google.maps.Event.trigger(data['marker'], "click");
        return false;
      });
      anchor.css("display", "inline");
      $.data(anchor.get(0), 'index', index);
      return anchor;
    }));
  },

  getAreaAnchors: function(area) {
    return $.map(this.getAreaMarkers(area), $.scope(this, function(marker, index) {
      var anchor = $('<a title="" href="#"><!--%= data.name %--></a>').evaluate(this.data[this.getAreaIndex(area, index)]);
      anchor.click(function() {
        google.maps.Event.trigger(marker, "click");
        return false;
      });
      anchor.css("display", "inline");
      return anchor;
    }));
  },

  setMarker: function (rect, callback) {
    this.rect = (rect ? rect : false);
    this._create(this.data);
    (callback || function() {}).apply(this);
  }

});