/*
 * Ext JS Library 2.2.1
 * Copyright(c) 2006-2009, Ext JS, LLC.
 * licensing@extjs.com
 *
 * http://extjs.com/license
 */
/**
 * @author Shea Frederick
 */
Ext.namespace('Ext.ux');

Ext.isArray = function(obj)
{
   //returns true is it is an array
   if (obj && obj.constructor.toString().indexOf("Array") != -1) 
   {
      return true;
   }
   return false;
};

/**
 *
 * @class GMapPanel
 * @extends Ext.Panel
 */
Ext.ux.GMapPanel = Ext.extend(Ext.Panel, 
{
   autoUpdate: true,
   initComponent: function()
   {
   
      var defConfig = 
      {
         plain: true,
         zoomLevel: 3,
         yaw: 180,
         pitch: 0,
         zoom: 0,
         gmapType: 'map',
         border: false
      };
      
      Ext.applyIf(this, defConfig);
      
      Ext.ux.GMapPanel.superclass.initComponent.call(this);
      this.addEvents('gmapuxloaded');
      this.addEvents('locationsloaded');
      this.addEvents('recenteredmap');
      
   },
   afterRender: function()
   {
      var wh = this.ownerCt.getSize();
      Ext.applyIf(this, wh);
      
      Ext.ux.GMapPanel.superclass.afterRender.call(this);
      
      if (this.gmapType === 'map') 
      {
         this.gmap = new GMap2(this.body.dom);
      }
      
      if (this.gmapType === 'panorama') 
      {
         this.gmap = new GStreetviewPanorama(this.body.dom);
      }
      
      if (typeof this.addControl == 'object' && this.gmapType === 'map') 
      {
         this.gmap.addControl(this.addControl);
      }
      
      GEvent.bind(this.gmap, 'load', this, function()
      {
         this.onMapReady();
      });
      
      if (typeof this.setCenter === 'object') 
      {
         if (typeof this.setCenter.geoCodeAddr === 'string') 
         {
            this.geoCodeLookup(this.setCenter.geoCodeAddr);
         }
         else 
         {
            var point;
            if (this.gmapType === 'map') 
            {
               point = new GLatLng(this.setCenter.lat, this.setCenter.lng);
               this.gmap.setCenter(point, this.zoomLevel);
            }
            if (typeof this.setCenter.marker === 'object' && typeof point === 'object') 
            {
               this.addMarker(point, this.setCenter.marker, this.setCenter.marker.clear);
            }
         }
         if (this.gmapType === 'panorama') 
         {
            this.gmap.setLocationAndPOV(new GLatLng(this.setCenter.lat, this.setCenter.lng), 
            {
               yaw: this.yaw,
               pitch: this.pitch,
               zoom: this.zoom
            });
         }
      }
      
      
   },
   onMapReady: function()
   {
      this.addMapControls();
      this.addOptions();
      this.addMarkers(this.markers);
      this.fireEvent('gmapuxloaded', this);
   },
   onResize: function(w, h)
   {
   
      if (typeof this.getMap() == 'object') 
      {
         this.gmap.checkResize();
      }
      
      Ext.ux.GMapPanel.superclass.onResize.call(this, w, h);
      
   },
   setSize: function(width, height, animate)
   {
   
      if (typeof this.getMap() == 'object') 
      {
         this.gmap.checkResize();
      }
      
      Ext.ux.GMapPanel.superclass.setSize.call(this, width, height, animate);
      
   },
   getMap: function()
   {
   
      return this.gmap;
      
   },
   getCenter: function()
   {
   
      return this.getMap().getCenter();
      
   },
   getCenterLatLng: function()
   {
   
      var ll = this.getCenter();
      return {
         lat: ll.lat(),
         lng: ll.lng()
      };
      
   },
   addMarkers: function(markers)
   {
   
      if (Ext.isArray(markers)) 
      {
         var length = markers.length;
         
         for (var i = 0; i < length; i++) 
         {
            var mkr_point = new GLatLng(markers[i].lat, markers[i].lng);
            this.addMarker(mkr_point, markers[i].marker, false, markers[i].setCenter, markers[i].listeners);
         }
      }
   },
   applyInfoTemplate: function(data, compiledTpl)
   {
      data = data.split("|");
      var dataObj = {};
      var fieldCount = data.length;
      for (var x = 0; x < fieldCount; x++) 
      {
         var dataItem = data[x].split("=");
         dataObj[dataItem[0]] = dataItem[1];
      }
      dataObj.location_type = dataObj.location_type_desc;
      var icons = [];
      if (dataObj.can_rollback == "T") 
      {
         icons.push('<img src="/images/skin2/search/icon-cpg-redemption.gif" />');
      }
      if (dataObj.can_issue == "T") 
      {
         icons.push('<img src="/images/skin2/search/icon-reward-issue.gif" />');
      }
      if (dataObj.can_redeem == "T") 
      {
         icons.push('<img src="/images/skin2/search/icon-c4g-redemption.gif" />');
      }
      dataObj.icons = icons.join("&nbsp;&nbsp;&nbsp;");
      dataObj.mapDestination = dataObj.address + " " + dataObj.city + ", " + dataObj.state + " " + dataObj.zipcode;
      dataObj.mapDestination = Ext.urlEncode(dataObj.mapDestination);
      return compiledTpl.apply(dataObj);
   },
   addMarkersCheckBounds: function(markers)
   {
      if (Ext.isArray(markers)) 
      {
         var infoTemplate = Ext.XTemplate.from('location-info').compile();
         var animarray = [];
        
         
         var length = markers.length;
         var anim = false;
         
         if (arguments.length > 1) 
         {
            anim = Boolean(arguments[1]);
            if (anim === true && length > 0) 
            {
               var progressBar = new ProgressbarControl(this.getMap(), 
               {
                  width: 150
               });
               progressBar.start(length);
            }
         }
         var addMarker = function(panel, marker)
         {
            panel.getMap().addOverlay(marker);
            panel.markerList.push(marker);
            panel.markerIdList.push(marker.location_id);
         };
         
         
         for (var i = 0; i < length; i++) 
         {
            var markerData = markers[i];
            var marker = markerData.marker;
            
            if (marker && marker.image) 
            {
               var tmp = new GIcon(G_DEFAULT_ICON);
               tmp.iconSize = new GSize(12, 20);
               tmp.shadowSize = new GSize(22, 20);
               tmp.iconAnchor = new GPoint(10, 20);
               tmp.image = marker.image;
               tmp.shadow = '/images/google/icons/shadow2.png';
               //marker.icon = tmp;
               delete marker.image;
               
               marker = 
               {
                  icon: tmp
               };
            }
            marker.title = markerData.title;
            
            var mkr_point = new GLatLng(markerData.lat, markerData.lng);
            
            
            marker = this.createMarker(mkr_point, marker, false, markerData.setCenter, markerData.listeners);
            marker.location_id = markerData.location_id;
            marker.bindInfoWindowHtml(this.applyInfoTemplate(markerData.html, infoTemplate));
            marker.data = markerData;
            
            var index = this.markerIdList.indexOf(markerData.location_id);
            
            if (index == -1) 
            {
               var timeout = (i * 100);
               if (timeout > 2000) 
               {
                  timeout = (i) * (Math.random() * 20);
               }
               if (anim === true) 
               {
                  animarray.push(marker);
               }
               else 
               {
                  addMarker(this, marker);
               }
            }
         }
         if (anim === true) 
         {
            var num = this.markerList.length;
            var speed = 1;
       
            var addMarkers = (function()
            {
               var limit = Math.random() * 20 + 10;
               for (var x = 0; x < limit; x++) 
               {
                  progressBar.updateLoader(1);
                  var marker = animarray.pop();
                  addMarker(this, marker);
                  if ((num + 1) == length) 
                  {
                     x = limit;
                  }
                  num = num + 1;
               }
               if (num < length) 
               {
                  setTimeout(addMarkers, speed);
               }
               else 
               {
                  this.fireEvent('locationsloaded', this, this.markerList);
                  progressBar.remove();
                  animarray = null;
               }
               
            }).createDelegate(this);
            
            setTimeout(addMarkers, speed);
         }
         this.clearMarkersOutOfBounds();
      }
   },
   clearMarkersOutOfBounds: function()
   {
      var bounds = this.getPoints().bounds;
      var currentGLatLngBound = new GLatLngBounds(bounds.getSouthWest(), bounds.getNorthEast());
      var currentMarkers = this.markerList.length;
      
      var marker;
      var marker_location_id;
      var deleted = 0;
      for (var i = 0; i < currentMarkers; i++) 
      {
         if (this.markerList[i]) 
         {
            marker = this.markerList[i];
            marker_location_id = this.markerList[i].location_id;
            
            if (!currentGLatLngBound.containsLatLng(this.markerList[i].getLatLng())) 
            {
               marker.hide();
               this.getMap().removeOverlay(marker);
               this.markerList.remove(marker);
               this.markerIdList.remove(marker_location_id);
               
               deleted++;
            }
         }
      }
      return deleted;
      
   },
   createMarker: function(point, marker, clear, center, listeners)
   {
   
      Ext.applyIf(marker, G_DEFAULT_ICON);
      
      if (clear === true) 
      {
         this.getMap().clearOverlays();
      }
      if (center === true) 
      {
         this.getMap().setCenter(point, this.zoomLevel);
      }
      /*
       if (marker && marker.image)
       {
       var tmp = new GIcon(G_DEFAULT_ICON);
       tmp.iconSize = new GSize(12, 20);
       tmp.shadowSize = new GSize(22, 20);
       
       tmp.iconAnchor = new GPoint(6,20);
       
       tmp.image = marker.image;
       tmp.shadow = '/images/google/icons/shadow2.png';
       //marker.icon = tmp;
       delete marker.image;
       
       marker = { icon: tmp }
       }
       */
      var mark = new GMarker(point, marker);
      if (typeof listeners === 'object') 
      {
         for (evt in listeners) 
         {
            GEvent.bind(mark, evt, mark, listeners[evt]);
         }
      }
      return mark;
   },
   addMarker: function(point, marker, clear, center, listeners)
   {
   
      Ext.applyIf(marker, G_DEFAULT_ICON);
      
      if (clear === true) 
      {
         this.getMap().clearOverlays();
      }
      if (center === true) 
      {
         this.getMap().setCenter(point, this.zoomLevel);
      }
      
      
      var mark = new GMarker(point, marker);
      if (typeof listeners === 'object') 
      {
         for (evt in listeners) 
         {
            GEvent.bind(mark, evt, this, listeners[evt]);
         }
      }
      this.getMap().addOverlay(mark);
      return mark;
   },
   addMapControls: function()
   {
   
      if (this.gmapType === 'map') 
      {
         if (Ext.isArray(this.mapControls)) 
         {
            for (i = 0; i < this.mapControls.length; i++) 
            {
               this.addMapControl(this.mapControls[i]);
            }
         }
         else if (typeof this.mapControls === 'string') 
         {
            this.addMapControl(this.mapControls);
         }
         else if (typeof this.mapControls === 'object') 
         {
            this.getMap().addControl(this.mapControls);
         }
      }
      
   },
   addMapControl: function(mc)
   {
   
      var mcf = window[mc];
      if (typeof mcf === 'function') 
      {
         this.getMap().addControl(new mcf());
      }
      
   },
   addOptions: function()
   {
   
      if (Ext.isArray(this.mapConfOpts)) 
      {
         var mc;
         for (i = 0; i < this.mapConfOpts.length; i++) 
         {
            this.addOption(this.mapConfOpts[i]);
         }
      }
      else if (typeof this.mapConfOpts === 'string') 
      {
         this.addOption(this.mapConfOpts);
      }
      
   },
   addOption: function(mc)
   {
   
      var mcf = this.getMap()[mc];
      if (typeof mcf === 'function') 
      {
         this.getMap()[mc]();
      }
      
   },
   centerOnSearch: function(addr)
   {
      this.geocoder = new GClientGeocoder();
      this.geocoder.getLocations(addr, (function(response)
      {
         if (response.Status.code == 200) 
         {
            var pointInfo = response.Placemark[0].Point.coordinates;
            var point = new GLatLng(pointInfo[1], pointInfo[0]);
            this.getMap().setCenter(point, 11);
            GEvent.trigger(this.getMap(), 'zoomend');
         }
      }).createDelegate(this));
   },
   geoCodeLookup: function(addr)
   {
      this.geocoder = new GClientGeocoder();
      this.geocoder.getLocations(addr, this.addAddressToMap.createDelegate(this));
   },
   getPoints: function()
   {
      var gmap = this.getMap();
      
      var bounds = gmap.getBounds();
      
      var north = bounds.getNorthEast().y;
      var east = bounds.getNorthEast().x;
      var south = bounds.getSouthWest().y;
      var west = bounds.getSouthWest().x;
      
      var zoom = gmap.getZoom();
      
      return {
         bounds: bounds,
         zoom: zoom,
         north: north,
         east: east,
         south: south,
         west: west
      };
   },
   clearAll: function()
   {
      this.clearLastValues();
      this.clearMarkerList();
      this.getMap().clearOverlays();
      
   },
   markerList: [],
   markerIdList: [],
   clearMarkerList: function()
   {
      this.markerList = [];
      this.markerIdList = [];
   },
   setLastValues: function()
   {
      this.getMap().lastPoints = this.getPoints();
   },
   getLastValues: function()
   {
      return this.getMap().lastPoints;
   },
   clearLastValues: function()
   {
      this.getMap().lastPoints = undefined;
   },
   addAddressToMap: function(response)
   {
   
      if (!response || response.Status.code != 200) 
      {
         Ext.MessageBox.alert('Error', 'Code ' + response.Status.code + ' Error Returned');
      }
      else 
      {
         place = response.Placemark[0];
         addressinfo = place.AddressDetails;
         accuracy = addressinfo.Accuracy;
         if (accuracy === 0) 
         {
            Ext.MessageBox.alert('Unable to Locate Address', 'Unable to Locate the Address you provided');
         }
         else 
         {
            if (accuracy < 7) 
            {
               Ext.MessageBox.alert('Address Accuracy', 'The address provided has a low accuracy.<br><br>Level ' + accuracy + ' Accuracy (8 = Exact Match, 1 = Vague Match)');
            }
            else 
            {
               point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
               if (typeof this.setCenter.marker === 'object' && typeof point === 'object') 
               {
                  this.addMarker(point, this.setCenter.marker, this.setCenter.marker.clear, true, this.setCenter.listeners);
               }
            }
         }
      }
      
   },
   addPointsFromUrl: function(url, appendParams)
   {
      var gmap = this.getMap();
      // Get our last bounds to see if we need to dodge any areas we already have.
      
      var params = this.getPoints();
      params.type = 'kson';
      
      for (var x in appendParams) 
      {
         params[x] = appendParams[x];
      }
      var anim = false;
      if (arguments.length > 2) 
      {
         anim = Boolean(arguments[2]);
      }
      
      
      Ext.Ajax.method = 'GET';
      Ext.Ajax.request(
      {
         url: url,
         success: function(response, request)
         {
            var resultObject = Ext.decode(response.responseText);
            this.addMarkersCheckBounds(resultObject.markers, anim);
            this.clearMarkersOutOfBounds();
            this.fireEvent('locationsloaded', this, this.markerList);
         },
         scope: this,
         params: params
      });
      
   }
   
});

Ext.reg('gmappanel', Ext.ux.GMapPanel);

