//global variable for the store;
var map;
var mgr;
var geocoder;
var directions;
var markers = [];
var searchDone = false;
var currentBrandImage;
var firstPointShown = false;
var maxResults = 15;

var APPPATH = '/typo3conf/ext/ppi_stores/res';

// Directions GIcon images on the map
var UI_MAP_DIRECTIONS_STARTIMAGE = APPPATH + "/from.jpg";
var UI_MAP_DIRECTIONS_ENDIMAGE = APPPATH + "/to.jpg";
var UI_MAP_DIRECTIONS_SHADOWIMAGE = APPPATH + "/dshadow.png";

var UI_DIRECTIONS_STARTIMAGE = APPPATH + "/from.jpg";
var UI_DIRECTIONS_ENDIMAGE = APPPATH + "/to.jpg";
var UI_DIRECTIONS_PAUSEIMAGE = APPPATH + "/to.jpg";

//direction options
var direction = {};

function addStoreMarkers(){
  fillSegmentList();
}

(function($) {
  $.fn.storefinder = function(options) {

    var mapTarget = $(this).get(0);
    //set width and height for map
    if(mapSettings.mapWidth > 0) {
      $(mapTarget).css('width', mapSettings.mapWidth);
    }
    if(mapSettings.mapHeight > 0) {
      $(mapTarget).css('height', mapSettings.mapHeight);
    }

    $('#storeSearch').submit(function(e){
        e.preventDefault();
        $.storefinder.updateMarkers();
        return false;
    });

    $('#searchLocation').focus(function(){
      if($(this).val() == UI_STRINGCONST_DEFAULT_ADDRESS) {
        $(this).val("");
      }
    });
    $('#searchLocation').blur(function(){
      if($(this).val() == "") {
        $(this).val(UI_STRINGCONST_DEFAULT_ADDRESS);
      }
    });

    $('#displayRouteBack').click(function(){
      $('#directionsWrap').hide('fast');
      $('#mapList').show('fast');
      return false;
    });

    geocoder = new GClientGeocoder();

    map = new GMap2(mapTarget);

    map.addControl(new GLargeMapControl());
    map.addControl(new GMapTypeControl());

    map.addMapType(G_NORMAL_MAP);
    map.enableScrollWheelZoom();



    directions = new GDirections();
    direction.options = { getSteps: true, getPolyline: true };
    direction.options.locale = GLOBAL_DIRECTIONS_LOCALE;

    //use this with for output with google api, no manual building of waypoits necessary google api
    //directions = new GDirections(map, document.getElementById("directions"));

    GEvent.addListener(directions, "error", onDirectionsError);
    GEvent.addListener(directions, "load", onDirectionsLoad);

    var startPoint = new GLatLng(mapSettings.mapStartLat, mapSettings.mapStartLong);
    map.setCenter(startPoint, mapSettings.mapStartZoom, G_NORMAL_MAP);

    //initialize dummy overlay
    //map.addOverlay(new GMarker(startPoint));

    mgr = new MarkerManager(map);

    setupIcons();

    for(var i = 0; i < mapSettings.markers.length; i++) {
      mapSettings.markers[i].point = new GLatLng(mapSettings.markers[i].latitude, mapSettings.markers[i].longitude);

      var theIcon = 'default';
      if(mapSettings.markers[i].brand && mapSettings.brands['key_'+mapSettings.markers[i].brand]) {
        theIcon = mapSettings.brands['key_'+mapSettings.markers[i].brand].icon;
      }

      if(theIcon != 'default') {
        marker = new GMarker(mapSettings.markers[i].point, {icon: theIcon});
      }
      else {
        marker = new GMarker(mapSettings.markers[i].point);
      }
      marker.bubble = formatMarkerValue(mapSettings.markers[i].bubbleTemplate);
      marker.bubble += '<a href="#" class="displayRoute" onclick="$.storefinder.openDirections(true, ' + i + '); return false;">'+UI_STRINGCONST_DISPLAY_ROUTE+'</a>';
      marker.brandimage = formatMarkerValue(mapSettings.markers[i].printImage);
      //save reference to the marker
      mapSettings.markers[i].mapMarker = marker;
      //save it in the right array for easier access
      markers[i] = marker;
    }

    populateMap(mapSettings.markers);
    fillBrandList();
    fillSegmentList();
    if($_GET('zip') != '' || $_GET('city') != '' || $_GET('segment') != '') {
      initialSettings();
    }
  };

  var initialSettings = function(){
    var zip     = $_GET('zip');
    var city    = $_GET('city');
    var segment = $_GET('segment');
    $('#searchSegments option[value='+segment+']').attr('selected', 'true');
    if(zip != '' || city != '') {
      $('#searchLocation').val(zip + ' ' + city);
    }
    $.jNice.SelectUpdate($('#searchSegments'));
    $.storefinder.updateMarkers(); return false;
  }

  var setupIcons = function(){
    for(i in mapSettings.brands) {
      var brandIcon = new GIcon(G_DEFAULT_ICON);
      brandIcon.image = 'uploads/tx_ppistores/'+mapSettings.brands[i].image_mapicon;
      brandIcon.iconSize = new GSize(60, 24);
      brandIcon.shadow = null;
      brandIcon.shadowSize = null;
      brandIcon.iconAnchor = new GPoint(30, 12);
      brandIcon.infoWindowAnchor = new GPoint(30, 0)
      brandIcon.imageMap = null;
      mapSettings.brands[i].icon = brandIcon;
    }
  }

  var populateMap = function (markers) {
      if(markers.length > 0) {
        //clear the current overlay, populate with stores nearer than 100km
        map.clearOverlays();
        mgr.clearMarkers();
        map.closeInfoWindow();
        var markersToShow = [];
        //build up markerArray to batch-add
        jQuery(markers).each(function(i, marker){
          markersToShow.push(marker.mapMarker);
        });

        //for explorative usage, only show markers when zoomed in
        if(searchDone == true) {
          mgr.addMarkers(markersToShow, 0);
        }
        else {
          mgr.addMarkers(markersToShow, 7);
        }
        mgr.refresh();

        var bounds = new GLatLngBounds();
        jQuery('#mapList').empty().show('fast');

        var infoWindowOptions = { pixelOffset: new GSize(0, -32), maxWidth: 500 };
        jQuery(markers).each(function(i,marker){
          bounds.extend(marker.point);

          //only fill the list, if a search was executed after initial load
          if(searchDone == true) {
            var liEntry = $("<li />")
              .html(formatMarkerValue(marker.liTemplate))
              .click(function(){
                  displayPoint(marker.mapMarker, false);
              })
              .appendTo("#mapList");
              if(jQuery.browser.msie == true && jQuery.browser.version < 7) {
                liEntry.hover(
                  function (){
                    $(this).addClass('hover');
                  },
                  function (){
                    $(this).removeClass('hover');
                  }
                );
              }

            //highlight the active entry in the list
            GEvent.addListener(marker.mapMarker, "click", function() {
              //marker.mapMarker.openInfoWindowHtml(marker.mapMarker.bubble);
              showBubble(marker.mapMarker.getPoint(), marker.mapMarker.bubble);


              $('#mapList li').removeClass("active");
              liEntry.addClass("active");
              $('#mapListWrap').scrollTo(liEntry);
            });
          }
          else {
            //google event listener
            GEvent.addListener(marker.mapMarker, "click", function() {
              //marker.mapMarker.openInfoWindowHtml(marker.mapMarker.bubble);
              showBubble(marker.mapMarker.getPoint(), marker.mapMarker.bubble);
            });
          }
        });

        //initial view does not depend on shown markers
        if(searchDone == true) {
            var clat = (bounds.getNorthEast().lat() + bounds.getSouthWest().lat()) /2;
            var clng = (bounds.getNorthEast().lng() + bounds.getSouthWest().lng()) /2;
            map.setCenter(new GLatLng(clat,clng), map.getBoundsZoomLevel(bounds));


          //show info pane, if only one marker exists
          if(markers.length == 1) {
            displayPoint(markers[0].mapMarker, true);
          }
          else {
            //center map
            //var clat = (bounds.getNorthEast().lat() + bounds.getSouthWest().lat()) /2;
            //var clng = (bounds.getNorthEast().lng() + bounds.getSouthWest().lng()) /2;
            //map.setCenter(new GLatLng(clat,clng), map.getBoundsZoomLevel(bounds));
          }
        }
      }
      else {
        displayErrorSearch(UI_STRINGCONST_NORESULTSFOUND);
      }
  };

  var showBubble = function(markerPoint, markerBubble){
    var windowOptions = { pixelOffset: new GSize(0, -12), maxWidth: 500 };
    map.openInfoWindowHtml(markerPoint, markerBubble, windowOptions);
  }

  var fillBrandList = function (){

    for(i in mapSettings.brands) {
      mapSettings.brands[i].used = 0;
    }

    var theSelect = $('#searchBrands').get(0);
    var thisOptions = $(theSelect).find('option');
    $(thisOptions).each(function(i){
          if(i > 0) {
            $(thisOptions[i]).remove();
          }
    });


    $(mapSettings.markers).each(function(i,marker){
      if(marker.brand > 0 && mapSettings.brands['key_'+marker.brand]) {
        mapSettings.brands['key_'+marker.brand].used = 1;
      }
    });
    for(i in mapSettings.brands) {
      if(mapSettings.brands[i].used == 1) {
        $(theSelect).append(jQuery("<option />").val(mapSettings.brands[i].uid).html(formatMarkerValue(mapSettings.brands[i].name)));
      }
    }
    //call jnice to refresh the styled select
    $.jNice.SelectUpdate(theSelect);
  };

  var fillSegmentList = function (){
    var theSelect = $('#searchSegments').get(0);
    var thisOptions = $(theSelect).find('option');
    $(thisOptions).each(function(i){
          if(i > 0) {
            $(thisOptions[i]).remove();
          }
    });

    for(i in mapSettings.segments) {
      $(theSelect).append(jQuery("<option />").val(mapSettings.segments[i].uid).html(formatMarkerValue(mapSettings.segments[i].name)));
      $.jNice.SelectUpdate(theSelect);
    }
  };

  var displayPoint = function (marker, showSingle){

    showBubble(marker.getLatLng(), marker.bubble);
    //marker.openInfoWindowHtml(marker.bubble);
    return ;

    if(showSingle == 1) {
      //marker.openInfoWindowHtml(marker.bubble);
      showBubble(marker.getLatLng(), marker.bubble);
      //map.setCenter(marker.getLatLng());
      //map.setZoom(10);
    }
    else {
      //marker.openInfoWindowHtml(marker.bubble);
      showBubble(marker.getLatLng(), marker.bubble);
      //map.setCenter(marker.getLatLng());
      //map.panTo(marker.getLatLng());
    }

    //marker.openInfoWindowHtml(marker.bubble);
    //map.panTo(marker.getLatLng());
  };

  var updateMarkers = function(){
    var selectedBrand = $("#searchBrands").val();
    var selectedSegment = $("#searchSegments").val();
    var searchLocation = jQuery.trim($("#searchLocation").val());
    var filteredMarkers = mapSettings.markers;

    if(searchLocation == '' || searchLocation == UI_STRINGCONST_DEFAULT_ADDRESS) {
      //displayErrorSearch(UI_STRINGCONST_NOZIPADDRESS);
      //return;
      searchLocation = '';
    }


    if(selectedBrand != -1) {
      filteredMarkers = filterBrands(selectedBrand, filteredMarkers);
    }

    if(selectedSegment != -1) {
      filteredMarkers = filterSegments(selectedSegment, filteredMarkers);
    }

    if(searchLocation) {
        geocoder.getLatLng(
          searchLocation + ' ' + GLOBAL_CCTLD,
          function(point) {
            if(!point) {
              displayErrorSearch(UI_STRINGCONST_NORESULTSFOUND);
            }
            else {
              compareDistance(point, filteredMarkers);
            }
          }
        );
    }
    else {
      populateMap(filteredMarkers);
    }

    //finally, populate the map with all results



  };

  var filterSegments = function (segment, markers) {
    var filteredMarkers = [];
    $(markers).each(function(i, marker){
      if(is_object(marker.segments['key_'+segment])) {
        filteredMarkers.push(marker);
      }
    });

    return filteredMarkers;
  };

  var filterBrands = function (brand, markers){
    var filteredMarkers = [];
    $(markers).each(function(i,marker){
      if(marker.brand == brand) {
        filteredMarkers.push(marker);
      }
    });

    return filteredMarkers;
  };

  var compareDistance = function(point, markers) {
    var matchedMarkers = [];
    var foundMarkers   = [];
    var nearestMarkers = [];

    $(markers).each(function(i, marker) {
      var distance = Math.floor((marker.point.distanceFrom(point)) / 1000);
      if(distance < 100) {
        foundMarkers.push([distance,marker]);
      }
    });
    foundMarkers.sort(distanceSort);
    //only show best x matches
    if(foundMarkers.length > maxResults) {
      nearestMarkers = foundMarkers.slice(0,(maxResults - 1));
    }
    else {
      nearestMarkers = foundMarkers;
    }
    $(nearestMarkers).each(function(i, marker){
      matchedMarkers.push(marker[1]);
    });

    populateMap(matchedMarkers);
  };

  function openDirections(toHere, markerID, routeAddress) {
      var theMarker = markers[markerID];
      var localMarkers = jQuery.makeArray(mapSettings.markers);
      var theMarker = localMarkers[markerID];
      var routePoint = (routeAddress ? routeAddress : '');

      //setDirections(theMarker.point, $("#directionsTo").val(), "de_DE");

      var gLatLngDealer;
      //hide result list and show the inputs for direction search
      $("#results").hide(300); // hide the results.
      $("#mapList").hide(300);
      // disable printing.
      $('#directionsPrintBtn, #directionsPrint')
          .css("cursor", "default")
          .fadeTo(1, 0.33)
          .unbind("click")
          .unbind("mouseover")
          .unbind("mouseout")
          .removeAttr('alt')
          .parent().parent().removeAttr("title")
          ;
      $("#directions_results").html("");
      $("#directionsWrap").show(300);
      //show this in input field - take only first line from address, %3Cbr%20%2F%3E is <br /> urlencoded
      var addressLine = formatMarkerValue((theMarker.address).split('%3Cbr%20%2F%3E').shift() + ", " + theMarker.zip + " " + theMarker.city);

      if (toHere) {
          $("#directionsFrom").val(routePoint)[0].focus();
          $("#directionsTo").val(addressLine);
      }
      else {
          $("#directionsFrom").val(addressLine);
          $("#directionsTo").val(routePoint)[0].focus();
      }

      $("#formSearchDirections").unbind('submit');
      $("#formSearchDirections").submit(function() {
          toggleSearch(true);
          try {
              if (toHere) {
                  directions.loadFromWaypoints(new Array($("#directionsFrom").val(), theMarker.point), direction.options);
              }
              else {
                  directions.loadFromWaypoints(new Array(theMarker.point, $("#directionsTo").val()), direction.options);
              }
          }
          catch (ex) {
          }
          return false;
      });
      // Ende openDirections
      $('#switchButton').unbind('click');
      $('#switchButton').click(function(){
          var switcher = toHere == 0 ? 1 : 0;
          var userInput = (toHere == 1 ? $("#directionsFrom").val() : $("#directionsTo").val());
          openDirections(switcher , markerID, userInput);
      });
  }

  function handleErrors()	{
  	if (directions.getStatus().code == G_GEO_UNKNOWN_ADDRESS)
  	alert("Adresse existiert nicht (evtl. mit Latitude und Longitude versuchen)!\n Fehler: " + directions.getStatus().code);
  	else if (directions.getStatus().code == G_GEO_SERVER_ERROR)
  	alert("Adresse wurde nicht gefungen (evtl. mit Latitude und Longitude versuchen)!\n Fehler: " + directions.getStatus().code);

  	else if (directions.getStatus().code == G_GEO_MISSING_QUERY)
  	alert("Adresse vollstaendig angeben!\n Fehler: " + directions.getStatus().code);

  	else if (directions.getStatus().code == G_GEO_BAD_KEY)
  	alert("Google Maps API Key nicht gueltig! Bitte nicht kopieren! Key kann auf http://www.google.com/apis/maps/signup.html beantragt werden! \n Fehler: " + directions.getStatus().code);

  	else if (directions.getStatus().code == G_GEO_BAD_REQUEST)
  	alert("Fehler bei der Berechnung. Bitte nochmal versuchen!\n Fehler: " + directions.getStatus().code);

  	else alert("Unbekannter Fehler!\n Fehler: " + directions.getStatus().code);

  	}


  	var onDirectionsError = function () {
        var errCode = directions.getStatus().code;
        displayErrorRoute(UI_STRINGCONST_NORESULTSFOUND);
        toggleSearch(false);
    }

    function onDirectionsLoad() {
      // => statusCode = 200 (G_GEO_SUCCESS);
      map.clearOverlays();
      clearErrors();
      mgr.clearMarkers();
      // setup polylines
      var poly = directions.getPolyline();
      map.addOverlay(poly);
      // fit and center map.
      var bounds = directions.getBounds();
      map.setCenter(bounds.getCenter());
      map.setZoom(map.getBoundsZoomLevel(bounds));
      // setup icons
      var baseIcon = new GIcon();
      baseIcon.shadow = UI_MAP_DIRECTIONS_SHADOWIMAGE;
      baseIcon.iconSize = new GSize(20, 20);
      baseIcon.shadowSize = new GSize(30,30);
      baseIcon.iconAnchor = new GPoint(10, 10);
      G_START_ICON = new GIcon(baseIcon);
      G_START_ICON.image = UI_MAP_DIRECTIONS_STARTIMAGE;
      G_END_ICON = new GIcon(baseIcon);
      G_END_ICON.image = UI_MAP_DIRECTIONS_ENDIMAGE;
      //G_PAUSE_ICON.image = UI_MAP_DIRECTIONS_PAUSEIMAGE;
      // plot start and end markers
      map.addOverlay(new GMarker(poly.getVertex(0), G_START_ICON));
      map.addOverlay(new GMarker(poly.getVertex(poly.getVertexCount() - 1), G_END_ICON));
      /*********************/

      /* fill results pane */

      /*********************/
      //Summary
      var distMeters = directions.getDistance().meters; // distance in meters (integer);
      var distHtml = directions.getDistance().html; // string representation of distance / set by Google.
      var durSeconds = directions.getDuration().seconds; // duration in seconds (integer);
      var durHtml = directions.getDuration().html; // string representation of duration / set by Google.
      var results = $("#directions_results");
      var htmlResultSummary = UI_STRINGCONST_RESULTSUMMARY_1.replace(/\[ADDRESSLINE\]/, $("#directionsTo").val());
      htmlResultSummary += "<br/>\n";
      htmlResultSummary += UI_STRINGCONST_RESULTSUMMARY_2.replace(/\[DISTANCE\]/, distHtml).replace(/\[DURATION\]/, durHtml);
      $(results).html("<p class=\"summary\">" + htmlResultSummary + "</p>\n");
      $(results).append("<div class=\"resultWaypoint\">\n" +
                          "<img src=\"" + UI_DIRECTIONS_STARTIMAGE + "\" alt=\"\"/>\n" +
                          "<span>" + $("#directionsFrom").val() + "</span>" +
                          "<div class=\"clear\"></div>" +
                          "</div>\n");
      //for (var i = 0; i < directions.getNumRoutes()-1; i++) {
      //var route = directions.getRoute(i);
      var route = directions.getRoute(0);
      var tableHtml = "<table>\n";
      for (var step = 0; step < route.getNumSteps(); step++) {
          currStep = route.getStep(step);
          var rowClass = (step == 0) ? " class=\"firstRow\"" : "";
          tableHtml += "<tr" + rowClass + ">\n" +
                          "<td>" + (step + 1) + ".</td>\n" +
                          "<td>" + currStep.getDescriptionHtml().replace(/\<b\>|\<\/b\>|/g, '') + "</td>\n" +
                          "<td class=\"distance\">" + currStep.getDistance().html + "</td>" +
                        "</tr>\n";
      }
      tableHtml += "</table>\n";
      $(results).append(tableHtml);
      //}
      $(results).append("<div class=\"resultWaypoint\">\n" +
                      "  <img src=\"" + UI_DIRECTIONS_ENDIMAGE + "\" alt=\"\"/>\n" +
                      "  <span>" + $("#directionsTo").val() + "</span>" +
                      "  <div class=\"clear\"></div>" +
                      "</div>\n");
      var fromLatLng = route.getStep(0).getLatLng();
      var toLatLng = route.getEndLatLng();
      // enable printing.


      $('#directionsPrintBtn, #directionsPrint')
          .bind("mouseover", function() { $(this).css("cursor", "pointer") })
          .bind("mouseout", function() { $(this).css("cursor", "default") })
          .fadeTo("fast", 1.0)
          .bind("click", function() {
              try {
                  console.log(fromLatLng.lng());
                  console.log(toLatLng.lng());
                  console.log($("#directionsFrom").val());
                  console.log($("#directionsTo").val());
              }
              catch (e) {
              }
              var win = window.open(mapSettings.printPage
                          + "?&fromText=" + escape($("#directionsFrom").val())
                          + "&toText=" + escape($("#directionsTo").val())
                          + "&fromLatLng=" + serializeLatLng(fromLatLng)
                          + "&toLatLng=" + serializeLatLng(toLatLng)
                          + "&brandImage=" + markers[currentBrandImage].brandimage.split('/').pop()
                          , "printPreview"
                          , "width=594,height=750,left=200,top=20,scrollbars=yes,resizable=yes");
          })
          .attr('alt', $("#lblPrint").text())
          .parent().parent().attr('title', $("#lblPrint").text() )
          ;

      toggleSearch(false);
  }

  var formatMarkerValue = function(value) {
    return Utf8.decode(unescape(value));
  }

  var toggleSearch = function(searching){
    //does nothing atm
  };

  var ParseLatLng = function (str) {
    var arr = str.split(';');
    if (arr.length > 1)
        return new GLatLng(arr[0], arr[1]);
    else
        return false;
  }

  var serializeLatLng = function (gLatLng) {
    var arrGLatLng = new Array();
    arrGLatLng[0] = gLatLng.lat();
    arrGLatLng[1] = gLatLng.lng();
    try {
        console.log(arrGLatLng.join(';'));
    }
    catch (e) {
    }
    return arrGLatLng.join(';');

  }


  var setDirections = function (fromAddress, toAddress, locale) {
    directions.load("from: " + fromAddress + " to: " + toAddress, { "locale": locale });
  }

  var displayErrorSearch = function(text) {
    //clear results
    $('#mapList').empty();
    $('#directionsWrap').hide('fast');
    $('#mapErrors').css('display', 'block').html("<p class=\"error\">" + text + "</p>");
  }
  var displayErrorRoute = function(text) {
    $('#mapList').empty();
    $('#directionsError').css('display', 'block').html("<p class=\"error\">" + text + "</p>");
  }

  var clearErrors = function() {
    $('#mapErrors').empty().css('display', 'none');
    $('#directionsError').empty().css('display', 'none');
  }

  var cleanDirections = function () {
    $('#directionsWrap').hide('fast');
  }

  var searchExecuted = function () {
    $('body').addClass('searchDone');
    searchDone = true;
  }




  $.storefinder = {
    updateMarkers : function(){
      clearErrors();
      cleanDirections();
      searchExecuted();
      updateMarkers();
      return false;
    },
    openDirections : function(toHere, markerID){
      currentBrandImage = markerID;
      openDirections(toHere, markerID);
    }
  };

})(jQuery);


$(document).ready(function(){
  if(jQuery('html').attr('lang') == 'en') {
    jQuery('body').addClass('en');
  }
  jQuery('#map').storefinder();
});
$(window).unload(function() {
    GUnload();
});


function is_object (mixed_var){
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Legaev Andrey
    // +   improved by: Michael White (http://getsprink.com)
    // *     example 1: is_object('23');
    // *     returns 1: false
    // *     example 2: is_object({foo: 'bar'});
    // *     returns 2: true
    // *     example 3: is_object(null);
    // *     returns 3: false

    if (mixed_var instanceof Array) {
        return false;
    } else {
        return (mixed_var !== null) && (typeof( mixed_var ) == 'object');
    }
}

function distanceSort(a,b) {
  var a = a[0];
  var b = b[0];
  return a == b ? 0 : (a < b ? -1 : 1)
}



function stripslashes (str) {
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +   improved by: Ates Goral (http://magnetiq.com)
    // +      fixed by: Mick@el
    // +   improved by: marrtins
    // +   bugfixed by: Onno Marsman
    // +   improved by: rezna
    // +   input by: Rick Waldron
    // +   reimplemented by: Brett Zamir (http://brett-zamir.me)
    // *     example 1: stripslashes('Kevin\'s code');
    // *     returns 1: "Kevin's code"
    // *     example 2: stripslashes('Kevin\\\'s code');
    // *     returns 2: "Kevin\'s code"
    return (str+'').replace(/\\(.?)/g, function (s, n1) {
        switch (n1) {
            case '\\':
                return '\\';
            case '0':
                return '\0';
            case '':
                return '';
            default:
                return n1;
        }
    });
}


/**
*
*  UTF-8 data encode / decode
*  http://www.webtoolkit.info/
*
**/

var Utf8 = {

	// public method for url encoding
	encode : function (string) {
		string = string.replace(/\r\n/g,"\n");
		var utftext = "";

		for (var n = 0; n < string.length; n++) {

			var c = string.charCodeAt(n);

			if (c < 128) {
				utftext += String.fromCharCode(c);
			}
			else if((c > 127) && (c < 2048)) {
				utftext += String.fromCharCode((c >> 6) | 192);
				utftext += String.fromCharCode((c & 63) | 128);
			}
			else {
				utftext += String.fromCharCode((c >> 12) | 224);
				utftext += String.fromCharCode(((c >> 6) & 63) | 128);
				utftext += String.fromCharCode((c & 63) | 128);
			}

		}

		return utftext;
	},

	// public method for url decoding
	decode : function (utftext) {
		var string = "";
		var i = 0;
		var c = c1 = c2 = 0;

		while ( i < utftext.length ) {

			c = utftext.charCodeAt(i);

			if (c < 128) {
				string += String.fromCharCode(c);
				i++;
			}
			else if((c > 191) && (c < 224)) {
				c2 = utftext.charCodeAt(i+1);
				string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
				i += 2;
			}
			else {
				c2 = utftext.charCodeAt(i+1);
				c3 = utftext.charCodeAt(i+2);
				string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
				i += 3;
			}

		}

		return string;
	}

}


//helper function to retrieve get vars
function $_GET(q,s) {
    s = (s) ? s : window.location.search;
    //var re = new RegExp('&amp;'+q+'=([^&amp;]*)','i');
    var re = new RegExp('&'+q+'=([^&]*)','i');
    var test = (s=s.replace(/^\?/,'&').match(re)) ?s=s[1] :s='';
    return unescape(test);
}

