/*
* Copyright (c) 2009-2010, Travellr.com (Travellr Pty Ltd). All rights reserved.
* Unless otherwise licensed, you may not copy, create derivative works,
* or re-use any part of this file without the express permission of
* Travellr Pty Ltd.
*/

(function($) {
  $.fn.travellrMap = function(opt) {
    opt = $.extend({
      projection: {},
      url: null,
      focusMarkerId: null,
      preprocessData: function(data) { return data; },
      preloadLocations: null,
      useAnimation: !($.browser.msie || $.isMobile()),
      markerContent: function(params) {
        var content = $($.sub("\
          <div class='clickable_marker'>\
          </div>\
        ", params));
        return content;
      }
    }, opt);
    
    return this.each(function() {
      var currentMarkers = [];
      var removedMarkers = [];
      
      var self = $(this)
        .bind('cleanUpMarkers', function(e, markersToAdd) {
          var newMarkerEmphasis = {};
          $(markersToAdd).each(function(){
            newMarkerEmphasis[this.id] = (this.give_more_emphasis ? 2 : 1); // modify out of boolean
          });
      
          var remainingMarkers = [];
          var markersToRemove = [];
          
          $(currentMarkers).each(function() {
            var data = $.data(this.getContent(),'params');
            var id = data.id;
            
            if(!newMarkerEmphasis[id]) {// $.inArray(id,newMarkerIds) == -1
              // REMOVE WAS HERE
              markersToRemove.push(this);
            } else {
              remainingMarkers.push(this);
              var emphasis = newMarkerEmphasis[id];
              if(emphasis == 2) {
                $(this.content).find('.pin').addClass('larger_pin');
              } else {
                $(this.content).find('.pin').removeClass('larger_pin');
              }
            }
          });

          removedMarkers = markersToRemove;
          currentMarkers = remainingMarkers;
        })
        .bind('drawMarkers', function(e, markers) {
          var bounds = map.getBounds();
          self.trigger('cleanUpMarkers', [markers]);
          var currentMarkerObjects = $(currentMarkers).map(function() { return $.data(this.getContent(),'params'); })
          var removedMarkerObjects = $(removedMarkers).map(function() { return $.data(this.getContent(),'params'); })
          var currentMarkerIds = $(currentMarkerObjects).map(function(){return this.id;}); //$.map(currentMarkerObjects,function() { return this.id; });
          var animationBuffer = 5;
          
          $(markers).each(function() {
            var markerSelf = this;
            var content = opt.markerContent(markerSelf);
            content.data('params', markerSelf);
            
            if (this.id == self.data('focusMarkerId')) { // opt.focusMarkerId
              self.data('focus_marker', content[0]);
            }
            
            if ($.inArray(markerSelf.id, currentMarkerIds) == -1) {
              var lowestParent = null;
              
              if(self.data('justZoomed') && opt.useAnimation) {
                var lowestDepth = 0;
                $.each(currentMarkerObjects,function() {
                  if(markerSelf.left > this.left && markerSelf.right < this.right && this.depth > lowestDepth) {
                    lowestParent = this;
                    lowestDepth = this.depth;
                  }
                });
              
                $.each(removedMarkerObjects,function() {
                  if(markerSelf.left > this.left && markerSelf.right < this.right && this.depth > lowestDepth) {
                    lowestParent = this;
                    lowestDepth = this.depth;
                  }
                });
              }
              
              if(lowestParent == null) {
                var marker = new TravellrMarker(new google.maps.LatLng(markerSelf.lat, markerSelf.lng), content[0], map);                
                currentMarkers.push(marker);
                content.data('marker', marker);
              } else {
                // it came from a parent
                var startLatLng = new google.maps.LatLng(lowestParent.lat, lowestParent.lng);
                var endLatLng = new google.maps.LatLng(markerSelf.lat, markerSelf.lng);
                
                var marker = new TravellrMarker(endLatLng, content[0], map);
                
                if(bounds.contains(startLatLng)) {
                  var startPoint = marker.getProjection().fromLatLngToDivPixel(startLatLng);
                  var endPoint = marker.getProjection().fromLatLngToDivPixel(endLatLng);
                  
                  var leftDiff = startPoint.x - endPoint.x;
                  var topDiff = startPoint.y - endPoint.y;

                  $(marker.getContent())
                  .css('left',leftDiff)
                  .css('top',topDiff)
                  .animate({
                  left: 0,
                  top: 0
                  },500);
                }
                
                currentMarkers.push(marker);
                content.data('marker', marker);
              }
            } 
          });
            
          var currentMarkerObjectsPost = $(currentMarkers).map(function() { return $.data(this.getContent(),'params'); })
          // iterate the old children
            
          $(removedMarkers).each(function() {
            var markerSelf = this;
            var highestParent = null;
            
            var data = $(this.getContent()).data('params');
            
            if(self.data('justZoomed') && opt.useAnimation) {
              var highestDepth = 0;
              // the json object, retrieved from the marker

              $.each(currentMarkerObjectsPost,function() {
                if(data.left > this.left && data.right < this.right && this.depth > highestDepth) {
                  highestParent = this;
                  highestDepth = this.depth;
                }
              });
            }

            if(highestParent != null) {
              // it came from a parent
              var startLatLng = new google.maps.LatLng(data.lat, data.lng);
              var endLatLng = new google.maps.LatLng(highestParent.lat, highestParent.lng);

              if(bounds.contains(startLatLng)) {
                var startPoint = this.getProjection().fromLatLngToDivPixel(startLatLng);
                var endPoint = this.getProjection().fromLatLngToDivPixel(endLatLng);

                var leftDiff = endPoint.x - startPoint.x;
                var topDiff = endPoint.y - startPoint.y;

                $(this.getContent())
                .css('left',0)
                .css('top',0)
                .animate({
                  left: leftDiff,
                  top: topDiff
                },500,function() {
                  markerSelf.setMap(null);
                });
              } else {
                markerSelf.setMap(null);
              }
            } else {
              markerSelf.setMap(null);
            }
          });
          self.data('justZoomed', false);
          self.data('firstDrawDone', true);
        })
        .bind('getMarkers', function() {
          var bounds = map.getBounds();
        
          var params = $.extend({
            zoom: map.getZoom(),
            top: bounds.getNorthEast().lat(),
            right: bounds.getNorthEast().lng(),
            bottom: bounds.getSouthWest().lat(),
            left: bounds.getSouthWest().lng()
          }, self.data('ajaxOptions'));

          if(self.data('focusMarkerId')) {
            params.focus_marker_id = self.data('focusMarkerId');
          } 
          
          if(opt.preloadLocations != null && !self.data('firstDrawDone')) {
            // use the markers
            self.trigger('travellrMap.gotData', [opt.preloadLocations]);
            self.trigger('drawMarkers', [opt.preloadLocations]);
            self.trigger('loadFocusMarker'); // only needed for preloading
          } else {
            // load dem markers
            $.getJSON(opt.url, params, function(data) {
              data = opt.preprocessData(data);
              self.trigger('travellrMap.gotData', [data]);
              self.trigger('drawMarkers', [data]);
              self.trigger('travellrMap.dataLoaded');
            });
          }
        })
        .bind('zoomChanged',function(e){
          self.data('focusMarkerId',null);
        })
        .bind('zoomIn', function(e, latlng) {
          if (latlng) {
            map.setCenter(latlng);
          };
          self.data('autoDraw', false);
          map.setZoom(map.getZoom() + 1);
          setTimeout(function() {
            map.setZoom(map.getZoom() + 1);
            self.data('autoDraw', true);   
          },1);
        })
        .bind('reset', function() {
          map.setZoom(opt.projection.zoom);
          map.setCenter(new google.maps.LatLng(opt.projection.latitude, opt.projection.longitude));
          self.data('currentMarker', null);
        })
        .one('loadFocusMarker', function() {
          if ($.browser.msie && $.browser.version == '7.0') {
            setTimeout(function() { $(self.data('focus_marker')).click(); }, 500);
          } else {
            $(self.data('focus_marker')).click();
          }
        });

      var map = new google.maps.Map(this, {
        zoom: opt.projection.zoom,
        center: new google.maps.LatLng(opt.projection.latitude, opt.projection.longitude),
        mapTypeId: google.maps.MapTypeId.TERRAIN,
        mapTypeControl: false,
        scrollwheel: false
      });
      
      self.data('map', map);
      self.data('ajaxOptions', {});
      self.data('focusMarkerId', opt.focusMarkerId);
      self.data('autoDraw', true);
      self.data('justZoomed', false);
     
      google.maps.event.addListener(map, 'idle', function() {
        if(self.data('autoDraw')) {
          self.trigger('getMarkers');
        } 
      });
      
      google.maps.event.addListener(map, 'zoom_changed', function() {
        self.data('justZoomed', true);
        self.trigger('zoomChanged');
      });
      
      google.maps.event.addListener(map, 'center_changed', function() {
        if (self.data('currentMarker') && !self.data('map').getBounds().contains(self.data('currentMarker').getPosition())) {
          self.data('currentMarker', null);
          self.trigger('travellrMap.currentMarkerOutOfBounds');
        }
      });
      
      $('.clickable_marker').live('click', function() {      
        var marker = $(this);
        // If the marker is not currently open
        if (self.data('currentMarker') != marker.data('marker')) {
          self.data('currentMarker', marker.data('marker'));
          self.trigger('travellrMap.onMarkerClick', [marker]);
        }
      });
    });
  };
  
  function TravellrMarker(latlng, content, map) {
    this.latlng = latlng;
    this.content = content;
    this.setMap(map);
  }
  
  $(function() {
    TravellrMarker.prototype = new google.maps.OverlayView();

    TravellrMarker.prototype.onAdd = function() {
      this.div = document.createElement('DIV');
      this.div.style.position = "absolute";
      // this.div.style.zIndex = '3000';
      this.div.className = 'travellr_marker';
      this.getPanes().overlayImage.appendChild(this.div);
      this.div.appendChild(this.content);
    };

    TravellrMarker.prototype.draw = function() {
      var point = this.getProjection().fromLatLngToDivPixel(this.latlng);
      this.div.style.left = point.x + 'px';
      this.div.style.top = point.y + 'px';
    };
    
    TravellrMarker.prototype.onRemove = function() {
      this.div.parentNode.removeChild(this.div);
      this.div = null;
    };

    TravellrMarker.prototype.getPosition = function() {
      return this.latlng;
    };
    
    // Used?
    TravellrMarker.prototype.getContent = function() {
      return this.content;
    };
  });
})(jQuery);

(function($) {
  $.fn.travellrMapQuestionPopup = function(opt) {
    opt = $.extend({
      url: null,
      map: null,
      outerTemplate: "<div class='map_popup'></div>",
      nipple: "<img class='nipple' src='/images/pointer.gif' />",
      loadingContent: "Loading...",
      preprocessData: function(data) { return data; },
      innerTemplate: function(params) {
        return $.sub("\
          <div class='close'></div>\
          #{content}\
          #{nav}\
          <div class='zoom_in'><a class='zoom'>+ Zoom In</a></div>\
        ", params);
      },
      nav: function(currentItem, totalItems) {
        return $.sub("<div class='nav'>#{prev} - #{currentItem} of #{totalItems} - #{next}</div>", {
          currentItem: currentItem,
          totalItems: totalItems,
          prev: currentItem == 1 ? "Prev" : "<a class='prev'>Prev</a>",
          next: currentItem == totalItems ? "Next" : "<a class='next'>Next</a>"
        });
      },
      content: function(params) {
        // This is a bit of a hack to get around a limitation of the $.sub plugin
        if (params['content'] == "") {
          params['content'] = " ";
        }
  
        return $.sub("\
          <div class='subject'><a href='#{question_link}'>#{subject}</a></div>\
          <div class='location'><a class='location' href ='#{location_link}'>#{location_name}</a></div>\
          <div class='content'>#{content}</div>\
        ", params);
      }
    }, opt);

    return this.each(function() {
      var self = $(this);
      
      if (opt.map.data('popup')) {
        opt.map.data('popup').trigger('close');
      }
      
      var params = $.data(this, 'params');
      
      var page = 0;
      var items = [];
      var currentItem = 1;
      
      var popup = $(opt.outerTemplate)
        .bind('loadMore', function() {
          page++;
          popup.html(opt.loadingContent);
          
          $.getJSON(opt.url, $.extend({ page: page }, opt.map.data('ajaxOptions')), function(data) {
            data = opt.preprocessData(data);
            
            if (data.length > 0) {
              items = items.concat(data);
              popup.trigger('showItem');
            }
          });
        })
        .bind('showItem', function() {
          var toShow = items[currentItem - 1];
          if (toShow) {
            popup.html(opt.innerTemplate({ content: opt.content(toShow), nav: opt.nav(currentItem, params.item_count) }));
          } else {
            popup.trigger('loadMore');
          }
        })
        .bind('close', function() {
          // We don't want to remove / refresh if another marker has been clicked on.
          if (opt.map.data('currentMarker') == self.data('marker')) {
            opt.map.data('currentMarker', null);
            opt.map.trigger('getMarkers');
          }
          
          nipple.remove();
          popup.remove();
        })
        .click(function(e) {
          var target = $(e.target);
          
          if (target.hasClass('next')) {
            currentItem++;
            popup.trigger('showItem');
          } else if (target.hasClass('prev')) {
            currentItem--;
            popup.trigger('showItem');
          } else if (target.hasClass('zoom')) {
            opt.map.trigger('zoomIn', [self.data('marker').getPosition()]);
            popup.trigger('close');
          } else if (target.hasClass('close')) {
            popup.trigger('close');
          } else  if (target.is('a')) {
              window.location = target.attr('href');
          }
          
          return false;
        })
        .appendTo(self);
        
      var nipple = $(opt.nipple)
        .appendTo(self);
        
      popup.trigger('showItem');        
      opt.map.data('popup', popup);
    });
  };
})(jQuery);

(function($) {
  $.fn.travellrMapLocationPopup = function(opt) {
    opt = $.extend({
      url: null,
      map: null,
      content: null,
      outerTemplate: "<div class='map_popup'></div>",
      nipple: "<img class='nipple' src='/images/pointer.gif' />",
      loadingContent: "<span class='loading'>Loading...</span>"
    }, opt);

    return this.each(function() {
      var self = $(this);
      
      if (opt.map.data('popup')) {
        opt.map.data('popup').trigger('close');
      }
      
      var params = $.data(this, 'params');
      
      self.bind('updatePopupContents', function(e,content) {
        popup.html(content);
      });
      
      var popup = $(opt.outerTemplate)
        .bind('showLocationDetails', function() {
          if(opt.content != null) {
            popup.html(opt.content);
          } else {
            popup.html(opt.loadingContent);
            if(opt.url != null) { 
              $.get(opt.url, opt.map.data('ajaxOptions'), function(html) {
                popup.html(html);
              });
            } 
          }
        })
        .bind('close', function() {
          self.removeClass('clicked');
          // We don't want to remove / refresh if another marker has been clicked on.
          if (opt.map.data('currentMarker') == self.data('marker')) {
            opt.map.data('currentMarker', null);
            opt.map.data('focusMarkerId',null); // wipe out the focus on close
//            opt.map.trigger('getMarkers');
          }
          
          nipple.remove();
          popup.remove();
          self.trigger('closed');
        })
        .click(function(e) {
          var target = $(e.target);
          
          if (target.hasClass('zoom')) {
            opt.map.trigger('zoomIn', [self.data('marker').getPosition()]);
            popup.trigger('close');
            return false;
          } else if (target.hasClass('close')) {
            popup.trigger('close');
            return false;
          }
        })
        .appendTo(self);
      
      var nipple = $(opt.nipple)
        .appendTo(self);
      
      self.addClass('clicked');  
      popup.trigger('showLocationDetails');        
      opt.map.data('popup', popup);
    });
  };
})(jQuery);