/**
* @fileoverview ShortGPS javascript lib
* @author Stefan Deitmer
* @version 1.0
*/

var eFailDB   = -1;	// database error
var eAliasTaken = -2; // custom URL alias already taken

var eMapTypeNormal    = 0;
var eMapTypeSatellite = 1;
var eMapTypeHybrid    = 2;
var eMapTypePhysical  = 3;

var sgTwitterURL = "http://twitter.com";
var sgGLCount = 60;
var sgGLMax = 300;
var sgMaxLoginLayer = 1;
var sgMaxTweetLen = 140;

var sg30days = 1000*3600*24*30;

// this is so we can use classes from the Pigaia namespace
Pigaia.Root = function() {};
Pigaia.forName = {};
function Pigaia() { Pigaia.Root(); }

/**
* constructor for root object. Creates necessary objects for startup
* @author Stefan Deitmer
* @version 1.0
* @class root object
* @constructor
*/
ShortGPS.Root = function() {
  if ((arguments.length==1)&&(typeof arguments[0]=="boolean") && (arguments[0]==false))
  {
    return;
  }
};
ShortGPS.forName = {};

/**
* @class
* @constructor
*/
function ShortGPS() {
  // call root-constructor
  ShortGPS.Root();

  var map = null;
  var geocoder = null;
  var marker = null;
  var allLocMarkers = {};
  var showAllLoc = false;
  var showAllLocFilter = "";
  var iwListeners = [];
  var twitterUID = -1;
  var UID = -1;
  var lastTweetText = "";

  this.alCallCount = 0;
  this.stCallCount = 0;
  this.twitterUserCache = [];

  this.getMap = function()
  {
    return map;
  };

  this.getGeocoder = function()
  {
    return geocoder;
  };

  this.setMarker = function(_marker)
  {
    marker = _marker;
  };

  this.getMarker = function()
  {
    return marker;
  };

  this.getShowAllLoc = function()
  {
    return showAllLoc;
  };

  this.getShowAllLocFilter = function()
  {
    return showAllLocFilter;
  };

  this.hasAllLocURL = function(_url)
  {
    return !!allLocMarkers[_url];
  };
  
  this.getTwitterUID = function()
  {
    return twitterUID;
  };

  this.setTwitterUID = function(_uid)
  {
    twitterUID = _uid;
  };

  this.getUID = function()
  {
    return UID;
  };

  this.setUID = function(_uid)
  {
    UID = _uid;
  };
  
  this.getLastTweetText = function()
  {
    return lastTweetText;
  };

  this.setLastTweetText = function(_text)
  {
    lastTweetText = _text;
  };

  this.addIWListener = function(_listener)
  {
    iwListeners.push(_listener);
  };

  this.clearIWListeners = function()
  {
    while (iwListeners.length > 0)
    {
      google.maps.Event.removeListener(iwListeners.pop());
    }
  };
  
  this.initMap = function(lat, lng, zoom, maptype)
  {
    // construct new map
    if (google.maps.BrowserIsCompatible())
    {
      map = new google.maps.Map2(document.getElementById("map"));
      map.addMapType(G_PHYSICAL_MAP);
      map.addControl(new google.maps.LargeMapControl3D());
      map.addControl(new google.maps.MapTypeControl());
      map.addControl(new google.maps.ScaleControl());
      map.enableScrollWheelZoom();
      map.enableContinuousZoom();
      geocoder = new google.maps.ClientGeocoder();

      switch (maptype)
      {
      case eMapTypeNormal:    map.setMapType(G_NORMAL_MAP);    break;
      case eMapTypeSatellite: map.setMapType(G_SATELLITE_MAP); break;
      case eMapTypeHybrid:    map.setMapType(G_HYBRID_MAP);    break;
      case eMapTypePhysical:  map.setMapType(G_PHYSICAL_MAP);  break;
      }

      var setCenter = function(lat, lng, zoom, bbox)
      {
        map.setCenter(new google.maps.LatLng(lat, lng), zoom);
        shortGPS.resizeMap(false);
        map.setCenter(new google.maps.LatLng(lat, lng), zoom);
        shortGPS.resizeMap(true);

        window.onresize = function () { shortGPS.resizeMap(true); };
        google.maps.Event.addListener(map, "moveend", function() { shortGPS.updateAllLocLayer(); } );
        google.maps.Event.addListener(map, "zoomend", function() { shortGPS.updateAllLocLayer(); } );

        if (bbox)
        {
          map.setZoom(map.getBoundsZoomLevel(bbox));
        }
      }
      
      if (!lat && !lng && !zoom)
      {
//        $.get( "c.php", {}, function(cresult) {
            // set center to IP location
            shortGPS.anonRequest("GetBBox", { ccode:"de" }, function(result) {
              if (result.status == -1)
              {
                setCenter(0, 0, 2);
              }
              else
              {
                var bbox = new google.maps.LatLngBounds(new google.maps.LatLng(result.bbox_south, result.bbox_west),
                                                        new google.maps.LatLng(result.bbox_north, result.bbox_east));

                setCenter(bbox.getCenter().lat(), bbox.getCenter().lng(), 0, bbox);
              }
            });
  //        }, "text");
      }
      else
      {
        setCenter(lat, lng, zoom);
      }
    }
  };

  this.showAllLocLayer = function(_show, _filter)
  {
    showAllLoc = _show;
    showAllLocFilter = _filter;
    for (var i in allLocMarkers)
    {
      if (showAllLoc && shortGPS.isMarkerVisible(allLocMarkers[i], showAllLocFilter))
      {
        allLocMarkers[i].show();
      }
      else
      {
        allLocMarkers[i].hide();
      }
    }
  };

  this.addAllLocMarker = function(_url, _marker)
  {
    allLocMarkers[_url] = _marker;
  };
};

ShortGPS.prototype.isMarkerVisible = function(_marker, _filter)
{
  if (!_filter || _filter == "")
  {
    return true;
  }

  return shortGPS.containsHashtag(_marker.hashtags, _filter);
};

ShortGPS.prototype.containsHashtag = function(_list, _filter)
{
  if (!_list)
  {
    return false;
  }

  for (var i=0; i<_list.length; i++)
  {
    if ("#" + _list[i].toLowerCase() == _filter.toLowerCase())
    {
      return true;
    }
  }

  return false;
};

ShortGPS.prototype.init = function()
{
  window.setInterval(function()
      {
        var now = new Date();
        var enddate = Date.UTC(2009, 07, 01, -2, 0, 0);
        var timeleft = parseInt((enddate - now.valueOf()) / 1000);

        var days = parseInt(timeleft / 86400);
        var hours = parseInt((timeleft - days*86400)/3600);
        var minutes = parseInt((timeleft - days*86400 - hours*3600)/60);
        $("#js-campaign-time-left").text(days + " days, " + hours + "h, " + minutes + " min left");
      }, 1000);
  $("#location").keypress(function(event)
      {
        if (event && event.keyCode == 13)
        {
          var loc = $("#location").val();
          var latlng;
          var lat, lng;
          
          // try to detect GPS coordinates

          // format example: N 54.09483° E 013.38752°
          if ((latlng = loc.match(/^\s*([NS])\s*0*(\d+(?:\.\d+)?)\s*°?\s*,?\s*([WE])\s*0*(\d+(?:\.\d+)?)\s*°?\s*$/)))
          {
            lat = (latlng[1] == 'N' ? 1 : -1) * latlng[2];
            lng = (latlng[3] == 'E' ? 1 : -1) * latlng[4];
          }
          // format example: 54.09483° -13.38752
          else if ((latlng = loc.match(/^\s*([\+\-]?\d+(?:\.\d+)?)\s*°?\s*,?\s*([\+\-]?\d+(?:\.\d+)?)\s*°?\s*$/)))
          {
            lat = parseFloat(latlng[1]);
            lng = parseFloat(latlng[2]);
          }
          // format example: N 54° 05.690' E 013° 23.251'
          else if ((latlng = loc.match(/^\s*([NS])\s*0*(\d+)\s*°\s*0*(\d+(?:\.\d+)?)\s*\'\s*,?\s*([WE])\s*0*(\d+)\s*°\s*0*(\d+(?:\.\d+)?)\s*\'\s*/)))
          {
            lat = (latlng[1] == 'N' ? 1 : -1) * (parseInt(latlng[2]) + latlng[3] / 60);
            lng = (latlng[4] == 'E' ? 1 : -1) * (parseInt(latlng[5]) + latlng[6] / 60);
          }
          // format example: N 54° 05' 41" E 013° 23' 15"
          else if ((latlng = loc.match(/^\s*([NS])\s*0*(\d+)\s*°\s*0*(\d+)\s*\'\s*0*(\d+(?:\.\d+)?)\s*\"\s*,?\s*([WE])\s*0*(\d+)\s*°\s*0*(\d+)\s*\'\s*0*(\d+(?:\.\d+)?)\s*\"\s*/)))
          {
            lat = (latlng[1] == 'N' ? 1 : -1) * (parseInt(latlng[2]) + parseInt(latlng[3]) / 60 + latlng[4] / 3600);
            lng = (latlng[5] == 'E' ? 1 : -1) * (parseInt(latlng[6]) + parseInt(latlng[7]) / 60 + latlng[8] / 3600);
          }
          else
          {
            // no known coordinate format, assume address and use Google geocoder
            shortGPS.geocode(loc);
            return;
          }

          $(".js-use-info").hide();
          $(".js-drag-info").show();

          lat = lat.toFixed(5);
          lng = lng.toFixed(5);
          shortGPS.getAddress(lat, lng, function(address) {
            var marker = shortGPS.makeDragMarker(lat, lng, true);
            shortGPS.showInfoMovable(address, marker);
          });
        }
      });

  $("#location").focus();

  $("#all_loc_box").click(function ()
      {
        $("#all_campaign").removeAttr("checked");
        shortGPS.showAllLocLayer(this.checked);
      });
  $("#all_campaign").click(function ()
      {
        $("#all_loc_box").removeAttr("checked");
        shortGPS.showAllLocLayer(this.checked, "#Kissmap");
      });

  if ($("#all_loc_box").get(0).checked)
  {
    shortGPS.showAllLocLayer(true);
  }
  else
  {
    shortGPS.showAllLocLayer(false);
  }

  ZeroClipboard.setMoviePath( 'js/lib/ZeroClipboard.swf' );

  $("#js-twitter-si-button").click(function() {
    shortGPS.anonRequest("GetTwitterOAuthURL", { dummy:0 }, function(result) {
      if (shortGPS.getCookie("TOA-RETURN-URL"))
      {
        shortGPS.setCookie("TOA-RETURN", 1);
      }
      window.location.href = result.url;
    });
    return false;
  });

  var showLogin = function()
  {
    $("#js-login-twitter").show();
    $("#js-twitter-user").hide();
    $("#js-user-pic").hide();

    $(".js-twitter-signin").show();
    $(".js-twitter-send").hide();
  };

  var showUserStatus = function()
  {
    $("#js-login-twitter").hide();
    $("#js-twitter-user").show();
    $("#js-user-pic").show();
    shortGPS.updateButtonHoverEvents();

    $.getJSON(sgTwitterURL + "/users/show.json?user_id=" + shortGPS.getTwitterUID() + "&callback=?",
          {  },
          function(result)
          {
            $("#twp_pic").attr("src", result.profile_image_url);
            $("#twp_pic").attr("alt", result.screen_name);
            $("#twp_pic").attr("title", result.screen_name);
            $("#twp_name").text(result.screen_name);
          });
  };

  $("#js-twitter-so-link").click(function() {
      shortGPS.anonRequest("TwitterLogout", { dummy:0 }, function()
      {
        showLogin();

        shortGPS.setTwitterUID(-1);
        shortGPS.deleteCookie("TOALOGIN");
        $("#remember_me").removeAttr("checked");
        if (shortGPS.getCookie("OTK"))
        {
          shortGPS.anonRequest("RemoveOTK", { otk:shortGPS.getCookie("OTK"), uid:shortGPS.getCookie("UID") }, function(){});
          shortGPS.deleteCookie("OTK");
          shortGPS.deleteCookie("UID");
        }
      });
      return false;
    });

  $(".js-create-loc-btn").click(function(_event){
      var hashTag = "";
      var markerIcon = null;
      if ($(this).hasClass("js-hashtag-kissmap"))
      {
        hashTag = "Kissmap";
        markerIcon = "images/poila_pin_heart_3.png";
      }
      var px = _event.pageX;
      var py = _event.pageY;

      var mapOffset = $("#map").offset();
      px -= mapOffset.left;
      py -= mapOffset.top;

      var p = new google.maps.Point(px, py);
      var latlng = shortGPS.getMap().fromContainerPixelToLatLng(p);

      var oldMarker = shortGPS.getMarker();
      if (oldMarker) shortGPS.getMap().removeOverlay(oldMarker);

      var marker = shortGPS.makeDragMarker(latlng.lat(), latlng.lng(), false, markerIcon);

      shortGPS.getMap().closeInfoWindow();

      var mouseMoveEvent = google.maps.Event.addListener(shortGPS.getMap(), "mousemove", function(_cursor_point) {
          marker.setLatLng(_cursor_point);
        });
      var mouseOutEvent = google.maps.Event.addListener(shortGPS.getMap(), "mouseout", function() {
          google.maps.Event.removeListener(mouseMoveEvent);
          google.maps.Event.removeListener(mouseOutEvent);
          google.maps.Event.removeListener(mapClickEvent);
          shortGPS.getMap().removeOverlay(marker);
        });
      var mapClickEvent = google.maps.Event.addListener(shortGPS.getMap(), "click", function() {
          google.maps.Event.removeListener(mouseMoveEvent);
          google.maps.Event.removeListener(mouseOutEvent);
          google.maps.Event.removeListener(mapClickEvent);
          latlng = marker.getLatLng();
          var lat = latlng.lat().toFixed(5);
          var lng = latlng.lng().toFixed(5);
          shortGPS.getAddress(lat, lng, function(address) {
            shortGPS.showInfoMovable(address, marker, null, null, null, null, hashTag);
          });
        });
    });

  var otk = shortGPS.getCookie("OTK");
  var uid = shortGPS.getCookie("UID");
  if (uid)
  {
    shortGPS.setUID(uid);
  }

  $("#remember_me").click(function ()
    {
      if (this.checked)
      {
        shortGPS.anonRequest("GetOTK", { dummy:0 }, function(result)
          {
            if (result.status == 0)
            {
              shortGPS.setCookie("OTK", result.otk, sg30days);
              shortGPS.setCookie("UID", shortGPS.getUID(), sg30days);
            }
          });
      }
      else
      {
        shortGPS.anonRequest("RemoveOTK", { otk:shortGPS.getCookie("OTK"), uid:shortGPS.getCookie("UID") }, function(){});
        shortGPS.deleteCookie("OTK");
        shortGPS.deleteCookie("UID");
      }
    });

  // set "remember me" checkbox
  if (otk)
  {
    $("#remember_me").attr("checked", "checked");
  }
  else
  {
    $("#remember_me").removeAttr("checked");
  }

  // Login: if TOALOGIN cookie is set, we have an OAuth login in progress (or are refreshing after an OAuth Login)
  if (shortGPS.getCookie("TOALOGIN") == 1)
  {
    shortGPS.anonRequest("TwitterLogin", { dummy:0 }, function(result)
      {
        if (result.status == 0)
        {
          shortGPS.setUID(result.uid);
          shortGPS.setTwitterUID(result.twitter_uid);
          showUserStatus();
          if (shortGPS.getCookie("TOA-RETURN"))
          {
            var tweet = shortGPS.getCookie("TOA-RETURN-TWEET");
            var url = shortGPS.getCookie("TOA-RETURN-URL");
            var urlMovable = shortGPS.getCookie("TOA-RETURN-URL-TYPE") == "movable";

            shortGPS.deleteCookie("TOA-RETURN");
            shortGPS.deleteCookie("TOA-RETURN-TWEET");
            shortGPS.deleteCookie("TOA-RETURN-URL");

            shortGPS.setLastTweetText(tweet);
            shortGPS.anonRequest("ShortGPSResolve", { url:url }, function(result)
                {
                  if (result.status != 0)
                  {
                    return;
                  }

                  var lat = result.lat;
                  var lng = result.lng;

                  // center map to position
                  var map = shortGPS.getMap();
                  map.setCenter(new google.maps.LatLng(lat, lng), result.zoom);

                  switch (result.maptype)
                  {
                  case eMapTypeNormal:    map.setMapType(G_NORMAL_MAP);    break;
                  case eMapTypeSatellite: map.setMapType(G_SATELLITE_MAP); break;
                  case eMapTypeHybrid:    map.setMapType(G_HYBRID_MAP);    break;
                  case eMapTypePhysical:  map.setMapType(G_PHYSICAL_MAP);  break;
                  }

                  shortGPS.getAddress(lat, lng, function(address) {
                      var marker;
                      if (urlMovable)
                      {
                        marker = shortGPS.makeDragMarker(lat, lng, false);
                        shortGPS.showInfoMovable(address, marker, url, true, result.has_tweets_nearby, result.link);
                      }
                      else
                      {
                        marker = shortGPS.makeFixedMarker(lat, lng, false);
                        shortGPS.showInfo(marker, lat, lng, result.pi_today, result.pi_total, result.created_at, address, false, url, null, false, result.has_tweets_nearby, result.link);

                      }
                    });
                });
          }
        }
        else
        {
          shortGPS.deleteCookie("TOALOGIN");
          showLogin();
        }
      });
  }
  else
  {
    // look if we have a "remember me" OTK cookie
    if (otk)
    {
      shortGPS.anonRequest("OTKLogin", { otk:otk,uid:shortGPS.getCookie("UID") }, function(result)
        {
          if (result.status == 0)
          {
            // update OTK cookie
            shortGPS.setCookie("OTK", result.otk, sg30days);
            shortGPS.setCookie("UID", shortGPS.getUID(), sg30days);
            shortGPS.setTwitterUID(result.twitter_uid);
            showUserStatus();
          }
        });
    }
    else
    {
      showLogin();
    }
  }

  var l = document.URL.match(/.*\/([a-zA-Z0-9\-_]+)#?$/);
  if (l && l[1])
  {
    shortGPS.deleteCookie("TOA-RETURN-URL");

    // goto shorturl l
    shortGPS.anonRequest("ShortGPSResolve", { url:l[1] }, function(result)
        {
          if (result.status != 0)
          {
            // set center to ip locatiom
            shortGPS.initMap();
            return;
          }

          var lat = result.lat;
          var lng = result.lng;

          var pi_today = result.pi_today;
          var pi_total = result.pi_total;
          var created_at = result.created_at;
          var has_tweets = result.has_tweets_nearby;
          var extlink = result.link;

          // center map to position
          shortGPS.initMap(lat, lng, result.zoom, result.maptype);

          shortGPS.getAddress(lat, lng, function(address) {
                // create & show a marker
                shortGPS.getMap().clearOverlays();
                var marker = shortGPS.makeFixedMarker(lat, lng, false);
                shortGPS.showInfo(marker, lat, lng, pi_today, pi_total, created_at, address, false, l[1], null, false, has_tweets, extlink);
                google.maps.Event.addListener(marker, "click", function() { shortGPS.showInfo(marker, lat, lng, pi_today, pi_total, created_at, address, false, l[1], null, false, has_tweets, extlink); });
            });
        });
  }
  else
  {
    shortGPS.initMap();
  }   
  
  // The tabs in the IW
  //$('#iw_tabs').tabs();
  
};

ShortGPS.prototype.updateAllLocLayer = function(startat, cc)
{
  if (!startat)
  {
    // start a new call chain
    startat = 0;
    cc = ++shortGPS.alCallCount;
  }

  // interrupt old call chains
  if (cc < shortGPS.alCallCount)
  {
    return;
  }

  // limit calls
  if (startat >= sgGLMax)
  {
    return;
  }

  var sw = shortGPS.getMap().getBounds().getSouthWest();
  var ne = shortGPS.getMap().getBounds().getNorthEast();

  if (sw.lat() == ne.lat())
  {
    // degenerate case during startup, ignore
    return;
  }

  shortGPS.anonRequest("ShortGPSGetLayer",
          { latmin :  sw.lat(),
            lngmin :  sw.lng(),
            latmax :  ne.lat(),
            lngmax :  ne.lng(),
            start  :  startat,
            count  :  sgGLCount
          },
          function(result)
          {
            if (!result.location)
            {
              return;
            }
            for (var i=0; i<shortGPS.getArrayLength(result.location); i++)
            {
              var loc = shortGPS.getArrayValue(result.location, i);
              if (!shortGPS.hasAllLocURL(loc.url))
              {
                var pos = new google.maps.LatLng(loc.lat, loc.lng);
                var ht = loc.hashtags;
                if (typeof ht == "string")
                {
                  ht = new Array();
                  ht[0] = loc.hashtags;
                }
                var icon = new google.maps.Icon(G_DEFAULT_ICON);
                if (shortGPS.containsHashtag(ht, "#Kissmap"))
                {
                  icon.image = "images/poila_pin_heart_3.png";
                }
                else
                {
                  icon.image = "images/drag_Marker.png";
                }
                var marker = new google.maps.Marker(pos, { icon:icon });
                marker.hashtags = ht;
                shortGPS.addAllLocMarker(loc.url, marker);
                shortGPS.getMap().addOverlay(marker);
                if (!shortGPS.getShowAllLoc() || !shortGPS.isMarkerVisible(marker, shortGPS.getShowAllLocFilter()))
                {
                  marker.hide();
                }

                google.maps.Event.addListener(marker, "click", function(m, lat, lng, pi_today, pi_total, created_at, url, has_tweets) { return function()
                      {
                        shortGPS.getAddress(lat, lng, function(address) {
                            shortGPS.showInfo(m, lat, lng, pi_today, pi_total, created_at, address, false, url, null, false, has_tweets);
                          });
                      }}(marker, loc.lat, loc.lng, loc.pi_today, loc.pi_total, loc.created_at, loc.url, loc.has_tweets_nearby));
              }
            }

            if (i == sgGLCount)
            {
              // get next batch after short delay
              window.setTimeout(function() {shortGPS.updateAllLocLayer(startat + sgGLCount, cc);}, 100);
            }
          });
};

ShortGPS.prototype.clearInfoWindow = function()
{
  shortGPS.deleteCookie("TOA-RETURN-URL");

  shortGPS.getMap().closeInfoWindow();
  shortGPS.clearIWListeners();
  if (shortGPS.getMarker())
  {
    shortGPS.getMap().removeOverlay(shortGPS.getMarker());
    shortGPS.setMarker(null);
  }
  $(".js-addr-not-found").hide();
  $(".js-drag-info").hide();
  $(".js-use-info").show();
};

ShortGPS.prototype.geocode = function(_location)
{
  shortGPS.clearInfoWindow();

  this.getGeocoder().setViewport(this.getMap().getBounds());
  this.getGeocoder().getLocations(_location,
    function(result){
      
      // Hide this before showing the other hints
      $(".js-use-info").hide();
      
      if (result && result.Status.code == 200)
      {
        // get geocoded position
        var lat = result.Placemark[0].Point.coordinates[1];
        var lng = result.Placemark[0].Point.coordinates[0];
        lat = lat.toFixed(5);
        lng = lng.toFixed(5);

        shortGPS.getAddress(lat, lng, function(address) {
          var marker = shortGPS.makeDragMarker(lat, lng, true);
          shortGPS.showInfoMovable(address, marker);
          $(".js-drag-info").show();
        });
      }
      else
      {
        $(".js-addr-not-found").show();
        $(".js-drag-info").hide();
      }
    }
  );
};

ShortGPS.prototype.getAddress = function(lat, lng, callback)
{
  shortGPS.getGeocoder().getLocations(lat + " " + lng, function(result)
      {
        var address;
        if (result && result.Status.code == 200)
        {
          address = result.Placemark[0].address;
        }
        else
        {
          address = lat + " " + lng;
        }

        callback(address);
      });
};

ShortGPS.prototype.makeFixedMarker = function(lat, lng, setCenter)
{
  var pos = new google.maps.LatLng(lat, lng);

  // center map to position
  if (setCenter)
  {
    shortGPS.getMap().setCenter(pos, 15);
  }

  // create & show a marker
  var icon = new google.maps.Icon(G_DEFAULT_ICON);
  icon.image = "images/drag_Marker.png";
  var marker = new google.maps.Marker(pos, { draggable:false, icon:icon });
  shortGPS.setMarker(marker);
  shortGPS.getMap().addOverlay(marker);

  return marker;
};

ShortGPS.prototype.makeDragMarker = function(lat, lng, setCenter, _icon)
{
  var pos = new google.maps.LatLng(lat, lng);

  // center map to position
  if (setCenter)
  {
    shortGPS.getMap().setCenter(pos, 15);
  }

  // create & show a marker
  var icon = new google.maps.Icon(G_DEFAULT_ICON);
  if (_icon)
  {
    icon.image = _icon;
  }
  else
  {
    icon.image = "images/drag_Marker.png";
  }
  var marker = new google.maps.Marker(pos, { draggable:true, icon:icon });
  shortGPS.setMarker(marker);
  shortGPS.getMap().addOverlay(marker);

  return marker;
};

ShortGPS.prototype.showInfoMovable = function(address, marker, alias, movelast, showLocTweets, extlink, hashTag)
{
  var lat = marker.getLatLng().lat();
  var lng = marker.getLatLng().lng();
  lat = parseFloat(lat).toFixed(5);
  lng = parseFloat(lng).toFixed(5);

  var updateFunc = function()
    {
      var _lat = marker.getLatLng().lat();
      var _lng = marker.getLatLng().lng();
      _lat = parseFloat(_lat).toFixed(5);
      _lng = parseFloat(_lng).toFixed(5);
      shortGPS.getAddress(_lat, _lng, function(_address) {
        address = _address;
        marker.closeInfoWindow();
        shortGPS.showInfoMovable(_address, marker, alias, true, showLocTweets, extlink, hashTag);
      });
    };

  shortGPS.addIWListener(google.maps.Event.addListener(marker, "dragstart", function() {
    marker.closeInfoWindow();
    var dragEndHandler = google.maps.Event.addListener(marker, "dragend", function() { 
        google.maps.Event.removeListener(dragEndHandler);
        updateFunc(); 
      });
  }));
  shortGPS.addIWListener(google.maps.Event.addListener(shortGPS.getMap(), "zoomend", updateFunc));
  shortGPS.addIWListener(google.maps.Event.addListener(shortGPS.getMap(), "maptypechanged", updateFunc));

  shortGPS.showInfo(marker, lat, lng, 0, 0, 0, address, true, null, alias, movelast, showLocTweets, extlink, hashTag);

  google.maps.Event.clearListeners(marker, "click");
  var clickHandler = google.maps.Event.addListener(marker, "click", function() {
        google.maps.Event.removeListener(clickHandler);
        shortGPS.showInfoMovable(address, marker, alias, true, showLocTweets, extlink, hashTag);
      });
};

ShortGPS.prototype.showInfo = function(marker, lat, lng, pi_today, pi_total, created_at, address, make_sglink, _url, _alias, _movelast, showLocTweets, _extlink, _hashTag)
{
  var iwContent = new Pigaia.Template("info_window");
  iwContent.updateField("js-address", address);
  iwContent.updateField("js-lat", lat);
  iwContent.updateField("js-lng", lng);
  iwContent.updateField("js-hits-today", pi_today);
  iwContent.updateField("js-hits-total", pi_total);
  iwContent.updateField("js-created", shortGPS.dateDiff(new Date(created_at*1000)));
  iwContent.getField("js-created").attr("title", new Date(created_at*1000));
  iwContent.getField("js-tweets").attr("id", "tweetappend");

  var tweetTextUpdateFunc = function() {
      var text = iwContent.getFormValue("js-tweet-text", true);
      iwContent.updateField("js-tweet-chars-left", sgMaxTweetLen - text.length);
      shortGPS.setCookie("TOA-RETURN-TWEET", text);

      if (text.length > sgMaxTweetLen)
      {
        iwContent.getField("js-twitter-send").attr("disabled", "disabled");
        iwContent.getField("js-twitter-send").addClass("ui-state-disabled");
        iwContent.getField("js-twitter-send").removeClass("ui-state-default");
      }
      else
      {
        iwContent.getField("js-twitter-send").removeAttr("disabled");
        iwContent.getField("js-twitter-send").removeClass("ui-state-disabled");
        iwContent.getField("js-twitter-send").addClass("ui-state-default");
      }
    };

  var searchTweetsNear = function (_lat, _lng)
  {
    iwContent.getField("js-tweets").empty();

    shortGPS.anonRequest("GetLocTweets", { lat:lat, lng:lng, start:0, count:10, maxdist:10 },
        function(result)
        {
          if (!result.tweet || shortGPS.getArrayLength(result.tweet) == 0)
          {
            // no tweets at this place
            iwContent.updateField("js-tweets", "none found");
            return;
          }

          for (var i=0; i<shortGPS.getArrayLength(result.tweet); i++)
          {
            var tw = shortGPS.getArrayValue(result.tweet, i);

            var tweet = new Pigaia.Template("tweet");
            tweet.updateFieldHTML("js-textlink", shortGPS.autolink(shortGPS.escapeHTML(tw.text)));
            //tweet.getField("js-textlink").attr("href", sgTwitterURL + "/" + tw.twitter_uname + "/statuses/" + tw.twitterid);
            tweet.updateField("js-authorlink", tw.twitter_uname);
            tweet.getField("js-authorlink").attr("href", sgTwitterURL + "/" + tw.twitter_uname);
            tweet.getField("js-authorpiclink").attr("href", sgTwitterURL + "/" + tw.twitter_uname);
            tweet.getField("js-authorpic").attr("alt", tw.twitter_uname);
            tweet.getField("js-authorpic").attr("title", tw.twitter_uname);
            tweet.getField("js-authorpic").attr("src", tw.twitter_avatar);
            var jsDate = new Date(tw.created_at*1000);
            tweet.updateField("js-date", shortGPS.dateDiff(jsDate));
            tweet.getField("js-date").attr("title", jsDate);
            tweet.getField("js-rt-link").click(function(a,t) { return function()
              {
                var tweetText = "RT @" + a + ": " + t;
                iwContent.setFormValue("js-tweet-text", tweetText);
                iwContent.getField("js-tweet-text").focus();
                shortGPS.setCookie("TOA-RETURN-TWEET", tweetText);
                tweetTextUpdateFunc();
                return false;
              }; }(tw.twitter_uname, tw.text));
            tweet.getField("js-reply-link").click(function(a) { return function()
              {
                var tweetText = "@" + a + ": ";
                iwContent.setFormValue("js-tweet-text", "@" + a + ": ");
                iwContent.getField("js-tweet-text").focus();
                shortGPS.setCookie("TOA-RETURN-TWEET", tweetText);
                tweetTextUpdateFunc();
                return false;
              }; }(tw.twitter_uname));
            $("#tweetappend").append(tweet.getNode());
          }
        });
  };


  if (showLocTweets)
  {
    iwContent.getField("js-tweetlist").show();
    iwContent.getField("js-tweetlist").removeClass("hide");
    iwContent.getField("js-twitter-section").removeClass("h_200");
    iwContent.getField("js-twitter-section").addClass("h_300");
  }
  else
  {
    iwContent.getField("js-twitter-section").removeClass("h_300");
    iwContent.getField("js-twitter-section").addClass("h_200");
  }

  iwContent.getField("js-tweet-text").keyup(tweetTextUpdateFunc);
  // Firefox event for right-click paste
  iwContent.getField("js-tweet-text").bind("input", tweetTextUpdateFunc);
  // IE event for right-click paste
  iwContent.getField("js-tweet-text").bind("paste", function() { window.setTimeout(tweetTextUpdateFunc, 100); } );
  // Safari: no event known :(

  var tweetURL = _url;
  iwContent.getField("js-twitter-send").click(function() {
      shortGPS.anonRequest("SendTweet", { text: iwContent.getFormValue("js-tweet-text"), url:tweetURL }, function(result) {
          if (result.status != 0)
          {
            // FIXME - error message
            return;
          }

          iwContent.setFormValue("js-tweet-text", "");
          shortGPS.deleteCookie("TOA-RETURN-TWEET");

          // update tweets
          marker.closeInfoWindow();
          if (make_sglink)
          {
            shortGPS.showInfoMovable(address, marker, _alias, true, true, _extlink, _hashTag);
          }
          else
          {
            shortGPS.showInfo(marker, lat, lng, pi_today, pi_total, created_at, address, make_sglink, _url, _alias, _movelast, true, _extlink, _hashTag);
          }
        });
    });

  iwContent.getField("js-twitter-signin").click(function() {
    shortGPS.anonRequest("GetTwitterOAuthURL", { dummy:0 }, function(result) {
      if (shortGPS.getCookie("TOA-RETURN-URL"))
      {
        shortGPS.setCookie("TOA-RETURN", 1);
      }
      window.location.href = result.url;
    });
    return false;
  });

  if (shortGPS.getTwitterUID() >= 0)
  {
    iwContent.getField("js-twitter-signin").hide();
    iwContent.getField("js-twitter-send").show();
    // Safari Fix
    iwContent.getField("js-twitter-send").css("display", "block");
  }
  else
  {
    iwContent.getField("js-twitter-signin").show();
    iwContent.getField("js-twitter-send").hide();
  }

  if (make_sglink)
  {
    var maptype = eMapTypeNormal;
    if      (shortGPS.getMap().getCurrentMapType() == G_NORMAL_MAP)    { maptype = eMapTypeNormal;    }
    else if (shortGPS.getMap().getCurrentMapType() == G_SATELLITE_MAP) { maptype = eMapTypeSatellite; }
    else if (shortGPS.getMap().getCurrentMapType() == G_HYBRID_MAP)    { maptype = eMapTypeHybrid;    }
    else if (shortGPS.getMap().getCurrentMapType() == G_PHYSICAL_MAP)  { maptype = eMapTypePhysical;  }

    var params = {
          lat:     lat,
          lng:     lng,
          zoom:    shortGPS.getMap().getZoom(),
          maptype: maptype,
          move:    _movelast ? true : false,
          link:    _extlink ? _extlink : ""
        };

    if (_alias)
    {
      params.alias = _alias;
    }

    shortGPS.anonRequest("ShortGPS", params,
        function(result)
        {
          if (result.status == eAliasTaken)
          {
            // FIXME - Problemanzeige!
            iwContent.setFormValue("js-custom-link-name", "");
          }
          else if (result.status != 0)
          {
            return;
          }
          else if (_alias)
          {
            iwContent.setFormValue("js-custom-link-name", _alias);
          }
          iwContent.setFormValue("js-extlink-input", _extlink);

          if (!showLocTweets && result.has_tweets_nearby)
          {
            iwContent.getField("js-tweetlist").show();
            iwContent.getField("js-tweetlist").removeClass("hide");
            showLocTweets = true;
            //searchTweetsNear(lat, lng);
            iwContent.getField("js-twitter-section").removeClass("h_200");
            iwContent.getField("js-twitter-section").addClass("h_300");
          }
          else
          {
            if (!showLocTweets)
            {
              iwContent.getField("js-twitter-section").removeClass("h_300");
              iwContent.getField("js-twitter-section").addClass("h_200");
            }
          }

          tweetURL = result.url;
          shortGPS.setCookie("TOA-RETURN-URL", result.url);
          shortGPS.setCookie("TOA-RETURN-URL-TYPE", "movable");

          //var sgURL = document.URL.match(/http:\/\/([^\/]+).*/)[1];
          var sgURL = "shortgps.com";
          var url = sgURL + "/" + result.url;
          var fullUrl = "http://" + url;

          if (_movelast)
          {
            var tweetText = shortGPS.getLastTweetText();
            tweetText = tweetText.replace(/http:\/\/shortgps.com\/[0-9a-zA-Z_\-]+/, fullUrl);
            iwContent.setFormValue("js-tweet-text", tweetText);
          }
          else
          {
            shortGPS.setLastTweetText("");
            iwContent.setFormValue("js-tweet-text", fullUrl + (_hashTag ? " #" + _hashTag : ""));
          }
          tweetTextUpdateFunc();

          var hIWOpen = google.maps.Event.addListener(shortGPS.getMap(), "infowindowopen", function()
              {
                google.maps.Event.removeListener(hIWOpen);
                iwContent.getField("js-link-section").show();
                iwContent.getField("js-extlink-edit-section").show();
                iwContent.getField("js-extlink-display-section").removeClass("clearfix");
                shortGPS.updateButtonHoverEvents();
                if (showLocTweets)
                {
                  searchTweetsNear(lat, lng);
                }
                
                window.setTimeout(function()
                      {
                        var clip = new ZeroClipboard.Client();
                        clip.setText(fullUrl);
                        clip.glue( iwContent.getField("js-urlcopy").get(0) );

                        shortGPS.addIWListener(google.maps.Event.addListener(shortGPS.getMap(), "infowindowbeforeclose", function() { if (clip) { clip.hide(); clip.destroy(); clip = null; }} ));
                        shortGPS.addIWListener(google.maps.Event.addListener(shortGPS.getMap(), "moveend", function() { if (clip) clip.reposition(); } ));
                        shortGPS.addIWListener(google.maps.Event.addListener(shortGPS.getMap(), "infowindowclose", function()
                          {
                            shortGPS.deleteCookie("TOA-RETURN-URL");
                            shortGPS.setLastTweetText(iwContent.getFormValue("js-tweet-text", true));
                            shortGPS.clearIWListeners();
                          }));
                      }, 1000);

                var aliasValid = false;
                var oldURL = url;

                var clearCustomizeFunc = function(resetUrl) {
                    iwContent.getField("js-custom-link-err-illegal").hide();
                    iwContent.getField("js-custom-link-err-taken").hide();
                    iwContent.getField("js-custom-link-help1").hide();
                    iwContent.getField("js-custom-link-help2").hide();
                    iwContent.getField("js-sglink-input").removeClass("shortlink_custom")
                                                         .css("color", "black")
                                                         .unbind("keypress")
                                                         .unbind("keydown")
                                                         .unbind("keyup")
                                                         .unbind("blur")
                                                         .attr("readonly", "readonly");
                    iwContent.getField("js-customize").focus();
                    if (resetUrl)
                    {
                      iwContent.setFormValue("js-sglink-input", fullUrl);
                    }
                  };

                iwContent.getField("js-customize").click(function()
                    {
                      iwContent.getField("js-sglink-input").addClass("shortlink_custom")
                                                           .removeAttr("readonly")
                                                           .focus()
                                                           .unbind("keypress")
                                                           .keypress(function(event) {
                        if (event)
                        {
                          if (event.keyCode == 13)
                          {
                            if (aliasValid)
                            {
                              var desAlias = iwContent.getFormValue("js-sglink-input").match(/^http:\/\/[^\/]+\/(.*)/)[1];
                              if (desAlias != "" && ("shortgps.com/" + desAlias) != url)
                              {
                                clearCustomizeFunc(false);
                                marker.closeInfoWindow();
                                shortGPS.showInfoMovable(address, marker, desAlias, true, showLocTweets, _extlink, _hashTag);
                              }
                              else
                              {
                                clearCustomizeFunc(true);
                              }
                            }
                          }
                          else if (event.keyCode == 27)
                          {
                            clearCustomizeFunc(true);
                          }
                        }
                      });

                      iwContent.getField("js-sglink-input").unbind("blur")
                                                           .blur(function(){
                          clearCustomizeFunc(true);
                        });

                      iwContent.getField("js-sglink-input").unbind("keydown")
                                                           .keydown(function(){
                          if (iwContent.getFormValue("js-sglink-input").match(/^http:\/\/shortgps\.com\/.*/))
                          {
                            oldURL = iwContent.getFormValue("js-sglink-input");
                          }
                        });

                      iwContent.getField("js-custom-link-help1").show();
                      iwContent.getField("js-sglink-input").unbind("keyup")
                                                           .keyup(function(){
                          if (!iwContent.getFormValue("js-sglink-input").match(/^http:\/\/shortgps\.com\/.*/))
                          {
                            iwContent.setFormValue("js-sglink-input", oldURL);
                            //return;
                          }
                          var daMatch = iwContent.getFormValue("js-sglink-input").match(/^http:\/\/[^\/]+\/(.*)/);
                          if (!daMatch)
                          {
                            return;
                          }
                          var desiredAlias = daMatch[1];
                          if (desiredAlias.match(/^[a-zA-Z0-9\-_]*$/))
                          {
                            iwContent.getField("js-custom-link-err-illegal").hide();
                            if (desiredAlias == "" || ("shortgps.com/" + desiredAlias) == url)
                            {
                              iwContent.getField("js-custom-link-err-taken").hide();
                              iwContent.getField("js-custom-link-help1").show();
                              iwContent.getField("js-custom-link-help2").hide();
                              iwContent.getField("js-sglink-input").css("color", "black");
                              aliasValid = true;
                            }
                            else
                            {
                              shortGPS.anonRequest("CheckAlias", { alias : desiredAlias }, function(result){
                                aliasValid = (result.status == 0);
                                if (aliasValid)
                                {
                                  iwContent.getField("js-custom-link-err-taken").hide();
                                  iwContent.getField("js-custom-link-help1").hide();
                                  iwContent.getField("js-custom-link-help2").show();
                                  iwContent.getField("js-sglink-input").css("color", "black");
                                }
                                else
                                {
                                  iwContent.getField("js-custom-link-err-taken").show();
                                  iwContent.getField("js-custom-link-help1").hide();
                                  iwContent.getField("js-custom-link-help2").hide();
                                  iwContent.getField("js-sglink-input").css("color", "red");
                                }
                              });
                            }
                          }
                          else
                          {
                            aliasValid = false;
                            iwContent.getField("js-sglink-input").css("color", "red");
                            iwContent.getField("js-custom-link-err-illegal").show();
                            iwContent.getField("js-custom-link-err-taken").hide();
                            iwContent.getField("js-custom-link-help1").hide();
                            iwContent.getField("js-custom-link-help2").hide();
                          }
                        });
                    });

                var updateExtLinkFunc = function()
                {
                  var extlink = iwContent.getFormValue("js-extlink-input");
                  marker.closeInfoWindow();
                  shortGPS.showInfoMovable(address, marker, _alias, true, showLocTweets, extlink, _hashTag);
                }

                iwContent.getField("js-extlink-save").click(updateExtLinkFunc);
                iwContent.getField("js-extlink-input").keypress(function(event)
                  {
                    if (event && event.keyCode == 13) { updateExtLinkFunc(); }
                  });

                iwContent.updateField("js-hits-today", result.pi_today);
                iwContent.updateField("js-hits-total", result.pi_total);
                iwContent.updateField("js-created", shortGPS.dateDiff(new Date(result.created_at*1000)));
                iwContent.getField("js-created").attr("title", new Date(result.created_at*1000));
              });

          iwContent.setFormValue("js-sglink-input", "http://" + url);
          marker.openInfoWindow(iwContent.getNodeElement());
        });
  }
  else
  {
    shortGPS.setCookie("TOA-RETURN-URL", _url);
    shortGPS.setCookie("TOA-RETURN-URL-TYPE", "fixed");
    iwContent.getField("js-link-section").removeClass("clearfix");
    iwContent.getField("js-extlink-edit-section").removeClass("clearfix");
    if (_extlink && _extlink.length > 0)
    {
      iwContent.getField("js-extlink-display-section").show();
      iwContent.updateField("js-extlink-display", _extlink);
      iwContent.getField("js-extlink-display").attr("href", _extlink);
    }
    else
    {
      iwContent.getField("js-extlink-display-section").removeClass("clearfix");
    }

    var hIWOpen = google.maps.Event.addListener(shortGPS.getMap(), "infowindowopen", function()
        {
          if (showLocTweets)
          {
            searchTweetsNear(lat, lng);
          }
          shortGPS.setLastTweetText("");
          iwContent.setFormValue("js-tweet-text", "http://shortgps.com/" + _url + (_hashTag ? " #" + _hashTag : ""));
          tweetTextUpdateFunc();

          google.maps.Event.removeListener(hIWOpen);
          shortGPS.updateButtonHoverEvents();
        });

    marker.openInfoWindow(iwContent.getNodeElement());
  }
};

/**
* make a non-authenticated request (will retry once on errors)
* @param{String} url URL of the WebService ERP
* @param{object} params Map of parameters to pass to the WS
* @param{function} callback function to call with the results from the WS
* @param{boolean} is_retry setting to true indicates that this is a retry, which will not trigger another retry
*/
ShortGPS.prototype.anonRequest = function(url, params, callback, is_retry)
{
  $.ajax( {
    url : '/pws/ShortGPSService/'+url,
    data : params,
    type : "POST",
    success : function(datatrans)
      {
        var responsedata = shortGPS.xml2obj(datatrans)[url+'Response'];
        if (callback) callback(responsedata);
      },
      error : (is_retry ? null : function()
      {
        shortGPS.anonRequest(url, params, callback, true);
      })
    }
  );
};

ShortGPS.prototype.getArrayLength = function(_arr)
{
  if (typeof _arr=="string")
  {
    return 1;
  }
  return _arr == undefined ? 0 : (_arr.length ? _arr.length : 1);
};

ShortGPS.prototype.getArrayValue = function(_arr, _idx)
{
  if (typeof _arr=="string")
  {
    return _arr;
  }
  return (_arr && _arr.length) ? _arr[_idx] : _arr;
};

ShortGPS.prototype.xml2obj = function(xml)
{
  if (xml.childNodes.length == 0)
  {
    if (xml.nodeValue == null)
    {
      return "";
    }
    else
    {
      if (xml.nodeValue.match(/^\-?\d+$/))
      {
        return parseInt(xml.nodeValue);
      }
      else if (xml.nodeValue.match(/^\-?\d*\.?\d+$/))
      {
        return parseFloat(xml.nodeValue);
      }
      else if (xml.nodeValue.match(/^true$/))
      {
        return true;
      }
      else if (xml.nodeValue.match(/^false$/))
      {
        return false;
      }
      else
      {
        return xml.nodeValue;
      }
    }
  }

  var node = {};

  for (var i=0; i<xml.childNodes.length; i++)
  {
    var childNode = xml.childNodes[i];
    var childName = (!!childNode.localName)?childNode.localName:childNode.baseName;

    if (childName == null || childName == "")
    {
      node = null;
      return shortGPS.xml2obj(childNode);
    }
    else if (node[childName] == null || typeof node[childName] == "undefined")
    {
      node[childName] = shortGPS.xml2obj(childNode);
    }
    else if (node[childName].__isArray)
    {
      node[childName][node[childName].length] = shortGPS.xml2obj(childNode);
    }
    else
    {
      var oldval = node[childName];
      node[childName] = new Array();
      node[childName].__isArray = true;
      node[childName][0] = oldval;
      node[childName][1] = shortGPS.xml2obj(childNode);
      oldval = null;
    }
  }

  childNode = null;
  childName = null;

  return node;
};

ShortGPS.prototype.dateDiff = function(date)
{
  var makeDate = function(num, unit)
  {
    return num + " " + unit + (num == 1 ? "" : "s") + " ago";
  };

  var seconds = parseInt((new Date() - Date.parse(date)) / 1000);
  if (seconds < 60) return makeDate(seconds, "second");
  var minutes = parseInt(seconds / 60);
  if (minutes < 60) return makeDate(minutes, "minute");
  var hours = parseInt(minutes / 60);
  if (hours < 24) return makeDate(hours, "hour");
  var days = parseInt(hours / 24);
  if (days < 7) return makeDate(days, "day");
  var weeks = parseInt(days / 7);
  if (weeks < 5) return makeDate(weeks, "week");
  var months = parseInt(days / 30.5);
  if (months < 12) return makeDate(months, "month");
  var years = parseInt(days / 365);
  return makeDate(years, "year");
};

ShortGPS.prototype.resizeMap = function(alUpdate)
{
  var height = document.documentElement.clientHeight-
          ($("#canvas").height() + $("#footer").height());
  $("#map").height(height);

  shortGPS.getMap().checkResize();

  if (alUpdate)
  {
    shortGPS.updateAllLocLayer();
  }
};

ShortGPS.prototype.setCookie =  function(name,value,expire)
{
  var domain = "." + document.URL.match(/http:\/\/([^\/]+).*/)[1];

  if (expire)
  {
    var a = new Date();
    a = new Date(a.getTime() +expire);
    document.cookie = name+'='+escape(value)+'; domain='+domain+'; expires='+a.toGMTString()+';';
  }
  else
  {
    document.cookie = name+'='+escape(value)+'; domain='+domain+';';
  }
};

ShortGPS.prototype.getCookie = function(name)
{
  var a = document.cookie;
  var res = '';
  while (a != '')
  {
    var cookiename = a.substring(0,a.search('='));
    var i = a.search(';');
    if (i == -1)
    {
      i = a.length;
    }
    var cookievalue = a.substring(a.search('=')+1,i);
    if (cookievalue == '')
    {
      cookievalue = a.substring(a.search('=')+1,a.length);
    }

    if(name == cookiename)
    {
      res = cookievalue;
    }

    i = a.search(';')+1;
    if (i == 0)
    {
      i = a.length;
    }
    a = a.substring(i,a.length);
    a = $.trim(a);
  }
  return unescape(res)
};

ShortGPS.prototype.deleteCookie = function(name)
{
  var domain = "." + document.URL.match(/http:\/\/([^\/]+).*/)[1];
  document.cookie = name+'=; domain='+domain+'; expires=Thu, 01-Jan-70 00:00:01 GMT;';
};

ShortGPS.prototype.formatDate = function(_unixtime, _withtime)
{
  var date = new Date(_unixtime*1000);
  var day = date.getDate();
  if (day < 10)
  {
    day = "0" + day;
  }
  var month = date.getMonth()+1;
  if (month < 10)
  {
    month = "0" + month;
  }

  var fdate = date.getFullYear()+"-"+month+"-"+day;
  if (_withtime)
  {
    var minutes = date.getMinutes();
    if (minutes < 10)
      minutes = "0" + minutes;

    fdate += ", " + date.getHours() + ":" + minutes;
  }
  return fdate;
};

ShortGPS.prototype.updateButtonHoverEvents = function()
{
  $("button").unbind("hover");
  $("button").hover(function() { $(this).addClass("ui-state-hover");   $(this).removeClass("ui-state-default"); },
                    function() { $(this).addClass("ui-state-default"); $(this).removeClass("ui-state-hover");   });
};

ShortGPS.prototype.autolink = function(txt)
{
  // URLs
  var regex = /https?:\/\/\S+/gi;
  txt = txt.replace(regex, function(value){
      return '<a href="' + value + '" target="_blank">' + value + '</a>';
  });

  // twitter users
  regex = /@\w+/g;
  txt = txt.replace(regex, function(value){
      value = value.match(/@(\w+)/)[1];
      return '<a href="http://twitter.com/' + value + '" target="_blank">@' + value + '</a>';
  });

  // hash tags
  regex = /#\w+/g;
  txt = txt.replace(regex, function(value){
      value = value.match(/#(\w+)/)[1];
      return '<a href="http://search.twitter.com/search?q=%23' + value + '" target="_blank">#' + value + '</a>';
  });

  return txt;
};

ShortGPS.prototype.escapeHTML = function(txt)
{
  txt = txt.replace(/</g, "&lt;");
  txt = txt.replace(/>/g, "&gt;");
  txt = txt.replace(/\n/g, "<br/>");

  return txt;
};
