console.log("%c p5.geolocation Loaded ", "color:pink; background:black; ");


/**
* Check if location services are available
*
* Returns true if geolocation is available
*
* @method locationCheck
* @return {boolean} true if geolocation is available
*/
p5.prototype.geoCheck = function(){
  if (navigator.geolocation) {
    return true;
  }else{
    return false;
  }

}

/**
* Get User's Current Position
*
* Gets the users current position. Can be used in preload(), or as a callback.
*
* @method getCurrentPosition
* @param  {function} a callback to handle the current position data
* @param  {function} a callback to handle an error
* @return {object} an object containing the users position data
*/
p5.prototype.getCurrentPosition = function(callback, errorCallback) {

  var ret = {};
  var self = this;

  if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(success, geoError);
  }else{
    geoError("geolocation not available");
  };

  function geoError(message){
    console.log(message.message);
    ret.error = message.message;
    if(typeof errorCallback == 'function'){ errorCallback(message.message) };
  }

  function success(position){
      // console.log(position);

      //get the entire position object....
      // //see the p5.js github libraries wiki page for more info on what is going on here.
      // for(var k in position){
      //   if (typeof position[k] == 'object'){
      //     ret[k] = {};
      //     for(var x in position[k]){
      //       ret[k][x] = position[k][x];
      //     }
      //   } else {
      //     ret[k] = position[k];
      //   }
      // }

      //get only the coords part of the position object
    for(var x in position.coords){
      ret[x] = position.coords[x];
      ret['timestamp'] = position.timestamp;
    }
    if (typeof self._decrementPreload === 'function') { self._decrementPreload() };
    if(typeof callback == 'function'){ callback(position.coords) };
  }

  return ret;
};

//add the get Current position to the preload stack.
p5.prototype.registerPreloadMethod('getCurrentPosition', p5.prototype);

/**
* Get User's Current Position on an interval
*
* Gets the users current position on an interval. Can be useful if watchPosition is not responsive enough. This can be a resource hog (read:battery) as it is calling the getPosition at the rate of your interval. Set it long for less intense usage.
*
* @method getCurrentPosition
* @param  {function} a callback to handle the current position data
* @param  {function} an interval in MS
* @param  {function} a callback to handle an error
*/
p5.prototype._intervalPosition = null;
p5.prototype.intervalCurrentPosition = function(callback, interval,  errorCallback){

  var gogogadget = 5000;
  gogogadget = interval;

  if (navigator.geolocation) {

    _intervalPosition = setInterval(function(){

      console.log("pos");
      navigator.geolocation.getCurrentPosition(success, geoError);

    }, gogogadget)

  }else{
    geoError("geolocation not available");
  };

    function geoError(message){
      console.log(message.message);
       if(typeof errorCallback == 'function'){ errorCallback(message.message) };
    }

    function success(position){
      if(typeof callback == 'function'){ callback(position.coords) };
    }
}

/**
* Clear interval Position
*
* clears the current intervalCurrentPosition()
*
* @method clearIntervalPos()
*/
p5.prototype.clearIntervalPos = function(){
  window.clearInterval(_intervalPosition);
}

/**
* Watch User's Current Position
*
* Watches the users current position
*
* @method watchPosition
* @param  {function} a callback to handle the current position data
* @param  {function} a callback to handle an error
* @param  {object} an positionOptions object: enableHighAccuracy, maximumAge, timeout
*/
p5.prototype._posWatch = null;
p5.prototype.watchPosition = function(callback, errorCallback, options){

  if (navigator.geolocation) {
    _posWatch = navigator.geolocation.watchPosition(success, geoError, options);
  }else{
    geoError("geolocation not available");
  };

  function geoError(message){
      console.log("watch Postition Error" + message);
       if(typeof errorCallback == 'function'){ errorCallback(message.message) };
    }

  function success(position){
        if(typeof callback == 'function'){ callback(position.coords) };
        // console.log(_posWatch);
  }

}

/**
* Clear the watchPosition
*
* clears the current watchPosition
*
* @method clearWatch
*/
p5.prototype.clearWatch = function(){
  navigator.geolocation.clearWatch( _posWatch );
}

/**
* Calculate the Distance between two points
*
*
* @method watchPosition
* @param  {float} latitude of the first point
* @param  {float} longitude of the first point
* @param  {float} latitude of the second point
* @param  {float} longitude of the second point
* @param  {string} units to use: 'km' or 'mi', 'mi' is default if left blank
* @return {float} the distance between the two points in the specified units, miles is default
*/

// http://www.movable-type.co.uk/scripts/latlong.html
// Used Under MIT License
p5.prototype.calcGeoDistance = function(lat1, lon1, lat2, lon2, units) {
  if(units == 'km'){
     var R = 6371; //earth radius in KM
  }else{
    var R = 3959; // earth radius in Miles (default)
  }
    var dLat = (lat2-lat1) * (Math.PI / 180);
    var dLon = (lon2-lon1) * (Math.PI / 180);
    var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
            Math.cos(lat1 * (Math.PI / 180)) * Math.cos(lat2 * (Math.PI / 180)) *
            Math.sin(dLon/2) * Math.sin(dLon/2);
    var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
    var d = R * c;
    return d;
  }


/**
* Calculate if a Location is inside Polygon
*
*
* @method watchPosition
* @param  {float} Array of Objects with lat: and lon:
* @param  {float} Object with lat and long of my location
* @return {boolean} true if geolocation is within polygon
*/

// http://jsfromhell.com/math/is-point-in-poly
// Adapted from: [http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html]
// Used Under MIT License
p5.prototype.isLocationInPolygon = function(poly, pt){
    for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
        ((poly[i].lon <= pt.lon && pt.lon < poly[j].lon) || (poly[j].lon <= pt.lon && pt.lon < poly[i].lon))
        && (pt.lat < (poly[j].lat - poly[i].lat) * (pt.lon - poly[i].lon) / (poly[j].lon - poly[i].lon) + poly[i].lat)
        && (c = !c);
    return c;
}



/**
* Create a new geoFenceCircle
*
* Watches the users current position and checks to see if they are witihn a set radius of a specified point.
*
* @method watchPosition
* @param  {float} latitude of the first point
* @param  {float} longitude of the first point
* @param  {float} distance from the point to trigger the insideCallback
* @param  {function} a callback to fire when the user is inside the geoFenceCircle
* @param  {function} a callback to fire when the user is outside the geoFenceCircle
* @param  {string} units to use: 'km' or 'mi', 'mi' is default if left blank
* @param  {object} an positionOptions object: enableHighAccuracy, maximumAge, timeout
*/
p5.prototype.geoFenceCircle = function(lat, lon, fence, insideCallback, outsideCallback, units, options){

  this.lat = lat;
  this.lon = lon;
  this.fence = fence;
  this.units = units; //this should work since calcGeoDistance defaults to miles.
  this.distance = 0.0;
  this.insideCallback = insideCallback;
  this.outsideCallback = outsideCallback;
  this.insideFence = false;
  this.options = options;
  this.id = '';

    this.geoError = function(message){
      console.log("geoFenceCircle Error :" + message);
    }

    this.success = function(position){
      this.distance = calcGeoDistance(this.lat,this.lon, position.coords.latitude, position.coords.longitude, this.units);

      if(this.distance <= this.fence){
          if(typeof this.insideCallback == 'function'){ this.insideCallback(position.coords) };
          this.insideFence = true;
      }else{
        if(typeof this.outsideCallback == 'function'){ this.outsideCallback(position.coords) };
        this.insideFence = false;
      }
    }

    this.clear = function() {
      if (this.id) {
        navigator.geolocation.clearWatch(this.id);
        this.id = '';
      }
    }

    if (navigator.geolocation) {
      // bind the callbacks to the geoFenceCircle 'this' so we can access, this.lat, this.lon, etc..
      this.id = navigator.geolocation.watchPosition(this.success.bind(this), this.geoError.bind(this), this.options);
    }else{
      geoError("geolocation not available");
    };
}





/**
* Create a new geoFencePolygon
*
* Watches the users current position and checks to see if they are witihn a set radius of a specified point.
*
* @method watchPosition
* @param  {float} latitude of the first point
* @param  {float} longitude of the first point
* @param  {float} distance from the point to trigger the insideCallback
* @param  {function} a callback to fire when the user is inside the geoFenceCircle
* @param  {function} a callback to fire when the user is outside the geoFenceCircle
* @param  {string} units to use: 'km' or 'mi', 'mi' is default if left blank
* @param  {object} an positionOptions object: enableHighAccuracy, maximumAge, timeout
*/


/*var points = [
    {x: 34.076089, y: -118.440915},
    {x: 34.076095, y: -118.440605},
    {x: 34.075906, y: -118.440597},
    {x: 34.075891, y: -118.440932},
];*/
p5.prototype.geoFencePolygon = function( ArrayOfObjectsWithLatLong, insideCallback, outsideCallback, units, options){

  this.ArrayOfObjectsWithLatLong = ArrayOfObjectsWithLatLong;
  this.units = units; //this should work since calcGeoDistance defaults to miles.
  this.insideCallback = insideCallback;
  this.outsideCallback = outsideCallback;
  this.insideFence = false;
  this.options = options;
  this.id = '';

    this.geoError = function(message){
      console.log("geoFencePolygon Error :" + message);
    }

    this.success = function(position){
      this.insideFence = isLocationInPolygon(this.ArrayOfObjectsWithLatLong, { lat:position.coords.latitude, lon: position.coords.longitude });

      if(this.insideFence == true){
          if(typeof this.insideCallback == 'function'){ this.insideCallback(position.coords) };
      }else{
        if(typeof this.outsideCallback == 'function'){ this.outsideCallback(position.coords) };
      }
    }

    this.clear = function() {
      if (this.id) {
        navigator.geolocation.clearWatch(this.id);
        this.id = '';
      }
    }

    if (navigator.geolocation) {
      // bind the callbacks to the geoFenceCircle 'this' so we can access, this.lat, this.lon, etc..
      this.id = navigator.geolocation.watchPosition(this.success.bind(this), this.geoError.bind(this), this.options);
    }else{
      geoError("geolocation not available");
    };
}
