google.load("earth", "1");

(function($) {
    $.earth = {};

    $.earth.ge;                 //google earth wrapper
    $.earth.google = google;    //google loader
    $.earth.speed =  7;        // degrees per second
    $.earth.lastMillis = (new Date()).getTime();
    $.earth.spinning;
    $.earth.camera;

    /*
     * let the game begin
     */
    $.earth.startGE = function (){
        $.earth.google.earth.createInstance('map3d', initCB, failureCB);
    }

    $.earth.restartGlobe = function (){
        if($.earth.spinning == 'true'){
            stopEarth();
        }
        else{
            $.earth.ge.getOptions().setFlyToSpeed($.earth.ge.SPEED_TELEPORT);
            $.earth.ge.getView().setAbstractView($.earth.camera);
            $.earth.camera.setAltitude(10000000.02);
            $.earth.google.earth.addEventListener($.earth.ge, "frameend", rotateEarth);
            $.earth.google.earth.addEventListener($.earth.ge.getWindow(), 'mousedown',stopEarth);
        }
    }

    $.earth.toggleTime = function (){
        if($.earth.ge.getTime().getControl().getVisibility() == $.earth.ge.VISIBILITY_HIDE){
            $.earth.ge.getTime().getControl().setVisibility($.earth.ge.VISIBILITY_SHOW);
        }else{
            $.earth.ge.getTime().getControl().setVisibility($.earth.ge.VISIBILITY_HIDE);
        }
    }

    /*
     * handle instance of google earth
     */
    function initCB(instance) {
        $.earth.ge = instance;
        $.earth.ge.getTime().getControl().setVisibility($.earth.ge.VISIBILITY_HIDE);//show controls
        $.earth.ge.getLayerRoot().enableLayerById($.earth.ge.LAYER_BORDERS , true);//add borders
        $.earth.ge.getSun().setVisibility(true);//show sun
        if($('#loadGlobe').html() == 'true'){
            loadGlobe();//load the default kml
        }else{
            if($('#geoRss').text().length > 0){
                loadGeoRss($('#geoRss'));
            }
            if($('#kml').text().length > 0){
                fetchKml($('#kml'));
            }
        }
        $.earth.ge.getOptions().setFlyToSpeed($.earth.ge.SPEED_TELEPORT);//steadies rotation of globe, default setting makes it jumpy
        $.earth.camera = $.earth.ge.getView().copyAsCamera($.earth.ge.ALTITUDE_RELATIVE_TO_GROUND);
        $.earth.google.earth.addEventListener($.earth.ge, "frameend", rotateEarth);
        $.earth.google.earth.addEventListener($.earth.ge.getWindow(), 'mousedown',stopEarth);
        $.earth.ge.getNavigationControl().setVisibility($.earth.ge.VISIBILITY_SHOW);
        $.earth.ge.getWindow().setVisibility(true);

    }

    function loadGeoRss($rss){
        var link = $.earth.ge.createLink('');
        link.setHref( $('#geoConversionParam').html() + 'loadGlobe=false&geoRss=' +$rss.html() + '&random='+Math.floor(Math.random()*99999999999));
        var networkLink = $.earth.ge.createNetworkLink('');
        networkLink.set(link, true, false); // Sets the link, refreshVisibility, and flyToView.
        $.earth.ge.getFeatures().appendChild(networkLink);
    }

    function fetchKml($kml){
        $.earth.google.earth.fetchKml($.earth.ge, $kml.text(), function(kmlObject) {
            if (kmlObject){
                visiblityChange(kmlObject);
                $.earth.ge.getFeatures().appendChild(kmlObject);
            }
        });
    }

    function visiblityChange(kmlObject){
        //alert(kmlObject.getType());
        if(kmlObject.getType() == 'KmlNetworkLink'){
            //alert(kmlObject.getType() + 'is KmlNetworkLink');
            kmlObject.setVisibility(true);
        }
        if(kmlObject.getType() == 'KmlFolder'){
            //alert(kmlObject.getType() + 'is KmlFolder');
            var features = kmlObject.getFeatures().getChildNodes();
            for (var i = 0; i < features.getLength(); ++i){
                visiblityChange(features.item(i));
            }
        }
        if(kmlObject.getType() == 'KmlDocument'){
            //alert(kmlObject.getType() + 'is KmlDocument');
            var features2 = kmlObject.getFeatures().getChildNodes();
            for (var j = 0; j < features2.getLength(); ++j){
                visiblityChange(features2.item(j));
            }
        }
    }

    function loadGlobe(){
        var link = $.earth.ge.createLink('');
        link.setHref( $('#geoConversionParam').html() + 'loadGlobe=true&random='+Math.floor(Math.random()*99999999999));
        var networkLink = $.earth.ge.createNetworkLink('');
        networkLink.set(link, true, false); // Sets the link, refreshVisibility, and flyToView.
        $.earth.ge.getFeatures().appendChild(networkLink);

    }

    function rotateEarth(){
        var now = (new Date()).getTime();
        // dt is the delta-time since last tick, in seconds
        var dt = (now - $.earth.lastMillis) / 1000.0;
        $.earth.lastMillis = now;
        var lookAt = $.earth.ge.getView().copyAsLookAt($.earth.ge.ALTITUDE_RELATIVE_TO_GROUND);
        lookAt.setLongitude(lookAt.getLongitude() + $.earth.speed*dt);
        lookAt.setHeading(0);
        $.earth.ge.getView().setAbstractView(lookAt);
        var camera = $.earth.ge.getView().copyAsCamera($.earth.ge.ALTITUDE_RELATIVE_TO_GROUND);
        camera.setAltitude(10000000.02);
        $.earth.ge.getView().setAbstractView(camera);
        $.earth.spinning = 'true';
    }

    function stopEarth() {
        $.earth.ge.getSun().setVisibility(false);
        $.earth.google.earth.removeEventListener($.earth.ge, "frameend",rotateEarth);
        $.earth.google.earth.removeEventListener($.earth.ge.getWindow(), 'mousedown',stopEarth);
        $.earth.spinning = 'false';
    }
    /*
     * handle initialisation error from google
     */
    function failureCB(errorCode) {
        alert(errorCode);
    }




    function computeFitLookAt( obj, aspectRatio) {
        var DEGREES = Math.PI / 180;
        var EARTH_RADIUS = 6378137;

        var coordData = getObjectCoordData($.earth.ge, obj);

        if ('getAbstractView' in obj) {
            var la = obj.getAbstractView();
            if (la != null)
                return la;
        }

        if (coordData.coords.length) {
            // range calculation -- the hard part
            var center = null;
            var range = 0.0;
            if (coordData.coords.length == 1) {
                center = new $.earth.google.maps.LatLng(coordData.coords[0].lat,
                    coordData.coords[0].lng);
                range = 1000;
            } else {
                // compute bbox
                var bounds = new $.earth.google.maps.LatLngBounds();
                for (var i = 0; i < coordData.coords.length; i++)
                    bounds.extend(new $.earth.google.maps.LatLng(coordData.coords[i].lat,
                        coordData.coords[i].lng));

                // find center
                center = bounds.getCenter();
                var sw = bounds.getSouthWest();
                var ne = bounds.getNorthEast();

                var lngSpan = new $.earth.google.maps.LatLng(center.lat(), sw.lng()).
                distanceFrom(new $.earth.google.maps.LatLng(center.lat(), ne.lng()));
                var latSpan = new $.earth.google.maps.LatLng(sw.lat(), center.lng()).
                distanceFrom(new $.earth.google.maps.LatLng(ne.lat(), center.lng()));

                if (!aspectRatio)
                    aspectRatio = 1.0;

                var PAD_FACTOR = 1.5; // add 50% to the computed range for padding
                var beta;

                var aspectUse = Math.max(aspectRatio, Math.min(1.0, lngSpan / latSpan));

                // computed experimentally;
                var alpha = (45.0 / (aspectUse + 0.4) - 2.0) * DEGREES;

                // create LookAt using distance formula
                if (lngSpan > latSpan) {
                    // polygon is wide
                    beta = Math.min(90 * DEGREES, alpha + lngSpan / 2 / EARTH_RADIUS);
                } else {
                    // polygon is taller
                    beta = Math.min(90 * DEGREES, alpha + latSpan / 2 / EARTH_RADIUS);
                }

                range = PAD_FACTOR * EARTH_RADIUS * (Math.sin(beta) *
                    Math.sqrt(1 / Math.pow(Math.tan(alpha),2) + 1) - 1);
            }

            var la = $.earth.ge.createLookAt('');
            la.set(center.lat(), center.lng(), coordData.maxAltitude,
                coordData.altitudeMode, 0, 0, range);
            return la;
        }

        return null;
    }

    function getPlacemarkCoordData(ge, kmlObject) {
        var out = {
            'coords': [],
            'altitudeMode': -1,
            'maxAltitude': -9999
        };
        // extract the points from the given object
        if (kmlObject && 'getType' in kmlObject) {
            if (out.altitudeMode == -1 && 'getAltitudeMode' in kmlObject)
                out.altitudeMode = kmlObject.getAltitudeMode();


        }

        return out;
    }

})(jQuery);

