
var YouMarker = Class.create({
    
    // Takes a YouMap object, a type string and an initial object
    // (e.g. JSON'd PropertyMarketStatus)
    // Can add extra objects by adding to o.objects array
    
  initialize: function(you_map, type, obj, options)
  {
    this.you_map = you_map; // you_map ref in this object
    this.type = type;       // e.g. 'listing' or 'poi'
    this.objects = [];
    this.objects[0] = obj;  // e.g. listing or poi object
    this.options = options;
    
    // set latitude and longitude
    this.glatlng = new GLatLng(Number(this.objects[0].lat), 
                               Number(this.objects[0].lng));
    
    this.you_map[type + '_markers'].push(this); // add myself to the array of markers in the YouMap
    this.setup_gmarker();  // setup google marker with appropriate icon
    this.show();           // add the marker to the google map
    
    var m = this;
    
    GEvent.addListener(this.gmarker, 'mouseover', this.highlight.bind(this));
    GEvent.addListener(this.gmarker, 'mouseover', this.highlight_all_in_table.bind(this));
    
    // unhighlight - breaks in IE6
    //GEvent.addListener(this.gmarker, 'mouseout', this.unhighlight.bind(this));
    
    // open info windows
    GEvent.addListener(this.gmarker, 'click', this.open_info_window.bind(this));
    GEvent.addListener(this.gmarker, 'infowindowopen', function()
    {
      if ($('show_blowup')) {
        $('show_blowup').observe('click', function(event)
        {
          event.stop();
          m.gmarker.showMapBlowup({zoomLevel: 19, mapType: G_HYBRID_MAP });
          m.highlight();
        });
      }
    });
    
    // dragged markers get a menu
    GEvent.addListener(this.gmarker, 'dragend', function()
    {
      var p = this.getPoint();
      this.openInfoWindowHtml('<p><strong>Marker dragged to new location</strong></p>' +
                              '<p>What would you like to do?</p>' +
                              '<ul>' +
                              '<li><a href="#" id="confirm_update">Use New Location</a></li>' + 
                              '<li><a href="#" id="cancel_update">Cancel</a></li>' + 
                              '</ul>'
                              );

      // Problem: the $('confirm_update') item can't be found
      // Need to wait until openInfoWindowHtml has completed
      // - The onOpenFn option doesn't seem to work'
      // - setTimeout also seems to have problems
      // - Is possible related to a version specific bug in google maps
      //
      //
      // Here is an ugly work around: sleep until $('confirm_update') exists
      m.define_move_observers(m, 500);
    });
  },

  define_move_observers: function(m, timeout) {
    var new_timeout = timeout * 2;
    // alert( "define_move_observers: "+timeout);
    if ($('confirm_update')) {

      $('confirm_update').observe('click', function(event)
      {
        event.stop();
        m.you_map.map.closeInfoWindow();
        m.update_lat_lng();
      });

      $('cancel_update').observe('click', function(event)
      {
        event.stop();
        m.you_map.map.closeInfoWindow();
        m.cancel_move.bind(m);
      });

    }
    else {
      setTimeout( m.define_move_observers, new_timeout, m, new_timeout );
    }

  },
      
  // displays an info window to the effect that something was cancelled
  // and resets the info window to its original location
  // bind a YouMarker to this function!
  //
  cancel_move: function(e, message)
  {
    if (!message) {
      message = 'Cancelled';
    }
      
    this.gmarker.setPoint(this.glatlng);
    this.update_lat_lng();
    this.gmarker.openInfoWindowHtml('<p>' + message + '</p>');
    e.stop();
  },
      
      
  set_point: function(lat, lng)
  {
    this.glatlng = new GLatLng(Number(lat), Number(lng));
    this.gmarker.setPoint(this.glatlng);
  },
      
      
  // set latitude and longitude fields to a new value
  update_lat_lng: function()
  {
    var p = this.gmarker.getPoint();
    var lat = $('lat');
    var lng = $('lng');
    
    lat.value = p.lat();
    lng.value = p.lng();
    
    lat.highlight();
    lng.highlight();
    
    this.zoom();
  },
      
      
  // type-dependent google marker + icon setup
  setup_gmarker: function(highlight)
  {
    var icon = new GIcon();
    
    if (this.type == 'property'
        || this.type == 'listing'
        || this.type == 'letting'
        || this.type == 'adc_property'
        || this.type == 'adc_planning_application') {
      object_icon = this.objects[0].icon;
        
      if (this.options && this.options.initial_state == 'lowlight') {
        icon.image = object_icon.image_lowlight;
      }
      else {
        icon.image = object_icon.image_highlight;
      }
      
      icon.iconSize   = new GSize(object_icon.size[0], object_icon.size[1]);
      icon.iconAnchor = new GPoint(object_icon.anchor[0], object_icon.anchor[1]);
      icon.infoWindowAnchor = new GPoint(object_icon.info_window_anchor[0],
                                         object_icon.info_window_anchor[1]);
      
      if (object_icon.shadow) {
        icon.shadow = object_icon.shadow;
        icon.shadowSize = new GSize(object_icon.shadow_size[0], 
                                    object_icon.shadow_size[1]);
      }
    }
    else {
      image_path = '/images/marker_' + this.objects[0].type_handle + '.png';
      icon.image = image_path;
      icon.iconSize   = new GSize(20, 20);
      icon.iconAnchor = new GPoint(10, 10);
      icon.infoWindowAnchor = new GPoint(10, 10);
    }

    opts = {};
    
    // enable icon / dragging as appropriate
    if (icon) {
      opts.icon = icon;
    }
    
    if (this.you_map.draggable_markers) {
      opts.draggable = true;
    }
    
    this.gmarker = new GMarker(this.glatlng, opts);
    if (this.you_map.draggable_markers) {
      this.gmarker.enableDragging();
    }
    
    if (this.type == 'listing' || this.type == 'property') {
      // unhighlight the icon when info windows are closed
      GEvent.addListener(this.gmarker, 'infowindowclose', 
                         this.unhighlight.bind(this));
    }
  },
      
  // return the current latitude of the marker
  lat: function()
  {
    return this.gmarker.getPoint().lat();
  },
      
  // return the current longitude of the marker
  lng: function()
  {
    return this.gmarker.getPoint().lng();
  },

  // zoom to this marker
  zoom: function()
  {
    this.you_map.center(this.lat(), this.lng(), 17);
  },
      
  // removes overlay
  hide: function()
  {
    this.you_map.map.removeOverlay(this.gmarker);
  },
      
  // add overlay
  show: function()
  {
    this.you_map.map.addOverlay(this.gmarker);
  },
      
  // returns true if it's safe to e.g. highlight
  no_info_window_open: function()
  {
    return this.you_map.no_info_window_open();
  },
      
  // set all markers to be grey except for us - red
  highlight: function(override)
  {
    // alert("+ highlight");
    
    if (this.type != 'listing'
        && this.type != 'letting'
        && this.type != 'property') {
      // alert("- highlight 1");
      return false;
    }
    
    if (this.no_info_window_open() || override) {
      this.you_map[this.type + '_markers'].each(function(m)
      {
        m.gmarker.setImage(m.objects[0].icon.image_lowlight);
      });
      this.gmarker.setImage(this.objects[0].icon.image_highlight);
    }
    
    // alert("- highlight 2");
  },
      
  // set all markers of our type to be lowlighted
  // unset highlight class for all list items in results
  unhighlight: function()
  {
    // alert ("= unhighlight");
    
    if (this.type != 'listing'
        && this.type != 'letting'
        && this.type != 'property') {
      return false;
    }
    
    if (this.no_info_window_open()) {
      this.you_map[this.type + '_markers'].each(function(m)
      {
        m.gmarker.setImage(m.objects[0].icon.image_lowlight);
      });
      try {
        $$('.property_list>li').each(function(el)
        {
          el.removeClassName('highlight');
        });
      }
      catch(err) {
      }
    }
  },

      
  unhighlight_table: function()
  {
    // alert("= unhighlight_table");
    
    $$('.property_list>li').each(function(el)
    {
      el.removeClassName('highlight');
    });
  },
      
  // only for YOU Know results table functionality
  highlight_in_table: function(id)
  {
    try {
      if (this.type == 'listing'
          || this.type == 'letting'
          || this.type == 'property') {
        this.unhighlight_table();
        $('property_' + id).addClassName('highlight');
      }
    }
    catch(err) {
    }
  },

      
  highlight_all_in_table: function()
  {
    // alert("= highlight_all_in_table");
    
    if($('results')) {
      // alert("= highlight_all_in_table + results");
      
      var first_in_list;
      var lowest_offset;
      
      if ((this.type == 'listing' || this.type == 'letting' || this.type == 'property')
          && this.no_info_window_open()) {
        // remove highlighting first
        this.unhighlight_table();
        
        this.objects.each(function(o)
                          {
                            this_offset = $('property_' + o.id).cumulativeOffset().top;
                            if (!lowest_offset || this_offset < lowest_offset) {
                              lowest_offset = this_offset;
                              first_in_list = o;
                            }
                          });
        
        // scroll to first in list
        $('results').scrollTop = lowest_offset - ($('results').getHeight());
        
        // add highlighting to relevant items
        this.objects.each(function(o)
                          {
                            $('property_' + o.id).addClassName('highlight');
                          });
      }
    }
  },
  
  
  // open info windows on a per-object basis
  //
  open_info_window_for_id: function(id)
  {
    var obj = this.find_object(id);
    if (this.type == 'listing') {
      this.open_info_window_for_id_ajax(id, listing_popup_url);
    }
    else if (this.type == 'letting') {
      this.open_info_window_for_id_ajax(id, letting_popup_url);
    }
    else if (this.type == 'property') {
      this.open_info_window_for_id_ajax(id, reference_address_popup_url);
    }
    else {
      this.open_info_window_for_id_old(id);
    }
  },
  
  
  open_info_window_for_id_old: function(id)
  {
    var obj = this.find_object(id);
    var html;
    var m = this; 
    
    if (this.is_tabbed()) {
      html = obj.info_window + 
        '<p><a href="#" id="back_to_list">' +
        '« List of items</a></p>'; 
    }
    else {
      html = this.objects[0].info_window;
    }
    
    html += '<p><a href="#" id="show_blowup">Aerial Photo</a></p>';
    
    this.gmarker.openInfoWindowHtml(html);
    
    // highlight results
    if (this.is_tabbed()) {
      this.highlight_in_table(obj.id);
    }
    else {
      this.highlight_in_table(this.objects[0].id);
    }
    
    if ($('show_blowup')) {
      $('show_blowup').observe('click',
                               function(event)
                               {
                                 event.stop();
                                 m.gmarker.showMapBlowup({
                                   zoomLevel: 19,
                                   mapType: G_HYBRID_MAP
                                 });
                                 m.highlight();
                               });
    }
      
    if ($('back_to_list')) {
      $('back_to_list').observe('click',
                                function(event)
                                {
                                  event.stop();
                                  m.open_info_window(); 
                                });
    }
    this.highlight(true);
  },
      

  // open info windows on a per-object basis
  open_info_window_for_id_ajax: function(id,url)
  {
    var obj = this.find_object(id);
    var html;
    var m = this; 
    
    //get all the ids of the objects in this marker
    var ids=new Array();
    this.objects.each(function(obj) { ids.push(obj.id);});
    
    new Ajax.Request(url, {
      method:'get',
      parameters : { 'ids':ids.toString()},
      onSuccess: function(transport) {
                         //show the window
                         var bubble_contents=transport.responseText;
                         m.gmarker.openInfoWindowHtml(bubble_contents);
                         //turn the show aerial view link into a javascript link
                         if ($('show_blowup')) {
                           $('show_blowup').observe('click',
                                                    function(event)
                                                    {
                                                      event.stop();
                                                      m.gmarker.showMapBlowup({
                                                        zoomLevel: 19,
                                                            mapType: G_HYBRID_MAP
                                                            });
                                                      m.highlight();
                                                    });
                         }
                         // highlight relevent results in the table
                         if (this.is_tabbed()) {
                           this.highlight_in_table(obj.id);
                         }
                         else {
                           this.highlight_in_table(this.objects[0].id);
                         }
                       }//end of on success
      });
    this.highlight(true);
  },
      
  // wrapper to open info windows on a per-marker basis
  // takes optional id to find the appropriate tab to open on
  open_info_window: function(id)
  {
    this.open_info_window_for_id(id);  
    this.highlight(true);
  },
      
  // return array of ginfowindowtabs
  tabs: function()
  {
    return this.objects.collect(function(obj) {
                                  return new GInfoWindowTab(obj.title, obj.info_window);
                                });
  },
    
  // return boolean indicating whether tabs are in use (yet)
  is_tabbed: function()
  {
    return this.objects.size() > 1;
  },
      
    
  tab_index_for: function(id)
  {
    var return_index;
    this.objects.each(function(obj, index)
                      {
                        if (obj.id == id) {
                          return_index = index;
                        }
                      });
    return return_index;
  },
      
  // add a tab given an JSONned object
  add_tab: function(obj)
  {
    this.objects.push(obj);
    if (this.type == 'property' ) {
      this.objects = this.objects.sort(function(a,b)
                                       {
                                         if (a.title) {
                                           int_a = parseInt(a.title.split(' ').last());
                                         }
                                         else {
                                           int_a = 0;
                                         }
                                         
                                         if (b.title) {
                                           int_b = parseInt(b.title.split(' ').last());
                                         }
                                           else {
                                             int_b = 0;
                                           }
                                         
                                         return ((int_a < int_b) ? -1 : ((int_a > int_b) ? 1 : 0));
                                       });
    }
  },
      
  // return object given its id
  find_object: function(id)
  {
    return this.objects.find( function(obj) { return obj.id == id });
  }
});
