/**
 * Javascript functions for google map
 *
 * @version $Id: retailers.js 38770 2008-06-12 01:52:56Z achilcott $
 * 
 * Note:
 * Global variables start from the letter 'my'
 * Capital valiables are constant.
 */

// Google instances
var myMap;        // google myMap object
var myGIcon;      // google marker icon object
var myGOpt;       // google myMap option object BUT NOT WORKING
var myGeoCoder;   // google myGeoCoder object

// Global variables
var myParentId;   // Database gmap_point_category.parent_id
var myZoom;       // To hold default zoom
var myPoints         = new Object(); // to hold received points
var myPointsForState = new Object(); // to hold received points for state level view
var myCats           = new Object(); // to hold received categories

// Constants
var ALERT_NOADDRESS_MATCH = "No matching address.\nPlease check your address and try again.";
var ALERT_ADDRESS_ERROR   = "Please type your postcode and try again.";
var ALERT_GOOGLE_ERROR    = "Google Map is temporary unavailable."
var WIDE_LEVEL_ZOOM = 9;


/**
 * loading map and markes
 * Called when page is opend
 * @param Object  GLatLng for center point
 * @param Integer zoom level
 */
function load(defpoint, zoom)
{
   if (GBrowserIsCompatible())
   {
      myCats = _getCat(myParentId);

      // Create a new GMapOptions object (instantiated as an object literal)
      var mapOptions =
      {
         // Map types (also gives us the white buttons in the top right hand corner.
         mapTypes: [G_NORMAL_MAP, G_HYBRID_MAP, G_SATELLITE_MAP]
      };

      myMap = new GMap2(document.getElementById('map'),mapOptions);

      /* TODO: myGOpt does not work... */
      myGOpt = myMap.getInfoWindow();
      myGOpt.maxWidth = 180;
      myGeoCoder = new GClientGeocoder();

      /* use same icon for all PoI */
      _createIcon();

      // Adds myMap Controls
      myMap.addControl(new GSmallMapControl());
      myMap.addControl(new GMapTypeControl());

      // Sets the position
      myMap.setCenter(defpoint, zoom);

      // Sets events
      GEvent.addListener(myMap, "moveend", function()
      {
         _decidePoints();
      });
      GEvent.addListener(myMap, "zoomend", function()
      {
         _hidePointsForState();
         _decidePoints();
      });

      _decidePoints();
   }
}

/**
 * Instanciating Icon object
 */
function _createIcon()
{
   myGIcon = new GIcon();
   myGIcon.image = "/images/gmap_icon.png";
   myGIcon.iconSize = new GSize(21, 32);
   myGIcon.iconAnchor = new GPoint(11, 32);
   myGIcon.infoWindowAnchor = new GPoint(11, 0);
   myGIcon.shadow = "/images/gmap_icon_shadow.png";
   myGIcon.shadowSize = new GSize(44, 33);
}

/**
 * decide which point should get
 */
function _decidePoints()
{
   if(myMap.getZoom() <= WIDE_LEVEL_ZOOM)
   {
      _getPointsForState(myParentId,((document.getElementById("p"))?document.getElementById("p").value:"0"));
   }
   else
   {
      _getPoints(myParentId,((document.getElementById("p"))?document.getElementById("p").value:"0"));
   }
}

/**
 * Get points (Marker or Icon) by parent ID
 * @param Integer parentId
 * @param Integer mType merchandise type 1 = pre-paid, 2 = modems
 */
function _getPoints(parentId, mType)
{
   if(typeof(myMap) != typeof(new Object())) return;
   _pleaseWait(true);

   // receive the difference only
   var bounds = myMap.getBounds();
   var southWest = bounds.getSouthWest();
   var northEast = bounds.getNorthEast();

   _sendRequest("retailers_ajax.php",
      ("action=getPoints"
         +"&id="+parentId
         +"&p="+mType
         +"&preferred="
         +"&diffOnly=1"
         +"&NELG="+northEast.lng()
         +"&SWLG="+southWest.lng()
         +"&NELT="+northEast.lat()
         +"&SWLT="+southWest.lat()),
      _getPointsCB);
}

/**
 * Call back function for _getPoints
 * Converting response to HTML
 * @param Object AJAX response
 */
function _getPointsCB(response)
{
   if(!response.responseText)
   {
      _pleaseWait(false);
      return false;     
   }  

   var tempObj;
   tempObj = _eval4Json(response);
   
   // get which categories are checked.
   var nowChecked = _convertCheckbox2Ary();
   
   setAryIndexOf();

   // converting tempObj to PlaceOfInterest object
   for(var i in tempObj)
   {
      var row = tempObj[i];
      var catId = row['cat'];

      if(!catId) continue; // chekcing cat because json.js returns some rubish(?)
      
      if(!myPoints[catId]) myPoints[catId] = new Object;
      var title = "(click for detail)";
      if(myCats[catId] && myCats[catId]['label']) title = myCats[catId]['label']+" "+title;
     
      myPoints[catId][row['id']] = new PlaceOfInterest(row['id']
         , catId
         , row['lt']
         , row['lg']
         , title);

      // if this category is checked show
      if(nowChecked.indexOf(catId) > -1)
      {
         if(myPoints[catId][row['id']].showOnMap)
            myPoints[catId][row['id']].showOnMap();
      }
   }

   _pleaseWait(false);
}

/**
 * Get points (Marker or Icon) by parent ID for state view
 * @param Integer parentId
 * @param Integer mType merchandise type 1 = pre-paid, 2 = modems
 */
function _getPointsForState(parentId, mType)
{
   if(typeof(myMap) != typeof(new Object())) return;
   _pleaseWait(true);

   // clear all markers then get 1 marker per state.
   myMap.clearOverlays();
   
   _sendRequest("retailers_ajax.php",
      ("action=getPointsForState"
         +"&id="+parentId
         +"&p="+mType
         +"&preferred="),
      _getPointsForStateCB);
}

/**
 * Get points (Marker or Icon) by parent ID for state view
 * @param Integer parentId
 * @param Integer mType merchandise type 1 = pre-paid, 2 = modems
 */
function _hidePointsForState()
{
   if(myMap.getZoom() <= WIDE_LEVEL_ZOOM) return;

   for(var i in myPointsForState)
   {
      if(myPointsForState[i].hideOnMap)
         myPointsForState[i].hideOnMap();
   }
}

/**
 * Call back function for _getPointsForState
 * Converting response to HTML
 * @param Object AJAX response
 */
function _getPointsForStateCB(response)
{
   if(!response.responseText)
   {
      _pleaseWait(false);
      return false;     
   }  

   var tempObj;
   tempObj = _eval4Json(response);

   // converting tempObj to PlaceOfInterest object
   for(var i in tempObj)
   {
      var row = tempObj[i];
      if(!row['id']) continue; // chekcing cat because json.js returns some rubish(?)

      if(!myPointsForState[row['id']])
      {
         myPointsForState[row['id']] = new PlaceOfInterest(row['id']
            , row['cat']
            , row['lt']
            , row['lg']
            , "Please click to ZOOM IN");
      }

      if(myPointsForState[row['id']].showOnMap)
         myPointsForState[row['id']].showOnMap();
   }

   _pleaseWait(false);
}

/**
 * Get all category information (image, label etc.)
 * @param  Integer parentId
 * @param  Boolean showFewShops
 * @return Object  category object (associated array)
 */
function _getCat(parentId)
{
   response = _sendRequest("retailers_ajax.php", ("action=getCat&id="+parentId));

   if(!response.responseText)
   {
      return false;     
   }  

   return _eval4Json(response);
}

/**
 * Get a point (Marker or Icon)
 * @param Integer id
 */
function _getPoint(id)
{
   // Note: IE6 cache the AJAX result, so should be all right if this is called always.
   response = _sendRequest("retailers_ajax.php", ("action=getOne&id="+id));

   if(!response.responseText)
   {
      return false;     
   }  

   tempObj = _eval4Json(response);
   
   return tempObj;
}

/**
 * Call back function for _getPoint
 * Converting response to HTML
 * @param Object response AJAX
 */
function getTab(id)
{
   var row = _getPoint(id);
   var cat = myCats[row['category_id']];

   //delete unnecessary lines
   var tab1 = "<div class='gmapTab whereami-tab-about'><h3>"+cat['label']+"</h3><h4>"+row['title']+"</h4>";
   if(cat['image_url'])
      tab1 += "<img src=\""+cat['image_url']+"\" alt=\"\" align='right'/>";
   tab1    += "</div>"
  
   var tab2                   = "<div class='gmapTab whereami-tab-contact'>";
   if(row['telephone']) tab2 += "<div><span class='label'>Phone: </span><span>"+row['telephone']+"</span></div>"
   if(row['fax'])       tab2 += "<div><span class='label'>Fax: </span><span>"+row['fax']+"</span></div>"
                        tab2 += "<div class='label'>Address: </div>"
   if(row['addr1'])     tab2 += "<div class='value'>"+row['addr1']+"</div>"
   if(row['addr2'])     tab2 += "<div class='value'>"+row['addr2']+"</div>"
                        tab2 += "<div class='value'>"
   if(row['town'])      tab2 += ""+row['town']+" "
   if(row['state'])     tab2 += ""+row['state']+" "
   if(row['postcode'])  tab2 += ""+row['postcode']
                        tab2 += "</div>"
                        tab2 += "</div>"

   return [new GInfoWindowTab("About", tab1),new GInfoWindowTab("Contact", tab2)];
}
/**
 * Object which holds PoI properties
 * @param Integer id (primary key of gmap_point)
 * @param Integer category_id
 * @param String  title
 * @param float   latitude
 * @param float   longitude
 * @param String  tab1 HTML for Tab 1
 * @param String  tab2 HTML for Tab 2
 */
function PlaceOfInterest(id,category_id,latitude,longitude,title)
{
   if(!latitude && !longitude) return;
   
   this.id                   = id;
   this.category_id          = category_id;
   this.latitude             = latitude;
   this.longitude            = longitude;
   this.GLatLng              = new GLatLng(latitude,longitude);
   if(title)
   {
      this.title             = title;
   }
   this.GMarker              = new GMarker(this.GLatLng, {icon:myGIcon, title:this.title});
   this.GMarker.infoVisible  = true;
   this.GMarker.poi          = this;


   this.click_handler = GEvent.addListener(this.GMarker, "click", function() {
      if (this.infoVisible)
      {
         if(myMap.getZoom() <= WIDE_LEVEL_ZOOM)
         { // then zoom and change center
            myMap.setCenter(this.poi.GLatLng, myZoom);
         }
         else
         {
            var tab = getTab(this.poi.id);
            this.openInfoWindowTabsHtml(tab, myGOpt);
         }
      }
   });

   this.showOnMap = function()
   {
      myMap.addOverlay(this.GMarker);
   }

   this.hideOnMap = function()
   {
      myMap.removeOverlay(this.GMarker);
   }
}

/**
 * show mini window which contains address sugestion
 * @param  String  address
 * @return boolean google getLocations result
 */
function showAddress(address)
{
   if(showAddress.arguments[1]) address = decodeURI(address);
  
   if (myGeoCoder)
   {
      address = _addressWrapper(address);

      myGeoCoder.getLocations
      (
         address,
         function(response)
         {
            if (!response || response.Status.code != 200 || !response.Placemark.length)
            {
               alert(ALERT_NOADDRESS_MATCH);
               return false;
            }

            // Filter: Limit search results to Australia, this is done by checking if the returned responses are within the Australia latlong boundary
            var austBoundary = new GLatLngBounds( new GLatLng(-43.7, 112.5), new GLatLng(-10.5, 154) )
            var austPlaces = new Array();

            for(var i=0; i<response.Placemark.length; i++)
            {
               var place = response.Placemark[i];
               var point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]); 
               
               if(
                  place.AddressDetails.Accuracy >= 4 && 
                  place.address != address &&
                  austBoundary.containsLatLng ( point )
               )
                  austPlaces.push( [ place.address, point ] );
            }


            if(austPlaces.length == 0)
            {
            
               alert(ALERT_ADDRESS_ERROR);
               return false;
               
            }
            else if ( austPlaces.length == 1 )
            {
                       
               var currentZoom = myMap.getZoom();
               if(currentZoom != myZoom)
               {
                  myMap.setCenter(austPlaces[0][1], myZoom);
                  changeVisibility();
               }
               else
               {
                  myMap.panTo(austPlaces[0][1]);
               }   
               return true;
                            
            }
            else // if(austPlaces.length > 1)
            {
               var contents = "<div class=\"close click\" onClick=\"javascript:hideLayer('multiAddress');\">[X]</div>\n"
               var tmpContents = ""
               contents += "<div class=\"text\">Did you mean:</div>\n";
               contents += "<ul>\n";              
              
               for(var i=0; i<austPlaces.length; i++)
               {
                  tmpContents += _listWrapper( austPlaces[i][0] );
               }

               contents += tmpContents+"</ul>\n";

               showMiniWindow("multiAddress", contents);
                 
               return false;
            }

         }
      );
   }
   else
   {
      alert(ALERT_GOOGLE_ERROR);
      return false;
   }
}

/**
 * convert given address to google friendly format
 * @param  String address
 * @return String address
 */
function _addressWrapper(address)
{
   if(address != "" && address.indexOf("Australia") < 0)
      address += " Australia";

   return address;
}

/**
 * convert given wrapped address to original address
 * @param  String address
 * @return String address
 */
function _addressUnWrapper(address)
{
   if(address != "")
   {
      re = new RegExp("(,| |, )Australia", "i");
      address = address.replace(re, "");
   }

   return address;
}

/**
 * convert given address for HTML li tag
 * @param  String address
 * @return String address
 */
function _listWrapper(adddress)
{
   if(adddress != "")
   {
      adddress = _addressUnWrapper(adddress);
      addressEncoded = encodeURI(adddress);
      adddress = "<li class=\"click\" onClick=\"showAddress('"+addressEncoded+"', true);hideLayer('multiAddress');\">"+adddress+"</li>\n";
   }

   return adddress;
}

/**
 * check document.retailerFinder.category_id checkbox element
 * @param  Object checkbox element
 */
function chkAll(elm)
{
   // This actions is sometimes slow, so prevent duble click.
   elm.disabled = true;
   _pleaseWait(true);

   var checkboxObjs = document.retailerFinder.category_id;
  
   if(elm.checked) _checkAll(checkboxObjs);
   else _uncheckAll(checkboxObjs);

   _pleaseWait(false);
   elm.disabled = false;
}

/**
 * check given checkbox element
 * @param  Object checkbox element
 */
function _checkAll(checkboxObjs)
{
   for(var i=0; i<checkboxObjs.length; i++)
   {
      checkboxObjs[i].checked = true;
   }

   if(myMap.getZoom() <= WIDE_LEVEL_ZOOM) return;

   changeVisibility();
}

/**
 * uncheck given checkbox element
 * @param  Object checkbox element
 */
function _uncheckAll(checkboxObjs)
{
   for(var i=0; i<checkboxObjs.length; i++)
   {
      checkboxObjs[i].checked = false;
   }
  
   if(myMap.getZoom() <= WIDE_LEVEL_ZOOM) return;

   myMap.clearOverlays();
}

/**
 * decide show or hide by given checkbox
 * @param  Object checkbox element
 */
function changeVisibility(checkboxObj) //if checkboxObj is null, check all checkbox
{
   if(myMap.getZoom() <= WIDE_LEVEL_ZOOM) return;

   myMap.closeInfoWindow();
   var checkboxObjs = (checkboxObj)?[checkboxObj]:document.retailerFinder.category_id;

   for(var i=0; i<checkboxObjs.length; i++)
   {
      var catId = checkboxObjs[i].value;
      var bol = checkboxObjs[i].checked;
     
      if(myPoints[catId])
      {
         var pointsByCat = myPoints[catId];
        
         for (var pid in pointsByCat)
         {
            if(bol)
            {
               if(pointsByCat[pid].showOnMap)
                  pointsByCat[pid].showOnMap();
            }
            else
            {
               if(pointsByCat[pid].hideOnMap)
                  pointsByCat[pid].hideOnMap();
            }
         }
      }
   }
}

/**
 * convert checkbox to array
 * @param  Object checkbox element
 * @return Array
 */
function _convertCheckbox2Ary(checkboxObj) //if checkboxObj is null, check all checkbox
{
   var checkboxObjs = (checkboxObj)?[checkboxObj]:document.retailerFinder.category_id;
   var rtn = new Array();

   for(var i=0; i<checkboxObjs.length; i++)
   {
      if(checkboxObjs[i].checked)
      {
         rtn[rtn.length] = checkboxObjs[i].value;
      }
   }
   
   return rtn;
}

/**
 * AJAX funcion: Send request to external page
 * Require createHttpRequest
 *
 * @param   String  url             External page
 * @param   String  value_str       value (eg. a=1&b=2&c=3...)
 * @param   Object  funcForSuccess  Call back function)
 * @param   Boolean aSync           
 * @param   String  get_post        Method (get or post)
 * @param   Boolean cache           Empty or any value. Default true means using cache.
 * @param   Boolean encode          Empty or any value. Default false means do not encode
 * @since   2005/08/30
 */
function _sendRequest() {
   var url = _sendRequest.arguments[0];
   var value_str = "";
      if(_sendRequest.arguments[1]) value_str = _sendRequest.arguments[1];
   var funcForSuccess = false;
      if(_sendRequest.arguments[2]) funcForSuccess = _sendRequest.arguments[2];
   var aSync = true;
      if(!funcForSuccess) aSync = false;
      else if(_sendRequest.arguments[3]) aSync = _sendRequest.arguments[3];
   var get_post = "GET";
      if(_sendRequest.arguments[4]) get_post = _sendRequest.arguments[4];
   var cache = true;
      if(_sendRequest.arguments[5]) cache = _sendRequest.arguments[5];
   var encode = false;
      if(_sendRequest.arguments[6]) encode = _sendRequest.arguments[6];

   var tmpResult = "";
   var err_msg = "";
   var ua = navigator.userAgent;
   var safari   = ua.indexOf("Safari")!=-1;
   var mozes = ((a=navigator.userAgent.split("Gecko/")[1] )?a.split(" ")[0]:0) >= 20011128;
   
   if(url == '')
   {
      alert("Error no argument.\n");
      return false;
   }

   /* AJAX */
   var request = _createHttpRequest();

   if(safari || mozes)
   {
      request.onload = function ()
      {
         if(funcForSuccess)
         {
            /* callback function for success */
            funcForSuccess(request);
         }
         else
         {
            tmpResult = request;
         }
      }
   }
   else
   {
      request.onreadystatechange = function()
      {
         if ( request.readyState == 4 )
         {
            //if error status (cf 0 = uninitialized, 1 = loading, 2 = loaded, 3 = interactive, 4 = complete)
            if (request.status != 200)
            {
               /* callback function/procedure for false */
               err_msg += "Error retrieving the data:\n" + request.status
                  + " | " + request.statusText
                  + " | " + url +"\n";
            }
            else if(funcForSuccess)
            {
               /* callback function for success */
               funcForSuccess(request);
            }
            else
            {
               tmpResult = request;
            }
         }
      }
   }



   // if cache is blank, force to get new data
   if(cache)
   {
      if(url.indexOf("?") > 0) url = url + "";
      else url = url + "?";
   }
   else
   {
      var tmp_date = new Date();

      if(url.indexOf("?") > 0) url = url + "&ms=" + tmp_date.getUTCMilliseconds()+"&";
      else url = url + "?ms=" + tmp_date.getUTCMilliseconds()+"&";
   }

   // Note: Both POST and GET need to encode
   var enc_value = '';
   if(encode) {
      var value_ary = value_str.split('&');
     
      for(i=0;i<value_ary.length;i++) {
         var value_ary_ary = value_ary[i].split('=');
         enc_value += '&'+encodeURIComponent(value_ary_ary[0])+'='+encodeURIComponent(value_ary_ary[1]);
      }
   }
   else enc_value = value_str;

   if(get_post == 'GET' || get_post == 'get')
   {
      url=url + enc_value;
      enc_value = ''; // If get, don't need to pass value into send()
   }

   // default aSync is true
   request.open(get_post, url, aSync);

   // With some brower, you can not use 'setRequestHeader' before 'open'.
   if(get_post == 'POST' || get_post == 'post')
   {
      if(!window.opera)
      {
         request.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
      }
      else
      {
         if((typeof request.setRequestHeader) == 'function')
            request.setRequestHeader('Content-Type','application/x-www-form-urlencoded;');
      }
   }

   request.send(enc_value);

   // for debug
   //if(err_msg != "") alert(err_msg);  
   return tmpResult;
}

/**
 * AJAX funcion: Create object for HTTP Request
 *
 * @return object
 * @since  2005/08/24
 */
function _createHttpRequest()
{
   if(window.ActiveXObject)
   {
      try
      {
         return new ActiveXObject("Msxml2.XMLHTTP");
      }
      catch (e)
      {
         try
         {
            return new ActiveXObject("Microsoft.XMLHTTP");
         }
         catch (e2) 
         {
            return null;
         }
      }
   }
   else if(window.XMLHttpRequest)
   {
      return new XMLHttpRequest();
   }
   else 
   {
      return null;
   }
}

/**
 * show a mini window
 * @param String id
 */
function showMiniWindow(id)
{
   if(document.getElementById(id))
   {
      var miniWin = document.getElementById(id);
      var contents = "";

      if(showMiniWindow.arguments[1])
         contents = showMiniWindow.arguments[1];
        
      document.getElementById(id).innerHTML = contents;
      document.getElementById(id).style.display = "block";
   }
}

/**
 * hide layer
 * @param String id
 */
function hideLayer(id)
{
   if(document.getElementById(id))
   {
      document.getElementById(id).style.display = "none";
   }
}

/**
 * Internet Exploer doesn't support indexOf for array
 */
function setAryIndexOf()
{
   /* IE Hack */
   if(!Array.indexOf)
   {
      Array.prototype.indexOf = function(obj)
      {
         for(var i=0; i<this.length; i++)
         {
            if(this[i]==obj) return i;
         }
   
         return -1;
      }
   }
}

/**
 * change something for AJAX waiting period
 */
function _pleaseWait(bool)
{
   if(bool)
   {
      document.getElementById("gmap_icon_combined").style.display="none";
      document.getElementById("gmap_icon_combined_moving").style.display="inline";
   }
   else
   {
      document.getElementById("gmap_icon_combined_moving").style.display="none";
      document.getElementById("gmap_icon_combined").style.display="inline";
   }
}

/**
 * improving eval security
 * @param  String AJAX(JSON) response
 * @return Mixed  
 */
function _eval4Json(response)
{
   var tempObj;
   var tempText = response.responseText;
   
   if(tempText.indexOf(";") >= 0) return null;

   tempObj = tempText.parseJSON();
   
   if(typeof(new Object()) != typeof(tempObj) && typeof(new Array()) != typeof(tempObj)) return null;
   
   return tempObj;
}
