$.maps = function() {
  var $o = {
    map_options: {
      zoom: 5,
      scrollwheel: true,
      scaleControl: true,
      navigationControl:  true,
      //      mapTypeId: google.maps.MapTypeId.ROADMAP,
      streetViewControl: true
    },
    zoom_levels: {
      street_number: 18,
      route: 13,
      locality: 12,
      political: 10
    }
  },
  $form       = $("FORM:first"),
  $query      = $("input[type=text]:first", $form).val(),
  $map_holder = $("#map"),
  geocoder    = new GClientGeocoder(),
  $map, $control, $default_control, guyIcon, $marker, $street_marker, $street_instance, $panorama, 
  client = new GStreetviewClient(),
  lastMarkerLocation, smallNode,
  layers = {
    panoramio: new GLayer("com.panoramio.all"),
    wikipedia: new GLayer("org.wikipedia.de"),
    youtube: new GLayer("com.youtube.all"),
    webcams: new GLayer("com.google.webcams")
  },
  $obj = {
    init: function() {
      if ($map_holder.attr('limit')) geocoder.setBaseCountryCode($map_holder.attr('limit'));
      $obj.setup_form();
      $obj.setup_guy();
      $obj.setup_map();
    },
    setup_guy: function() {
      guyIcon =   new GIcon(G_DEFAULT_ICON);
      guyIcon.image = "http://maps.gstatic.com/mapfiles/cb/man_arrow-0.png";
      guyIcon.transparent = "http://maps.gstatic.com/mapfiles/cb/man-pick.png";
      guyIcon.imageMap = [
      26,13, 30,14, 32,28, 27,28, 28,36, 18,35, 18,27, 16,26,
      16,20, 16,14, 19,13, 22,8
      ];
      guyIcon.iconSize = new GSize(49, 52);
      guyIcon.iconAnchor = new GPoint(25, 35);  // near base of guy's feet
      guyIcon.infoWindowAnchor = new GPoint(25, 5);  // top of guy's head
    },
    setup_form: function() {
      $("input[type=text]", $form).focus();
      $("SELECT", $form).change(function(){
        $form.submit()
      });
    },
    setup_map: function() {
      $map_holder.bind('got_coordinates', function() {
        $map_holder.css({height: $(window).height()});
        $map = new GMap2($map_holder.get(0));
        $map.setCenter($o.map_options.center, $o.map_options.box ? $map.getBoundsZoomLevel($o.map_options.box) + 2  : 15);
        
        GEvent.addListener($map, "zoomend", function() {console.log($map.getZoom())});

        if (!$map_holder.is('.small')) {
          $map.addMapType(G_SATELLITE_3D_MAP);
          $map.addMapType(G_PHYSICAL_MAP);
          $map.addControl(new GLargeMapControl3D());
          $map.enableRotation();
          $default_control = new GMapTypeControl();
          $map.addControl($default_control, new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(0,7)));
          $obj.setup_controls();
        }
        $marker = new GMarker($o.map_options.center);
        $map.addOverlay($marker);
        window.onunload = GUnload;
      });
      $obj.find_address();

    },
    setup_controls: function() {
      if (typeof($default_control.B) == 'undefined') return setTimeout($obj.setup_controls, 100);
      var $c = $($default_control.B);
      if ($c.width() == 0) return setTimeout($obj.setup_controls, 100);
      var $position = $c.position();

      OtherApisControl.prototype.getDefaultPosition = function() {
        return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize($position.left - 240, $position.top));
      }

      $control = new OtherApisControl();
      
      $map.addControl($control);
      $map.enableContinuousZoom();
      $map.enableScrollWheelZoom() ;
    },
    find_address: function(){
      if (!$query.length) return false;
      var geocoder = new GClientGeocoder();
      geocoder.getLocations($query, function(response) {
        $o.map_options.center = null;
        $o.map_options.box = null;
        if (response && response.Status.code == 200) {
          var point = response.Placemark[0].Point.coordinates;
          $o.map_options.center = new GLatLng(point[1], point[0]);
          var $box= response.Placemark[0].ExtendedData.LatLonBox;
          $o.map_options.box = new GLatLngBounds(
              new GLatLng($box.west, $box.south),
              new GLatLng($box.east, $box.north)
            );
          $map_holder.trigger('got_coordinates');
          return;
        }
        $obj.draw_not_found();
      });
    },
    toggleStreet: function() {
      if (!$street_instance) {
        $street_instance = new GStreetviewOverlay();
        $street_marker = new GMarker($marker.getLatLng(), {
          icon: guyIcon,
          draggable: true
        });
        $map.addOverlay($street_marker);
        $map.addOverlay($street_instance);
        $map.removeOverlay($marker);
        if (!lastMarkerLocation) lastMarkerLocation = $street_marker.getLatLng();

        var maximizeclickHandler = function() {$panorama.remove();};
        var maximizeendHandler = function() {setTimeout(function() {$panorama.checkResize()}, 500);};
        var infowindowbeforecloseHandler = function() {$panorama.remove();};

        GEvent.addListener($street_marker, "dragend", $obj.drag_street_marker);
        GEvent.addListener($street_marker, "click", $obj.open_panorama_bubble);

//        GEvent.addListener($map.getInfoWindow(), "maximizeclick", maximizeclickHandler);
//        GEvent.addListener($map.getInfoWindow(), "maximizeend", maximizeendHandler);
        GEvent.addListener($street_marker, "infowindowbeforeclose", infowindowbeforecloseHandler);

        $obj.open_panorama_bubble();
      }
      else {
        $map.removeOverlay($street_instance);
        $map.removeOverlay($street_marker)
        $map.addOverlay($marker);
        $street_instance = null;
        $street_marker = null;
      }
      
    },
    drag_street_marker: function() {
//      if (!$.browser.msie) $panorama.remove();
      $panorama.remove();
      var latlng = $street_marker.getLatLng();
      client.getNearestPanorama(latlng, $obj.onPanoramaResponse);
    },
    open_panorama_bubble: function() {
      var timeout = 500;
      if (!$panorama) {
        timeout = 1500;
        smallNode = $('<div/>').width(500).height(300).attr({id: 'pano'});
        $(document).append(smallNode);
      }

      $panorama = new GStreetviewPanorama(smallNode);
      $panorama.setContainer(smallNode.get(0));
      GEvent.addListener($panorama, "error", $obj.handle_error_panorama);
      
      $street_marker.openInfoWindow(smallNode.get(0));
      setTimeout(function() {$panorama.setLocationAndPOV(lastMarkerLocation, null)}, timeout);
    },
    onPanoramaResponse: function(response) {
      if (response.code != 200) {
        $street_marker.setLatLng(lastMarkerLocation);
      } else {
        var latlng = new GLatLng(response.Location.lat, response.Location.lng);
        $street_marker.setLatLng(latlng);
        lastMarkerLocation = latlng;
        $obj.open_panorama_bubble();
      }
    },
    draw_not_found: function() {
      var $t = $('#address_not_found').clone().removeClass('error-template');
      $("script", $t).remove();
      $map_holder.after($t);
      $map_holder.remove();
      $obj.hide_banners();
    },
    handle_error_panorama: function(error) {
      if (error == GStreetviewPanorama.ErrorValues.NO_NEARBY_PANO) {
        var $t = $('#address_not_found_panoramio').clone().removeClass('error-template');
        $("script", $t).remove();
        $street_marker.openInfoWindowHtml($t.html());
        $obj.hide_banners();
      }
    },
    hide_banners: function() {
      $('#rightside-banner, #header-banner').remove();
    }
  };


  function OtherApisControl() {} //Class contructor

  OtherApisControl.prototype = new GControl();
  OtherApisControl.prototype.initialize = function(map) {
    var container = document.createElement("div"),
    fsContainer = document.createElement("div");
    fsContainer.className = "gmap_buttons";

    var $buttons_holder = $("#buttons-prototype").removeClass('hidden');
    map.getContainer().appendChild(container);
    container.appendChild(fsContainer);
    $(container).append($buttons_holder);

    $(".map-menu-opener A", $buttons_holder).mousedown(function(){
      var $parent = $(this).parents('.map-menu-opener:first');
      $parent.toggleClass('closed');
      if ($parent.is('[ref=street]')) $obj.toggleStreet();
    });
    $("#map-options INPUT[type=checkbox]").change(function(){
      var $checkbox = $(this);
      setTimeout(function(){
        $checkbox.toggle_layer($checkbox.is(':checked'));
      }, 100);
    });


    return container;
  }

  $.fn.toggle_layer = function(show) {
    var $name = this.attr('name');
    show ? $map.addOverlay(layers[$name]) : $map.removeOverlay(layers[$name]);
  };

  $obj.init();
};

$(function(){
  $.maps();
});


