function Route() {
    this.points = [];
    this.gpxData = "";
}

function LonLat(lon, lat) {
    this.lon = lon;
    this.lat = lat;
}

function AltitudeEngine() {
    this.altitudes = {};
}

function Point(x, y) {
    this.x = x;
    this.y = y;
    this.altitude = null;

    var point = this;
    altitudeEngine.setAltitude(this, function(altitude) {
        point.altitude = altitude;
        jQuery(gpxGeneratorRoute).trigger("altitudesUpdated", [gpxGeneratorRoute]);
    });
}

(function($) {
Route.prototype.setGpxData = function(gpxData) {
    this.gpxData = gpxData;
}

Route.prototype.getGpxData = function(gpxData) {
    return this.gpxData;
}

Route.prototype.addPoint = function(point) {
    this.points.push(point);
    this.triggerPointsUpdated();
}

Route.prototype.setPoints = function(points) {
    this.points = points;
    this.triggerAllPointsUpdated();
}

Route.prototype.getPoint = function(index) {
    return this.points[index];
}

Route.prototype.numOfPoints = function() {
    return this.points.length;
}

Route.prototype.removePoint = function(index) {
    this.points.splice(index, 1);
    this.triggerPointsUpdated();
}

Route.prototype.removeLastPoint = function() {
    this.removePoint(this.points.length - 1);
}

Route.prototype.movePoint = function(index , point) {
    this.points[index] = point;
    this.triggerPointsUpdated();
}

Route.prototype.triggerPointsUpdated = function() {
    $(this).trigger("pointsUpdated", [this]);
}

Route.prototype.triggerAllPointsUpdated = function() {
    $(this).trigger("allPointsUpdated", [this]);
    this.triggerPointsUpdated();
}

Route.prototype.bindPointsUpdated = function(callback) {
    $(this).bind("pointsUpdated", callback);
}

Route.prototype.hasPoints = function() {
    return this.points.length > 0;
}

Route.prototype.calculateTotalRouteLength = function() {
    return this.calculateRouteLengthToPoint(this.numOfPoints() - 1)
}

Route.prototype.calculateRouteLengthToPoint = function(index) {
    var totalLength = 0;
    if (this.hasPoints()) {
        var previousPoint = this.getPoint(0);
        for (var pointsIndex = 1; pointsIndex <= index; pointsIndex++) {
            var currentPoint = this.getPoint(pointsIndex);

            var legLength = Math.sqrt(Math.pow(previousPoint.x - currentPoint.x, 2) + Math.pow(previousPoint.y - currentPoint.y, 2));

            totalLength += legLength;
            previousPoint = currentPoint;
        }
    }

    return totalLength;
}

Route.prototype.calculateTotalHeigthChange = function(calHeightGain) {
    var totalHeightChange = 0;
    if (this.numOfPoints() > 1) {
        var lastAltitude = this.getPoint(0).altitude;
        for (var pointsIndex = 1; pointsIndex < this.numOfPoints(); pointsIndex++) {
            var altitude = this.getPoint(pointsIndex).altitude;
            
            if (altitude != null && lastAltitude < altitude == calHeightGain) {
                totalHeightChange += (calHeightGain) ? altitude - lastAltitude : lastAltitude - altitude;
            }
            lastAltitude = altitude;
        }
    }

    return totalHeightChange;
}

AltitudeEngine.prototype.setAltitude = function(point, callback) {
    var altitudesForXAndY = this.altitudes[point.x + '-' + point.y];
    var localAltitudes = this.altitudes;

    if (altitudesForXAndY) {
        callback(altitudesForXAndY);
    }
    else {
        var data = {};
        var lonLat = getLonLatFromPoint(point);
        data['lat'] = lonLat.lat;
        data['lng'] = lonLat.lon;
        $.get("http://ws.geonames.org/srtm3JSON", data, saveAltitude, "jsonp");

//        $.ajax({
//            type: "GET",
//            url: "http://ws.geonames.org/srtm3JSON",
//            data: "lat=" + lonLat.lat + "&lng=" + lonLat.lon,
//            dataType: "jsonp",
//            success: function(data, textStatus) {
//                localAltitudes[point.x + '-' + point.y] = data.srtm3;
//                callback(data.srtm3);
//            },
//            error: function (XMLHttpRequest, textStatus, errorThrown) {
//                alert("error getting altitude " + textStatus + " | " + errorThrown);
//            }
//        });

    }

    function saveAltitude(data, textStatus) {
        localAltitudes[point.x + '-' + point.y] = data.srtm3;
        callback(data.srtm3);
    }
}
})(jQuery);

var altitudeEngine = new AltitudeEngine();

var gpxGeneratorRoute = new Route();