﻿/**
* @classDescription Interface object to encapsulate API 
* commands between javascript and inteleview
*
* @constructor
* @param input_placeholder - string ID of the placeholder element on the page.
* @param input_settings - settings for the IVJ instance
*/
function ivj(input_placeholder, input_settings)
{
    //Properties: Page Elements
    this.object = null;
    this.placeholder = null;

    //Properties: Positioning
    this.offset = null;
    this.width = 0;
    this.height = 0;
    this.scroll_y = 0;

    //Properties: Animation
    this.script = null;

    //Properties: State
    this.settings = null;
    this.full_screen = false;
    this.loaded = false;
    this.loading_error=false;
    this.environment=false;
    this.overlays = [];

    try
    {
        ivj.log("performing basic checks");

        //Validate: Make sure we have jquery.
        if($==undefined || (/1\.(0|1|2)\.(0|1|2)/).test($.fn.jquery))
            throw ivj.strings.en['error_no_jquery'];

        //Validate: Make sure we have plugin detect script
        if(PluginDetect==undefined)
            throw ivj.strings.en['error_no_plugindetect'];

        //Validate: Make sure we have placeholder element
        this.placeholder = $('#'+input_placeholder);
        if(!this.placeholder.length)
            throw ivj.strings.en['error_no_placeholder'];

        //Setup: Get all settings.
        this.settings = $.extend({
            'id':null,
            'allow_full_screen': true,
            'auth_token':null,
            'group_id':null,
            'startup_action':'none',
            'startup_location':null,
            'startup_script':null,
            'show_side_panel':true,
            'on_startup_callback':null,
            'on_fullscreen_start_callback':null,
            'on_fullscreen_end_callback':null,
            'on_exit_callback':null,
            'path':'',
            'ivj_path':'',
            'click_to_start':false,
            'lang':'en',
            'pre_included':false,
            'use_cookies':false,
            'controls':true
        },input_settings);
        ivj.log(this.settings);

        //Setup: get ID
        if(this.settings.id == null)
            throw ivj.strings.en['error_no_id'];

        //add to static instances so we can reference it later
        ivj.instances[this.settings.id] = this;

        //add startup script if defined
        if(this.settings.startup_script)
            this.script = this.settings.startup_script;

        //get position info
        this.get_position();

        //bind resizing events for all overlays
        var closure = function(self){
            return function(){
                self.position();
            }
        };
        $(window).resize(closure(this));
        $(window).load(closure(this));

        //if the applet was preincluded or the cookie is set, skip testing
        if(!this.settings.pre_included && (this.settings.use_cookies && $.cookie('ivj_testing_status')!='true'))
        {
            //No java found
            if(this.env().version == 0)
                return this.show_options(this.localize('no_java'),true,false,false);

            //mac running without safari
            else if(this.env().platform.mac && !this.env().browser.safari)
                return this.show_options(this.localize('mac_firefox'), false, false, true);

            //mac with java 5
            else if(this.env().version ==5 && this.env().platform.mac && this.env().browser.safari)
                return this.show_options(this.localize('mac_old'),false,true,true);

            //anyone else running java 5
            else if(this.env().version==5)
                return this.show_options(this.localize('old_java'),true,false,false);
        }

        //check click to start only if the applet is not pre_included
        if(this.settings.click_to_start && !this.settings.pre_included)
            return this.show_options(this.localize('click_to_load'),false,false,true);

        //add applet
        ivj.log('Did not meet any loading roadblocks. Adding applet directly.');
        this.add_applet();
    }
    catch(err)
    {
        alert(err);
    }
}

//static properties
ivj.instances = {};
ivj.debug = true;
ivj.strings = {
    'en':{
        'tip':"InteleView is a powerful online GIS tool for displaying vast quantities of data, in real time, from around the world, and displaying it in a way that is intuitive and easy to use.",
        'old_java': "The version of Java installed on your machine is not the latest and could cause InteleView to run slowly.",
        'no_java': "Java was not detected on your machine, or your version of java is too old to run InteleView. It may be disabled, or it may not be installed.",
        'mac_old': "The version of Java installed on your machine is the latest for your platform, however, it limits the capabilities of InteleView and may cause it to run slowly",
        'click_to_load': "InteleView will run successfully on your system!",
        'mac_firefox': "InteleView will run successfully on your system, however, additional features may be available using Safari.",
        'popup_title':'InteleView',
        'error_detecting_java':'There was a problem detecting the java capabilities of your browser.',
        'error_adding_inteleview':'There was a problem adding InteleView to the page.',
        'error_no_placeholder':'Placeholder element was not found.',
        'error_no_plugindetect':'Plugin Detection library was not found.',
        'error_no_jquery':'jQuery library was not found.',
        'error_no_id':'No element ID was provided.',
        'error':'Error',
        'details':'Details',
        'options':'InteleView Options',
        'option_continue':'Continue with the current version of Java',
        'option_download':'Download the latest version  of Java here.',
        'option_webstart':'Use InteleView WebStart',
        'new_window':'Opens in a new window.',
        'loading':'InteleView is Loading',
        'problem_detected':'Problem Detected',
        'jar_blocked':'It looks like Java may be blocked by your firewall, or there is a network problem.',
        'slow_connection':'InteleView appears to be taking a long time to load. This may not indicate a problem if you have a slower internet connection.',
        'try_again':'Try to load InteleView again.',
        'more_time':'Give it a bit more time.',
        'test_system':'Do a test of my system.'
    },
    'es':{
        'tip': 'El visualizador GEO-MEXICO, de la Presidencia de la República está cargando en su equipo de cómputo, esto puede durar algunos minutos. ',
        'old_java': 'La versión de Java instalada en su máquina no es el más reciente y podría causar InteleView a funcionar lentamente.',
        'no_java': 'Java no se ha detectado en su máquina, o su versión de Java es demasiado viejo para correr InteleView. Puede ser desactivado, o no puede ser instalado.',
        'mac_old': 'La versión de Java instalada en su máquina es la más reciente para su plataforma, sin embargo, limita la capacidad de InteleView y puede provocar que se ejecute lentamente',
        'click_to_load': 'InteleView se ejecutará correctamente en su sistema!',
        'mac_firefox': 'InteleView se ejecutará correctamente en su sistema, sin embargo, las características adicionales pueden ser accesibles por medio de Safari.',
        'popup_title': 'InteleView',
        'error_detecting_java': 'Ha habido un problema la detección de las capacidades de Java de su navegador.',
        'error_adding_inteleview': 'Hubo un problema al añadir InteleView a la página.',
        'error': 'Error',
        'details': 'Detalles',
        'options': 'Opciones de InteleView',
        'option_continue': 'Continuar con la versión actual de Java',
        'option_download': 'Descarga la última versión de Java aquí.',
        'option_webstart': 'Usar InteleView WebStart',
        'new_window': 'Se abre en una ventana nueva.',
        'loading': 'InteleView está cargando'
    }
};

/**
 * Log debugigng info to firebug or safari console or the page
 *
 *@static
 *@method
 *@returns void
 */
ivj.log = function(message)
{
    if(ivj.debug)
    {
        if(typeof(window["console"]) != "undefined") console.log(message);
    }
}

/**
 * Get the current position of the placeholder
 */
ivj.prototype.get_position = function()
{
    this.offset = this.placeholder.offset();
    this.width = this.placeholder.width();
    this.height = this.placeholder.height();
}

/**
 * Localize a string.
 *
 * @method
 * @param <string>
 * @return <string>
 */
ivj.prototype.localize = function(s)
{
    //ignore set language if there is no localization
    if(typeof(ivj.strings[this.settings.lang])==undefined) this.settings.lang = 'en';
    if(typeof(ivj.strings[this.settings.lang][s])==undefined)
    {
        if(this.settings.lang == 'en' || typeof(ivj.strings['en'][s])==undefined) return '';
        return ivj.strings['en'][s];
    }
    return ivj.strings[this.settings.lang][s];
}

/**
* Add the java applet to the page.
* 
* Applet is positioned off the left hand side, and moved intop position when
* loaded.
*
* @method
* @return void
*/
ivj.prototype.add_applet = function()
{
    try
    {
        this.show_loading();

        //set a cookie
        if(this.settings.use_cookies)
        {
            ivj.log("Saving Cookie to skip testing next time");
            $.cookie("ivj_testing_status", 'true', { path: '/', expires: 10 });
        }

        //reset error flag
        this.loading_error = false;

        //if we already included it, just get the reference.
        if(this.settings.pre_included)
        {
            ivj.log("Connecting to pre-included applet");
            this.object = $('#'+this.settings.id);
        }
        
        //or else create the applet
        else
        {
            ivj.log("Adding applet tag to the page.");
            var sidePanel = this.settings.show_side_panel ? 'true' : 'false';
            this.object = $(
                '<applet class="ivj_viewers" id="'+this.settings.id+'" name="wwjApplet" ' +
                '   mayscript="true" code="org.jdesktop.applet.util.JNLPAppletLauncher" ' +
                '   style="width:100%;height:500px" ' +
                '   archive="'+this.settings.path+'resources/applet-launcher.jar, ' +
                '      http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jar, ' +
                '      http://download.java.net/media/gluegen/webstart/gluegen-rt.jar, ' +
                '      '+this.settings.path+'resources/inteleview.jar"> ' +
                '   <param name="jnlp_href" value="'+this.settings.path+'resources/inteleview-default.jnlp"> ' +
                '   <param name="authtoken" value="'+this.settings.auth_token+'"> ' +
                '   <param name="codebase_lookup" value="false"> ' +
                '   <param name="subapplet.classname" value="com.intelesense.inteleview.applet.InteleviewApplet"> ' +
                '   <param name="subapplet.displayname" value="InteleView 2.0 Web"> ' +
                '   <param name="noddraw.check" value="true"> ' +
                '   <param name="progressbar" value="true"> ' +
                '   <param name="cache_option" value="no" /> ' +
                '   <param name="separate_jvm" value="true" /> ' +
                '   <param name="showSidePanel" value="'+sidePanel+'" /> ' +
                '   <param name="jnlpNumExtensions" value="1"> ' +
                '   <param name="appletId" value="'+this.settings.id+'"> ' +
                '   <param name="user_group" value="'+this.settings.group_id+'"> ' +
                '   <param name="navigateFunctionName" value="follow_link"> ' +
                '   <param name="jnlpExtension1" value="http://download.java.net/media/jogl/builds/archive/jsr-231-webstart-current/jogl.jnlp"> ' +
                '   <param name="java_arguments" value="-Xmx512m -Dsun.java2d.noddraw=true -Dsun.awt.noerasebackground=true"> ' +
                '</applet>'
                );
            var container = $(
                '<div ' +
                '   style="position:absolute;' +
                '      top:0px;' +
                '      left:-5000px;' +
                '      width:300px;' +
                '      height:300px;z-index:1000" ' +
                '   class="'+this.settings.id+'_overlay ivj_container" ' +
                '   id="'+this.settings.id+'_container"></div>').append(this.object);
            if(this.settings.controls)
            {
                ivj.log("Adding IVJ controls");
                var play = function(self){return function(){
                        if(self.script == null) self.script = ivj_script.default_scripts.orbit;
                        self.run_script();return false;
                    }
                };
                var pause = function(self){return function(){self.pause();return false;}};
                var fullscreen = function(self){return function(){self.appletFullscreen();return false}};
                var reset = function(self){return function(){self.go_to('goto;0;0;30000000');return false;}};
                container.prepend($('<div id="'+this.settings.id+'_controls" class="ivj_controls"></div>')
                    .append(
                        $('<a href=""><img class="icon" src="'+this.settings.path+'resources/play.gif"></a>')
                            .click(play(this))
                    ).append(
                        $('<a href=""><img class="icon" src="'+this.settings.path+'resources/pause.gif"></a>')
                            .click(pause(this))
                    ).append(
                        $('<a href=""><img class="icon rightside" src="'+this.settings.path+'resources/fullscreen.gif"></a>')
                            .click(fullscreen(this))
                    ).append(
                        $('<a href=""><img class="icon rightside" src="'+this.settings.path+'resources/globe.gif"></a>')
                            .click(reset(this))
                    )
                );
                play=null;pause=null;fullscreen=null,reset=null;
            }
            $('body').append(container);
        }

        //set up a timer to check that we have loaded after 60 seconds.
        var closure = function(self){
            return function(){
                if(!self.loaded&&!self.loading_error)
                {
                    self.loading_error = true;
                    self.abort_load(self.localize('slow_connection'),false,true,true);
                }
            }
        };
        setTimeout(closure(this),60000);

        //this is where we test for JAR availability - we can do this in parallel.
        closure = function(self){
            return function(XMLHttpRequest, status){
                if(status!='success')
                {
                    $('applet').remove();
                    self.loading_error = true;
                    self.abort_load(self.localize('jar_blocked'),true,false,true);
                }
            }
        };
        $.ajax({
            "url":this.settings.path+'resources/getJavaInfo.jar',
            "dataType":"text",
            "complete": closure(this)
        });

        //poll for events if we are on mac but not using safari
        if(this.env().platform.mac && !this.env().browser.safari)
        {
            ivj.log("Polling for old mac java since we get no init events.");
            this.poll();
        }
    }
    catch(err)
    {
        this.show_error(this.localize('error_adding_inteleview'),err);
    }
}

/**
 * Run the java and browser detection.
 *
 * @method
 * @param <boolean>
 * @return <int>
 */
ivj.prototype.env = function(mode,retest)
{
    //set defaults
    if(mode==undefined) mode = 2;
    if(retest==undefined) retest = false;

    //only test the first time
    if(this.environment == false || retest == true)
    {
        ivj.log("Testing Java.");

        //do java detection
        info = PluginDetect.getInfo(
            'Java',
            this.settings.path + 'resources/getJavaInfo.jar',
            [0,mode,0]
        );

        //defaults
        this.environment = {
            'version':0,
            'platform':{'win':false,'mac':false,'linux':false},
            'browser':$.browser
        };

        //version
        if(PluginDetect.isMinVersion('Java', '1,6,0,12'))
            this.environment.version = 6;
        else if(PluginDetect.isMinVersion('Java', '1,5,0,2'))
            this.environment.version=5;

        //platform
        if(/Win/.test(navigator.platform)) this.environment.platform.win = true;
        else if(/Mac/.test(navigator.platform)) this.environment.platform.mac = true;
        else if(/Linux/.test(navigator.platform)) this.environment.platform.linux = true;

        ivj.log(this.environment);
        
        //track with google analytics if it is enabled
        if (typeof pageTracker !== "undefined")
        {
            ivj.log('tracking events');
            pageTracker._trackEvent(
                "inteleview",
                "java version family",
                this.environment.version);
        }
    }
    return this.environment;
}

/**
* Poll applet for availability
*
* In browsers which have problems triggering the appletInit and appletStart
* functions we need to poll the applet to determine when it ha sloaded
*
* @method
* @return void
*/
ivj.prototype.poll = function()
{
    ivj.log("Polling for applet");
    try
    {
        if(this.instance().getOrbitView().getZoom())
        {
            ivj.log("poll successful");
            this.appletInit();
            var closure = function(self){
                return function(){
                    self.appletStart();
                }
            };
            setTimeout(closure(this),2000);
        }
        else
        {
            throw "not ready yet";
        }
    }
    catch(err)
    {
        //setup next call
        ivj.log("poll failed: "+err);
        closure = function(self){
            return function(){
                self.poll();
            }
        };
        setTimeout(closure(this),2000);
    }
}

/**
 *Add an overlay with additional information to the page
 *
 *
 *@method
 *@param (string) contents
 *@return void
 */
ivj.prototype.add_overlay = function(contents)
{
    $('body').append(
        $("<div></div>")
        .addClass('ivj_message_overlay')
        .addClass(this.settings.id+'_overlay')
        .width(this.width)
        .height(this.height)
        .css({
            'top':this.offset.top + 'px',
            'left':this.offset.left + 'px'
        })
        .append(contents)
    );
    this.position();
}

/**
 *Remove all overlays associated with this applet
 *
 *@method
 *@return void
 */
ivj.prototype.remove_overlays = function()
{
    $('.'+this.settings.id+'_overlay').not('#'+this.settings.id+'_container').remove();
}

/**
 *Show an error message in the overlay
 *
 *No error handling because this is in the error display path
 *
 * @method
 * @return void
 */
ivj.prototype.show_error = function(message,details)
{
    ivj.log(message+': '+details);
    var output = $("<div></div>").addClass('ivj_error').append(
        $("<h3>"+this.localize("error")+"</h3>")
        ).append(
        $("<p>"+message+"</p>")
        ).append(
        $("<a>"+this.localize("details")+"</a>").click(function(){
            $(this).after("<p>"+this.localize("details")+"</p>");
        })
    );
    this.add_overlay(output);
}

/**
 *Show an error message in the overlay
 *
 *No error handling because this is in the error display path
 *
 * @method
 * @param (string) message the message to display
 * @param (boolean) download show the download link
 * @param (boolean) webstart show the webstart link
 * @param (boolean) webstart show the webstart link
 * @return void
 */
ivj.prototype.abort_load = function(message,retry,wait,systemtest)
{
    var output = $("<div></div>").addClass('ivj_options').append(
        $("<div class='ivj_header'>" +
            "<img class='ivj_logo' src='"+this.settings.path+"resources/inteleview-icon.png'/>" +
            "<h3>"+this.localize('problem_detected')+"</h3>" + 
        "</div>")).append($("<p class='ivj_main_p'>"+message+"</p>")
    );
    if(retry===true)
    {
        load_id = this.settings.id;
        output.append($("<p></p>").append($("<a href='#'>"+this.localize('try_again')+"</a>").click(function(){
            ivj.instances[load_id].add_applet();
            return false;
        })));
    }
    if(wait===true)
    {
        load_id = this.settings.id;
        output.append($("<p></p>").append($("<a href='#'>"+this.localize('more_time')+"</a>").click(function(){
            ivj.instances[load_id].show_loading();
            return false;
        })));
    }
    if(systemtest===true)
    {
        load_id = this.settings.id;
        output.append($("<p></p>").append($("<a href='#'>"+this.localize('test_system')+"</a>").click(function(){
            ivj.instances[load_id].show_loading();
            return false;
        })));
    }
    this.add_overlay(output);
}

/**
 *Show an error message in the overlay
 *
 *No error handling because this is in the error display path
 *
 * @method
 * @param <string> message the message to display
 * @param <boolean> download show the download link
 * @param <boolean> webstart show the webstart link
 * @param <boolean> load show the continue loading link
 * @return void
 */
ivj.prototype.show_options = function(message,download,webstart,load)
{
    var output = $("<div></div>").addClass('ivj_options').append(
        $("<div class='ivj_header'>" +
            "<img class='ivj_logo' src='"+this.settings.path+"resources/inteleview-icon.png'/>" +
            "<h3>"+this.localize('options')+"</h3>" +
            "<img class='ivj_loading' src='"+this.settings.path+"bar.gif'/>" +
        "</div>")).append($("<p class='ivj_main_p'>"+message+"</p>"));
    if(load===true)
    {
        load_id = this.settings.id;
        output.append($("<a href='#'>"+this.localize('option_continue')+"</a>").click(function(){
            ivj.instances[load_id].add_applet();
            return false;
        }));
    }
    if(download===true)
    {
        output.append("<p><a href='http://www.java.com/en/download/index.jsp'>"+
            this.localize('option_download')+"</a></p>");
    }
    if(webstart===true)
    {
        output.append("<p><a href='"+this.settings.path+"resources/inteleview-webstart.jnlp'>"+
            this.localize('option_webstart')+"</a> ("+this.localize('new_window')+")</p>");
    }
    this.add_overlay(output);
}

/**
 *Show a loading message
 *
 * @method
 * @return void
 */
ivj.prototype.show_loading = function()
{
    var output = $("<div></div>").addClass('ivj_options').append(
        $("<div class='ivj_header'>"+
            "<img class='ivj_logo' src='"+this.settings.path+"resources/inteleview-icon.png'/>"+
            "<h3>"+this.localize('loading')+"</h3>"+
            "<img class='ivj_loading' src='"+this.settings.path+"resources/loading.gif'/>"+
        "</div>")
    ).append(
        $("<p class='ivj_main_p ivj_loading_message'>"+this.localize('tip')+"</p>")
    );
    this.add_overlay(output);
}

/**
* Applet is initialized
*
* @method
* @return void
*/
ivj.prototype.appletInit = function()
{
    ivj.log('Method: appletInit is executing.');
    //turn on full screen interface elements if requested
    if (this.settings.allow_full_screen)
    {
        this.toggle_full_screen();
    }
};

/**
* Globe has rendered
*
* @method
* @return void
*/
ivj.prototype.appletStart = function()
{
    ivj.log('Method: appletStart');

    //move applet into position
    this.remove_overlays();
    this.loaded = true;
    this.position();

    //start scripting
    if(this.settings.startup_action == 'script')
    {
        this.run_script();
    }
    else if(this.settings.startup_action == 'goto')
    {
        if(this.settings.startup_location)
            this.go_to(this.settings.startup_location);
    }
    else if(this.settings.startup_action == 'orbit')
    {
        this.script = ivj_script.default_scripts.orbit;
        this.run_script();
    }
};

/**
* Applet is exiting
*
* @method
* @return void
*/
ivj.prototype.appletStop = function()
{
    ivj.log('Method: appletStop');
};

/**
* Applet is signaling full screen
*
* @method
* @param {Bool} state: the desired full screen state
* @return void
*/
ivj.prototype.appletFullscreen = function(state)
{
    ivj.log('Method: appletFullscreen');

    //continue only if full screen mode is allowed
    if (this.settings.allow_full_screen && state !== this.full_screen)
    {
        if (state==false || (typeof state == 'undefined' && this.full_screen))
        {
            this.full_screen = false;
            this.position();
        }
        else
        {
            $("body", "html").css({
                height: "100%",
                width: "100%"
            });
            this.full_screen = true;
            this.position();
        }
    }
};


/**
* Direct the applet to a new location
*
* @method
* @param {string} string_coordinates
* @return void
*/
ivj.prototype.go_to = function(string_coordinates)
{
    ivj.log('Method: go_to');

    //send correct method signature depending on params going out
    var params = string_coordinates.split(';');
    if(params.length == 3)
        this.instance().gotoLatLon(
            parseFloat(params[1]),
            parseFloat(params[2])
            );
    else if(params.length == 4)
        this.instance().gotoLatLon(
            parseFloat(params[1]),
            parseFloat(params[2]),
            parseFloat(params[3]),0,0
            );
    else if(params.length == 5)
        this.instance().gotoLatLon(
            parseFloat(params[1]),
            parseFloat(params[2]),
            parseFloat(params[3]),
            parseFloat(params[4]),0
            );
    else if(params.length == 6)
        this.instance().gotoLatLon(
            parseFloat(params[1]),
            parseFloat(params[2]),
            parseFloat(params[3]),
            parseFloat(params[4]),
            parseFloat(params[5])
            );
};

/**
* Toggle the applet full screen awareness state
*
* @method
* @return void
*/
ivj.prototype.toggle_full_screen = function()
{
    ivj.log('Method: toggle_full_screen');
    this.instance().toggleFullscreenMode();
}

/**
* Creates or updates a screen overlay
*
* @method
* @return void
*/
ivj.prototype.screen_overlay = function(id,name,description,url,x,y,opacity,corner_radius)
{
    ivj.log('Method: screen_overlay');

    //check required params
    if(!name || !url) return false;

    //prepare optional params
    corner_radius = corner_radius || 0;
    opacity = opacity || 1;
    x = x || 0;
    y = y || 0;
    description = description || '';
    id = id || ivj.generate_id();
    ivj.log(id+', name:'+name+', desc:'+description+', url:'+url+', x:'+x+', y:'+y+', a:'+opacity+', corner:'+corner_radius);

    //switch action based on ID
    if(this.overlays.toString().indexOf(id) === -1)
    {
        this.instance().addScreenOverlay(
            id, name, description, url, x, y, opacity, true, corner_radius);
        this.overlays.push(id);
    }
    else
    {
        this.instance().refreshScreenOverlay(
            id, name, description, url, x, y, opacity, true, corner_radius);
    }

    //return ID
    return id;
}

/**
* Set the opacity of the layer with the provided ID
*
* @method
* @return boolean
*/
ivj.prototype.set_layer_opacity = function(id,opacity)
{
    ivj.log('Method: set_layer_opacity');

    //validate inputs
    if(!id || !opacity) return false;

    //direct traffic
    if(this.overlays.toString().indexOf(id) > -1)
    {
        return this.instance().setLayerOpacityById(id, opacity)
    }
    else
    {
        return this.instance().setLayerOpacityByDatabaseId(id, opacity)
    }
};

/**
* Set the visibility of the layer with the provided ID
*
* @method
* @return string
*/
ivj.prototype.set_layer_visibility = function(id,state)
{
    ivj.log('Method: set_layer_visibility');

    //validate inputs
    if(!id || !state) return false;

    //direct traffic
    if(this.overlays.toString().indexOf(id) > -1)
    {
        return this.instance().setLayerEnabledById(id, state)
    }
    else
    {
        return this.instance().setLayerEnabledByDatabaseId(id, state)
    }
};

/**
* Get the current coordinates
*
* @method
* @return string
*/
ivj.prototype.get_coordinates = function()
{
    ivj.log('Method: get_coordinates');

    //get coordinates
    var lat = Math.round(this.instance().getOrbitView().getCenterPosition().getLatitude().degrees*1000000)/1000000;
    var lon = Math.round(this.instance().getOrbitView().getCenterPosition().getLongitude().degrees*1000000)/1000000;
    var zoom = Math.round(this.instance().getOrbitView().getZoom());
    var head = Math.round(this.instance().getOrbitView().getHeading().degrees*100)/100;
    var pitch = Math.round(this.instance().getOrbitView().getPitch().degrees*100)/100;
    return 'Coordinates' + ';' + lat + ';' + lon + ';' + zoom + ';' + head + ';' + pitch;
};

/**
* Load a KML file
*
* @method
* @return void
*/
ivj.prototype.load_kml = function(name,uri)
{
    ivj.log('Method: load_kml');
    this.instance().addKmlLayer(name,uri);
};

/**
 *Run a script made up of multiple goto locations
 *
 *@method
 *@return void
 */
ivj.prototype.run_script = function()
{
    if(this.script)
    {
        this.script.play(this.settings.id,true);
    }
}

/**
 *Load a script into an array for running
 *
 *@method
 *@return void
 */
ivj.prototype.load_script = function(object_script)
{
    this.script = object_script;
}

/**
 *Pause a script
 *
 *@method
 *@return void
 */
ivj.prototype.pause = function()
{
    if(this.script)
    {
        this.script.pause(this.settings.id);
    }
}

/**
 *Load a script into an array for running
 *
 *@method
 *@return void
 */
ivj.prototype.load_script_from_string = function(string_script)
{
    this.script = new ivj_script(this.settings.id,string_script);
}


/**
* Set the applet position based on fullscreen mode and placeholder position
*
* @method
* @return void
*/
ivj.prototype.position = function()
{
    ivj.log("Method: position");
    var offset = this.settings.controls ? 20 : 0;
    var elements = $('.'+this.settings.id+'_overlay');
    if(!this.loaded) elements = elements.not('#'+this.settings.id+'_container');

    if (this.full_screen)
    {
        this.scroll_y = $(window).scrollTop();
        elements.height($(window).height()).width($(window).width()).css({
            top: (this.scroll_y+1)+'px',
            left: 0
        }).find('applet').height($(window).height()-offset);
        window.scroll(0,this.scroll_y+1);
    }
    else
    {
        this.get_position();
        elements.width(this.width).height(this.height).css({
            top:this.offset.top + 'px',
            left:this.offset.left + 'px'
        }).find('applet').height(this.height-offset);
    }
}

/**
 * Get the current instance of the IVJ object, eithe rold style or new style.
 *
 * @method
 * @return {object}
 */
ivj.prototype.instance = function()
{
    var theApplet = this.object[0];
    try
    {
        theApplet = theApplet.getSubApplet();
    }
    catch (e)
    {
        ivj.log("Failed to get sub applet, using object reference. " + theApplet.id);
    }
    return theApplet;
}

/**
 * Callback Router Function
 * Called by IVJ when an instance is initialized.
 */
function appletInit(id) 
{
    ivj.log(id + ' appletInit');
    if(ivj.instances[id]) ivj.instances[id].appletInit();
}

/**
 * Callback Router Function
 * Called by IVJ when an applet is started.
 */
function appletStart(id) 
{
    ivj.log(id + ' appletStart');
    if(ivj.instances[id]) ivj.instances[id].appletStart();
}

/**
 * Callback Router Function
 * Called by IVJ when an applet is closed
 */
function appletStop(id) 
{
    ivj.log(id + ' appletStop');
    if(ivj.instances[id]) ivj.instances[id].appletStop();
}

/**
 * Callback Router Function
 * Called by IVJ when an applet's "full screen" button is clicked.
 */
function appletFullscreen(id, state)
{
    ivj.log(id + ' appletFullscreen');
    if(ivj.instances[id]) ivj.instances[id].appletFullscreen(state);
}

/**
 * Callback link handler
 */
function follow_link(url)
{
    if(url.indexOf("?") !== -1)
    {
        url_options = $.extend({
            'popup':'false',
            'width':'500',
            'height':'300'
        },urlQueryToObject(url));
        var nav = url.split("?")
        if(url_options.popup == 'true')
        {
            window.open(
                nav[0],
                "ivj_popup",
                "status=no,toolbar=no,location=no,menubar=no," +
                "directories=no,resizable=yes,scrollbars=no,personalbar=no,height=" +
                url_options.height+",width="+url_options.width);
        }
        else window.location.href = url;
    }
    else window.location.href = url;
}

/**
 * Get query string from URL
 */
function urlQueryToObject(s){
    var query = {};
    var pairs = s.split("?");
    pairs = pairs[1].split("&");
    for ( i in pairs )
    {
        var keyval = pairs[ i ].split( "=" );
        query[ keyval[0] ] = keyval[1];
    }
    return query;
}

//------------------------------------------------------------------------------Scripts

/**
* @classDescription Script object for animating IVJ
* @param input_script string script
* @param input_settings object settings
*/
function ivj_script(input_script,input_settings)
{
    try
    {
        this.settings = {
            'default_delay':5000,
            'repeat':1
        }
        this.locations = [];
        this.pointer = 0;
        this.repeats = 0;
        this.paused = false;

        //setup
        if(input_script) this.locations = input_script.split('|');
        if(input_settings) this.settings = $.extend(this.settings,input_settings);
    }
    catch(err)
    {
        alert(err);
    }
}

/**
 *@method
 *Adds a location to the script queue
 *
 *@param location string location (semicolon delimited)
 *@returns void
 */
ivj_script.prototype.add_location = function(location)
{
    this.locations.push(location);
};

/**
 *@method
 *Removes all items from the script queue
 *
 *@returns void;
 */
ivj_script.prototype.clear = function()
{
    this.locations = [];
};

/**
 *@method
 *Resets the script counters (start the script over)
 *
 *@returns void
 */
ivj_script.prototype.reset = function()
{
    this.pointer = 0;
    this.repeats = 0;
}

/**
 *@method
 *Plays the current script
 *
 *@param instance_id string id of the inteleview instance to play on
 *@param resume boolean indicator to override "paused" state
 *@returns void
 */
ivj_script.prototype.play = function(instance_id,resume)
{
    ivj.log("Play Script");
    if(resume) this.paused = false;
    try
    {
        if(!instance_id) throw("Script must play on an instance!");
        var next = this.get_next(instance_id);
        if(next!==false)
        {
            //perform actions
            if(typeof next.location != 'undefined') 
            {
                ivj.instances[instance_id].go_to(next.location);
            }
            if(typeof next.overlay != 'undefined')
            {
                //[id];[name];[url];[screen-x];[screen-y];[opacity]
                //screen_overlay = function(id,name,description,url,x,y,opacity,corner_radius)
                var p = next.overlay.split(';');
                if(typeof p[0]!='undefined'&&typeof p[1]!='undefined'&&typeof p[2]!='undefined')
                {
                    if(typeof p[5]!='undefined')
                        ivj.instances[instance_id].screen_overlay(p[0],p[1],'',p[2],p[3],p[4],p[5]);
                    else if(typeof p[4]!='undefined')
                        ivj.instances[instance_id].screen_overlay(p[0],p[1],'',p[2],p[3],p[4]);
                    else if(typeof p[3]!='undefined')
                        ivj.instances[instance_id].screen_overlay(p[0],p[1],'',p[2],p[3]);
                    else
                        ivj.instances[instance_id].screen_overlay(p[0],p[1],'',p[2]);
                }
            }
            if(typeof next.enableLayer != 'undefined')
            {
                ivj.instances[instance_id].set_layer_visibility(next.enableLayer,true);
            }
            if(typeof next.disableLayer != 'undefined')
            {
                ivj.instances[instance_id].set_layer_visibility(next.disableLayer,false);
            }
            if(typeof next.fullscreen != 'undefined')
            {
                ivj.log('fullscreen!');
                ivj.instances[instance_id].appletFullscreen(next.fullscreen);
            }


            //setup next call
            thisObj = this;
            setTimeout(function() {
                thisObj.play.call(thisObj,instance_id);
            }, parseInt(next.delay));
        }
    }
    catch(err)
    {
        alert(err);
    }
};

/**
 *@method
 *Get the next location from the script
 *
 *@caller play()
 *@param instance_id string id of the inteleview instance the script is being played on
 *@returns object
 */
ivj_script.prototype.get_next = function(instance_id)
{
    if(!this.paused)
    {
        if(this.locations.length > 0)
        {
            //if we have run out our welcome, leave.
            if(this.pointer>this.settings.repeat*this.locations.length) return false;

            //otherwise, set our location
            var loc = this.locations[this.pointer%this.locations.length];
            var retval = {};
            var start = 0;

            //special case for old style scripts
            if(loc.indexOf('Coordinates;')===0)
            {
                retval['location'] = this.locations[this.pointer];
                retval['delay'] = this.settings.default_delay;
                this.pointer++;
            }
            else
            {
                //we loop now because we may have multiple instructions / lines
                for (var i=0;i<=10;i++)
                {
                    loc = this.locations[this.pointer%this.locations.length].split('::');
                    ivj.log(this.pointer+' - '+loc);
                    if(loc.length==3)
                    {
                        //numbers, people
                        loc[0] = parseFloat(loc[0]);
                        
                        //handle timing
                        if(i == 0)
                        {
                            start = loc[0];
                        }
                        else if (loc[0] != start)
                        {
                            if(loc[0] > start)
                            {
                                retval['delay'] = (loc[0]-start)*1000;
                            }
                            else if(loc[0] < start)
                            {
                                retval['delay'] = loc[0]*1000;
                            }
                            break;
                        }

                        //add the item to the return value
                        retval[loc[1]] = loc[2];
                    }
                    //increment the pointer
                    this.pointer++;
                }
            }
            return retval;
        }
        else return false;
    }
    else return false;
}

/**
 *@method
 *Pause the script immediately.
 *
 *@returns void
 */
ivj_script.prototype.pause = function(instance_id)
{
    ivj.instances[instance_id].go_to(ivj.instances[instance_id].get_coordinates());
    this.paused = true;
};

/**
 *@static propetry
 *Default scripts
 */
ivj_script.default_scripts = {
    'orbit':new ivj_script(),
    'timeline':new ivj_script()
};

/**
 *@Method Override
 *Change the get_next method to calculate the next position instead of fetching
 *it from the queue
 *
 *@param instance_id
 *@returns object
 */
ivj_script.default_scripts.orbit.get_next = function(instance_id)
{
    if(!this.paused)
    {
        var params = ivj.instances[instance_id].get_coordinates().split(';');
        params[1]=parseFloat(params[1]);
        params[2]=parseFloat(params[2]);
        params[2] += 36;
        params[1] = params[1]/1.2;

        return {
            'location':params.join(';'),
            'delay':5000
        };
    }
    else return false;
}


jQuery.cookie = function(name, value, options) {
    if (typeof value != 'undefined') { // name and value given, set cookie
        options = options || {};
        if (value === null) {
            value = '';
            options = $.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed
            options.expires = -1;
        }
        var expires = '';
        if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
            var date;
            if (typeof options.expires == 'number') {
                date = new Date();
                date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
            } else {
                date = options.expires;
            }
            expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
        }
        // NOTE Needed to parenthesize options.path and options.domain
        // in the following expressions, otherwise they evaluate to undefined
        // in the packed version for some reason...
        var path = options.path ? '; path=' + (options.path) : '';
        var domain = options.domain ? '; domain=' + (options.domain) : '';
        var secure = options.secure ? '; secure' : '';
        document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
    } else { // only name given, get cookie
        var cookieValue = null;
        if (document.cookie && document.cookie != '') {
            var cookies = document.cookie.split(';');
            for (var i = 0; i < cookies.length; i++) {
                var cookie = jQuery.trim(cookies[i]);
                // Does this cookie string begin with the name we want?
                if (cookie.substring(0, name.length + 1) == (name + '=')) {
                    cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                    break;
                }
            }
        }
        return cookieValue;
    }
};