var g_apt_journey_prev = -1;
var g_apt_journey_prev_charidx = 0;
var g_apt_legs = new Array();
var g_legidx = -1;

function apt_reset() {
    g_apt_legs = new Array();
    g_legidx = -1;
    g_apt_journey_prev = -1;
    g_apt_journey_prev_charidx = 0;
}

function apt_leg_new(idx_src, idx_dst, legidx, charidx_src, charidx_dst) {
	var o = new Object();
	o.idx_src = idx_src;
	o.idx_dst = idx_dst;
	o.charidx_src = charidx_src;
	o.charidx_dst = charidx_dst;
	o.legidx = legidx;
	o.segments = apt_gc_segments(apt_get_lonlat(idx_src), apt_get_lonlat(idx_dst), 250);
	g_apt_legs[g_apt_legs.length] = o;
}

function apt_leg_count() {
	return g_apt_legs.length;
}

function apt_leg_get(idx) {
	return g_apt_legs[idx];
}

//Returns the angle of the vector from lonlat1 to lonlat2
//relative to the positive x-axis
function apt_gc_angle(lonlat1, lonlat2) {
      var dx = lonlat2.lon - lonlat1.lon;
      var dy = lonlat2.lat - lonlat1.lat;
      var a = apt_gc_rad2deg(Math.atan2(dy, dx));
      if (a < 0) a += 360;
      if (a >= 360) a -= 360;
      a += 90;
      if (a < 0) a += 360;
      if (a >= 360) a -= 360;
      return a;
}

function apt_journey_start(code, charidx) {
    if (g_legidx == 0) {
        // when only one airport code per line
        apt_journey_next(apt_get_code(g_apt_journey_prev), g_apt_journey_prev_charidx);
    }
    var ret = 0;
    code = code.toUpperCase();
    var idx = apt_get_idx(code);
    if (idx >= 0) {
        g_apt_journey_prev = idx;
        g_apt_journey_prev_charidx = charidx;
        g_legidx = 0;
        ret = 1;
    }
    return ret;
}

function apt_journey_next(code, charidx) {
    g_apt_last_start_on = null;
	var ret = 0;
	code = code.toUpperCase();
	var idx = apt_get_idx(code);
	if (idx >= 0) {
	    apt_leg_new(g_apt_journey_prev, idx, g_legidx, g_apt_journey_prev_charidx, charidx);
	    g_apt_journey_prev = idx;
	    g_apt_journey_prev_charidx = charidx;
		ret = 1;
		g_legidx++;
	}
	return ret;
}

function apt_journey_finish() {
    if (g_legidx == 0) {
        // when only one airport code per line
        apt_journey_next(apt_get_code(g_apt_journey_prev), g_apt_journey_prev_charidx);
    }
    g_apt_journey_prev = -1;
    g_apt_journey_prev_charidx = 0;
    g_legidx = -1;
}

function apt_gc_rad2deg(a) {
	return (a*(180.0/Math.PI));
}

function apt_gc_deg2rad(a) {
	return ((a/180.0)*Math.PI);
}

function apt_gc_dist(lonlat1, lonlat2) {
        var Rk = 6373; // mean radius of the earth (km) at 39 degrees from the equator

        // convert coordinates to radians
        var lat1 = apt_gc_deg2rad(lonlat1.lat);
        var lon1 = apt_gc_deg2rad(lonlat1.lon);
        var lat2 = apt_gc_deg2rad(lonlat2.lat);
        var lon2 = apt_gc_deg2rad(lonlat2.lon);

        // find the differences between the coordinates
        var dlat = lat2 - lat1;
        var dlon = lon2 - lon1;

        // here's the heavy lifting
        var a  = Math.pow(Math.sin(dlat/2),2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(dlon/2),2);
        var c  = 2 * Math.atan2(Math.sqrt(a),Math.sqrt(1-a)); // great circle distance in radians
        var dk = c * Rk; // great circle distance in km

        return dk;
}

function apt_lonlat_new(lon, lat) {
	var o = new Object();
	o.lon = lon;
	o.lat = lat;
	return o;
}

function apt_gc_segments(lonlat1, lonlat2, step) {

	var idx = 0;
	var res = new Array();
	
	res[0] = lonlat1;

	var dist = apt_gc_dist(lonlat1, lonlat2);
	if (dist < step * 1.5) {
		res[1] = lonlat2;
		return res;
	}

	var lat1 = apt_gc_deg2rad(lonlat1.lat);
	var lat2 = apt_gc_deg2rad(lonlat2.lat);
	var lon1 = apt_gc_deg2rad(lonlat1.lon);
	var lon2 = apt_gc_deg2rad(lonlat2.lon);

	// Translate the polar coordinates to the corresponding cartesian coordinates 
	var x1 = Math.cos(lon1)*Math.cos(lat1);
	var y1 = Math.sin(lon1)*Math.cos(lat1);
	var z1 = Math.sin(lat1);
	var x2 = Math.cos(lon2)*Math.cos(lat2);
	var y2 = Math.sin(lon2)*Math.cos(lat2);
	var z2 = Math.sin(lat2);

	// Calculate the angular distance ? (psi) between the two cities, as seen from the center of the Earth
	var psi = Math.acos(x1*x2 + y1*y2 + z1*z2);

	// Calculate the coordinates of the point on the great circle that is 90° from the first city in the direction of the second city
	var x3 = (x2 - x1*Math.cos(psi))/Math.sin(psi);
	var y3 = (y2 - y1*Math.cos(psi))/Math.sin(psi);
	var z3 = (z2 - z1*Math.cos(psi))/Math.sin(psi);

	for (var dist = step; dist < 40000; dist+= step) {

		//The cartesian coordinates of the points of the great circle are then, as a function of the angular distance f (phi) from the first city: 

		var phi = apt_gc_deg2rad(dist/111.317);

		// If f = 0, then you are in the first city. If f = ?, then you are in the second city. 
		if (phi > psi) {
			phi = psi;
		}

		var x = x1*Math.cos(phi) + x3*Math.sin(phi);
		var y = y1*Math.cos(phi) + y3*Math.sin(phi);
		var z = z1*Math.cos(phi) + z3*Math.sin(phi);

		// Translate the cartesian coordinates x, y, z to polar coordinates l, b: 

		// The arctan(y,x) with two arguments means that you must make sure that the answer is in 
		// the right quadrant. The correct answer is either arctan(y/x), or arctan(y/x) + 180°, and 
		// (in this case) you must select the solution that has x for its cosine and y for its sine 
		// (with the correct signs). 

		var lat3 = apt_gc_rad2deg(Math.asin(z));
		var lon3 = apt_gc_rad2deg(Math.atan2(y, x));

		res[res.length] = apt_lonlat_new(lon3, lat3);

		if (phi >= psi)
			break;
	}

	return res;
}
