// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults

Array.prototype.remove = function(value) {
    for (var i = 0; i < this.length; ++i) {
        if (this[i] == value) {
            while (i < this.length-1) {
                this[i] = this[i+1];
                ++i;
            }
            this.pop();
            break;
        }
    }
};

Array.prototype.clear = function() {
    while (this.length > 0) {
        this.pop();
    }
};

Array.prototype.insert = function(pos, value) {
    return this.splice(pos, 0, value);
};

function getChildElementById(parent, id) { 
    var elements = parent.getElementsByTagName('*');
    for (var i = 0; i < elements.length; ++i) {
        if (elements[i].id == id) {
            return elements[i];
        }
    }
    return null;
}

var app;

function Point(map, options) { 
} 
 
Point.prototype.remove = function() { 
  app.map.removeOverlay(this.marker); 
  app.points.remove(this); 
}; 
 
Point.prototype.createMarker = function() { 
  var marker = this.marker = new GMarker(this.latlng, { draggable: true, bouncy: false, icon: (this.description ? app.textIcon : app.mapIcon) }); 
  marker.appPoint = this; 
  if (!app.drawing) { 
    marker.disableDragging(); 
  } 
  GEvent.addListener(marker, 'dragend', function() { app.onMarkerDragEnd(marker); }); 
  GEvent.addListener(marker, 'click', function() { app.onMarkerClick(marker); }); 
  app.map.addOverlay(marker); 
}; 

Point.prototype.removeMarker = function() { 
  app.map.removeOverlay(this.marker); 
  this.marker = null; 
};

function App(options) {
    if (GBrowserIsCompatible()) {
        if (!options.mode) {
            options.mode = 'edit';
        }
        
        app = this;
        this.drawing = true;
        this.map = new GMap2($("map"), {draggableCursor: 'crosshair'}); 
        this.map.addControl(new GSmallMapControl());
        this.map.addControl(new GMapTypeControl());
        
        var iconProperties = { 
          image: '/images/xplor_pin_map.png',
          shadow: '/images/xplor_pin_shadow.png', 
          iconSize: new GSize(15, 34), 
          shadowSize: new GSize(37, 34), 
          iconAnchor: new GPoint(7, 34) 
        }; 
        this.mapIcon = Object.extend(new GIcon(), iconProperties); 
        iconProperties.image = '/images/xplor_pin_text.png'; 
        this.textIcon = Object.extend(new GIcon(), iconProperties);
        
        if (options.mode == 'edit') {
            this.points = [];
            this.tripline = null;
            this.markerClickMode = 'edit';
            this.markerEditorHtml = $('marker-editor').innerHTML;
            $('marker-editor').innerHTML = '';
        } else if (options.mode == 'my') {
            this.tripMarkers = [];
            this.tripInfoHtml = $('trip-info').innerHTML;
            $('trip-info').innerHTML = '';
        }
        this.triplineClickTolerance = 10;
        
        if (options.data) {
            data = options.data;
            data = JSON.parseJSON(data);
            this.map.setCenter(new GLatLng(data.center.lat, data.center.lng), data.zoom);
            points = data.points;
            for (var i = 0; i < points.length; ++i) {
              this.addDataPoint(points[i], this.points.length, i == 0 || i == points.length-1); 
            }
            this.redisplayTrip();
            this.recalcDistances();
        } else if (options.center) {
            this.map.setCenter(options.center, options.zoom);
        }
        
        if (options.mode == 'edit') {
            GEvent.bind(this.map, 'click', this, this.onMapClickForEdit);
        } else if (options.mode == 'my') {
            GEvent.bind(this.map, 'click', this, this.onMapClickForMy);
        }
    }
}

App.prototype.startDrawing = function() {
    this.drawing = true;
    var length = this.points.length; 
    for (var i = 0; i < length; ++i) { 
      if (!this.points[i].marker) { 
        this.points[i].createMarker(); 
      } 
      this.points[i].marker.enableDragging();
    }
};

App.prototype.stopDrawing = function() {
    this.drawing = false;
    var length = this.points.length; 
    for (var i = 0; i < length; ++i) { 
      if (this.points[i].description) { 
        this.points[i].marker.disableDragging(); 
      } else if (i != 0 && i != length-1) { 
        this.points[i].removeMarker(); 
      }
    }
};

App.prototype.onMapClickForEdit = function(marker, point) {
    if (!this.drawing) {
        return;
    }
    if (!marker) {
      // check if the marker is on trip polyline
      var markerIndex = this.points.length; 
      for (var i = 1; i < this.points.length; ++i) { 
        var dist = this.latLngToLineDistanceInPixels(point, this.points[i-1].latlng, this.points[i].latlng); 
        if (dist != null && dist < this.triplineClickTolerance) {
          markerIndex = i;
          break;
        }
      }
      this.addPoint(point, markerIndex);
    }
    this.redisplayTrip();
    this.recalcDistances();
};

App.prototype.onMarkerClick = function(marker) { 
  if (this.markerClickMode == 'edit') { 
      if (this.ownerViewing) { 
        this.map.openInfoWindowHtml(marker.getPoint(), this.markerEditorHtml); 
        if (marker.appPoint.description != undefined) { 
          $('marker-editor-text').value = marker.appPoint.description;
        } 
        setTimeout(function() { $('marker-editor-text').focus(); }, 100); 
        $('marker-editor-save').onclick = function() {
          var oldDescription = marker.appPoint.description; 
          var newDescription = marker.appPoint.description = $('marker-editor-text').value; 
          app.map.closeInfoWindow();
          if (oldDescription && !newDescription || !oldDescription && newDescription) {  
            app.recreateMarker(marker); 
          }             
        }; 
      } else { 
        this.map.openInfoWindow(marker.getPoint(), document.createTextNode(marker.appPoint.description || "Description not entered for this marker"));  
      }
  } else { 
      marker.appPoint.remove();
  } 
}; 

App.prototype.recreateMarker = function(marker) { 
  var point = marker.appPoint; 
  point.removeMarker(); 
  point.createMarker();
};

App.prototype.addPoint = function(point, markerIndex) {
  return this.addDataPoint({ latlng: point, description: '' }, markerIndex, true); 
}; 

App.prototype.addDataPoint = function(dataPoint, markerIndex, forceMarker) { 
  var latlng;
  if (dataPoint.latlng) { 
    latlng = dataPoint.latlng;  
  } else { 
    latlng = new GLatLng(dataPoint.lat, dataPoint.lng); 
  } 
  var point = new Point; 
  point.latlng = latlng; 
  point.description = dataPoint.description; 
  if (forceMarker || this.drawing || point.description) { 
    point.createMarker(); 
  } 
  this.points.insert(markerIndex, point);
};

App.prototype.onMarkerDragEnd = function(marker) {
  marker.appPoint.latlng = marker.getPoint(); 
  app.recalcDistances(); 
  app.redisplayTrip();
};

App.prototype.undoStep = function() {
  if (!this.drawing) {
    return;
  }
  if (this.points.length > 0) { 
    this.points.pop().remove();
    this.map.removeOverlay(this.markers.pop());
    this.redisplayTrip();
    this.recalcDistances();
  }
};

App.prototype.clearPoints = function() {
    if (this.tripline != null) {
        this.map.removeOverlay(this.tripline);
    }
    for (var i = 0; i < this.points.length; ++i) { 
      this.points[i].remove(); 
    }
};

App.prototype.geoDistance = function(loc1, loc2) {
    // see http://geocoder.us/blog/2006/04/21/calculating-distances/
    var lat1 = loc1.latRadians();
    var lng1 = loc1.lngRadians();
    var lat2 = loc2.latRadians();
    var lng2 = loc2.lngRadians();
    var a = lng1-lng2;
    if (a < 0) {
        a = -a;
    }
    if (a > Math.PI) {
        a = 2*Math.PI;
    }
    return Math.acos(Math.sin(lat2)*Math.sin(lat1) + Math.cos(lat2)*Math.cos(lat1)*Math.cos(a)) * 3958;
};

// this can return null if point is not between lineStart and lineEnd
App.prototype.latLngToLineDistanceInPixels = function(point, lineStart, lineEnd) {
    point = this.map.fromLatLngToDivPixel(point);
    lineStart = this.map.fromLatLngToDivPixel(lineStart);
    lineEnd = this.map.fromLatLngToDivPixel(lineEnd);
    var distStart = this.pointToPointDistance(point, lineStart);
    var distEnd = this.pointToPointDistance(point, lineEnd);
    var distLine = this.pointToPointDistance(lineStart, lineEnd);
    if (distStart > distLine || distEnd > distLine || distLine < 1) {
        return null;
    }
    return Math.abs((lineEnd.x-lineStart.x)*(lineStart.y-point.y)-(lineStart.x-point.x)*(lineEnd.y-lineStart.y))/distLine;
};

App.prototype.pointToPointDistance = function(from, to) {
    return Math.sqrt((from.x-to.x)*(from.x-to.x) + (from.y-to.y)*(from.y-to.y));
};

App.prototype.recalcDistances = function() {
    var lastLeg = 0;
    var total = 0;
    for (var i = 1; i < this.points.length; ++i) { 
      lastLeg = this.geoDistance(this.points[i].latlng, this.points[i-1].latlng);
      total += lastLeg;
    }
    $('total-dist').innerHTML = sprintf("%.1f", total);
    $('last-leg-dist').innerHTML = sprintf("%.1f", lastLeg);
};

App.prototype.redisplayTrip = function() {
    if (this.tripline != null) {
        this.map.removeOverlay(this.tripline);
    }
    if (this.points.length > 0) { 
      this.tripline = new GPolyline(this.points.collect(function(point) { return point.latlng; }), '#ff0000', 5);
      this.map.addOverlay(this.tripline);
    }
};

App.prototype.geocode = function(address, callback) {
    if (this.geocoder == null) {
        this.geocoder = new GClientGeocoder;
    }
    return this.geocoder.getLatLng(address, callback);
};

App.prototype.centerOnAddress = function(address) {
    this.geocode(address, function(latlng) {
        app.map.setCenter(latlng, 12);
    });
};

App.prototype.save = function(formData) {
    this.stopDrawing();
    var data = [];
    if (this.points.length < 1) {
      alert('Please plot at least one point on the map before saving.');
      this.startDrawing();
      return 0;
    end
    }
    for (var i = 0; i < this.points.length; ++i) { 
      var p = {lat: this.points[i].latlng.lat(), lng: this.points[i].latlng.lng()}; 
      if (this.points[i].description != undefined) { 
        p.description = this.points[i].description;
      }
      data.push(p);
    }
    data = {center: {lat: this.map.getCenter().lat(), lng: this.map.getCenter().lng()}, zoom: this.map.getZoom(), points: data};
    var json = JSON.toJSONString(data);
    new Ajax.Updater('save-results', '/rides/save_map', {asynchronous: true, parameters: "trip_data="+encodeURIComponent(json)+"&tags="+formData['tags']+'&name='+formData['name']+'&id='+formData['id']+'&event_id='+formData['event_id']});
};

App.prototype.addTripMarker = function(trip) {
    if (trip.trip_data.points.length == 0) {
        return;
    }
    var marker = new GMarker(new GLatLng(trip.start_lat, trip.start_lng), this.mapIcon);
    marker.trip = trip;
    this.tripMarkers.push(marker);
    this.map.addOverlay(marker);
};

App.prototype.clearTripMarkers = function() {
    while (this.tripMarkers.length > 0) {
        this.map.removeOverlay(this.tripMarkers.pop());
    }
};

App.prototype.onMapClickForMy = function(marker, point) {
    if (!marker) {
        return;
    }
    c = document.createElement('div');
    c.innerHTML = this.tripInfoHtml;
    getChildElementById(c, 'trip-info-href').href = "/rides/show_map/"+marker.trip.id.toString(); 
    if (marker.trip.tag_list.length > 0) {
        getChildElementById(c, 'trip-info-tags').innerHTML = "Tags: "+marker.trip.tag_list; 
    } else {
        getChildElementById(c, 'trip-info-tags').innerHTML = ''; 
    } 
    getChildElementById(c, 'trip-info-distance').innerHTML = sprintf("%.1f miles", marker.trip.distance);
    app.infoWindowContent = c;
    this.map.openInfoWindow(marker.getPoint(), c);
};

App.prototype.showClosestRides = function(latlng) {
    // var pt = this.map.getCenter();
    new Ajax.Request('/rides/get_nearest_rides?lat='+latlng.lat()+'&lng='+latlng.lng(), { onComplete: function(req) {
        app.clearTripMarkers();
        eval("var trips = "+req.responseText);
        var bounds = new GLatLngBounds(latlng);
        for (var i = 0; i < trips.length; ++i) {
            bounds.extend(new GLatLng(trips[i].start_lat, trips[i].start_lng));
        }
        app.map.setZoom(app.map.getBoundsZoomLevel(bounds));
        app.map.setCenter(bounds.getCenter());
        for (var i = 0; i < trips.length; ++i) {
            app.addTripMarker(trips[i]);
        }
    } });
};

function clearText(elt) {
    elt = $(elt);
    if (!elt.cleared) {
        elt.cleared = true;
        elt.savedText = elt.value;
        elt.value = '';
    }
}

function restoreText(elt) {
    elt = $(elt);
    if (elt.cleared && elt.value == '') {
        elt.cleared = false;
        elt.value = elt.savedText;
        elt.savedText = '';
    }
}

function submitSearch() { 
    new Ajax.Updater('dummy', '/rides/find', {asynchronous:true, evalScripts:true, parameters:Form.serialize($('search-form'))}); 
} 

function search_validate(f) {
  if(f.search_term.value=="") {
    return false;
  }
  return true;
}

function gallery_validate(f) {
  if(f.project_name.value=="") {
    return false;
  }
  dumbQuotes(f);
  return true;
}


function FilterUpload(form,file) {
  extArray = new Array(".gif", ".jpg", ".jpeg", ".png");
  allowSubmit = false;
  if (!file) return;
  while (file.indexOf("\\") != -1)
    file = file.slice(file.indexOf("\\") + 1);
    ext = file.slice(file.indexOf(".")).toLowerCase();
    for (var i = 0; i < extArray.length; i++) {
      if (extArray[i] == ext) { allowSubmit = true; break; }
    }
    if (allowSubmit) {
      Element.show('spinner'); 
      form.submit();
    } else {
      alert("XPLOR only supports upload of the following file types:  " + (extArray.join("  ")) + "\n\nPlease select a new file and try again.");
    }
}

var rules = {
    '.clearonfocus': {
        onfocus: function() { clearText(this); },
        onblur: function() { restoreText(this); }
    }
};

/* was causing an error, not sure what it is for. 01/02/07 */
/* Behavior.register(rules); */

function dumbQuotes(f) {
  var replacements, regex, key, s;

  replacements = {
      "\xa0": " ",
      "\xa9": "(c)",
      "\xae": "(r)",
      "\xb7": "*",
      "\u2018": "'",
      "\u2019": "'",
      "\u201c": '"',
      "\u201d": '"',
      "\u2026": "...",
      "\u2002": " ",
      "\u2003": " ",
      "\u2009": " ",
      "\u2013": "-",
      "\u2014": "--",
      "\u2122": "(tm)"};
  regex = {};
  
  for (key in replacements) {
      regex[key] = new RegExp(key, 'g');
  }
  
  for (var i = 0; i < f.length; i++) {
    for (key in replacements) {
        if (f[i].value.match(regex[key])) {
          f[i].value = f[i].value.replace(regex[key], replacements[key]);
        }
    }
  }
  return true;
}

/* messaging-specific ajax */

function message_save_onclick(ref) {
  var checked = Form.getInputs("messages_form", "checkbox").findAll(function(item) 
  { return item.checked; }).pluck("value");
  if (checked.length > 0) {
    new Ajax.Updater({success:''},
                      '/messaging/save_messages',
                      { asynchronous:true,
                        evalScripts:true,
                        parameters:Form.serialize($('messages_form')),
                        onLoading:function(request){Element.show('spinner')}
                      })
  }
}

function message_trash_onclick(ref) {
  var checked = Form.getInputs("messages_form", "checkbox").findAll(function(item) 
  { return item.checked; }).pluck("value");
  if (checked.length > 0) {
    new Ajax.Updater({success:''},
                      '/messaging/trash_messages',
                      { asynchronous:true,
                        evalScripts:true,
                        parameters:Form.serialize($('messages_form')),
                        onLoading:function(request){Element.show('spinner')}
                      })
  }
}

function message_empty_trash_onclick() {
  if (confirm('Are you sure you want to permanently delete all messages in your trash folder?')) {
    new Ajax.Updater({success:''},
                      '/messaging/empty_trash',
                      { asynchronous:true,
                        evalScripts:true,
                        onLoading:function(request){Element.show('spinner')}
                      })
  }
}

function message_clicked() {

}

function checkAll(master){
  var checked = master.checked;
  var col = document.getElementsByTagName("INPUT");
  for (var i=0;i<col.length;i++) {
    col[i].checked= checked;
  }
}

/** begin xplorgs map javascript **/

function showCountry(content,country) {
	//alert("Show "+countrycode);
	overlib(content, ANCHOR, 'cal_box', ANCHORALIGN, 'UR', ANCHORX, -5, ANCHORY, 15, WIDTH, 220, HEIGHT, 160, CELLPAD, '10', BGCOLOR, '#cccccc', FGCOLOR, '#cccccc', STICKY, CAPTION, country, CLOSECLICK, CLOSECOLOR, 'grey', CLOSETEXT, '&nbsp;X&nbsp;'); 
}


/** end xplorgs map javascript **/