/*!
 *  install.js - A javascript abstraction library which makes it easy
 *               to integrate in-page browserplus installation.
 * 
 *  Usage:
 *
 *  BPTool.installer.show() is a drop in replacement for BrowserPlus.init()
 * 
 *  the former will display an in page installation flow in the event
 *  browserplus is not installed
 *  
 *  (c) Yahoo! Inc 2008-2009 All rights reserved
 */

// create BPTool object if required
if (typeof BPTool == "undefined" || !BPTool) {
    var BPTool = {};
}

// handle multiple inclusions of this file
BPTool.Installer = typeof BPTool.Installer != "undefined" && BPTool.Installer ? BPTool.Installer : function() {

    var OverlayInstalled = false;
    var OverlayId = "bpt_install_overlay";
    var DialogId  = "bpt_install_dialog";

    var assetServer = 'http://bp.yahooapis.com/toolbox/installer/1.0.10/' + 'assets/';
    var siteSprite = "http://l.yimg.com/a/i/us/bp/s/1.4/site/site-sprite.png";
    var userInitCB = null;
    var userInitArgs = null;

    var OkAction = null;
    var CancelAction = null;
    var ForumLink   = "<a href=\"http://developer.yahoo.net/forum/index.php?showforum=83\">BrowserPlus Forums</a>";
    var SupportLink = "<a href=\"http://browserplus.yahoo.com/support/\">Support page</a>";
    var InstallURL = "http://browserplus.yahoo.com/dist/v2/installer/";
    var InstallTitle = "Installing BrowserPlus&trade;";
    var WindowsBrowsers = "Internet Explorer, Firefox, Safari and Chrome";
    var WindowsOS = "Windows XP and Windows Vista";
    var MacBrowsers = "Firefox and Safari";
    var MacOS = "Mac OS X (Intel)";
    var BPName = "BrowserPlus&trade;";
    
    var CSS = {
        s_select  : { display: 'inline-block', border: '1px solid rgb(200, 210, 230)', padding: '1px 0 0 4px', fontFamily: 'Arial', 
                      fontSize: 'smaller', position: 'relative', top: '1px'},
        s_overlay : { background: "#000", opacity: "0.33", position: "fixed", top: "0px", left: "0px", width: "100%", height: "100%", display: "none"},
        s_dialog  : { background: "#fff", position: "absolute", zIndex: "999", top:"0px", left: "0px", width: "550px", display: "none", padding: "0", 
                    margin: "0", fontFamily: "Arial, Helvetica, Verdana, sans-serif", border: "1px solid #666"}
    };

    // stylesheets? we don't need no stinkin' stylesheets
    var Styles = {
        s_p         : 'margin:1em 0;',
        s_div       : 'border:8px solid #639; position:relative;text-align:left;background:#fff;',
        s_body      : 'font-size:9pt; padding:0 10px;',
        s_note      : 'font-size:8pt; padding:5px 10px 2px 10px;',
        s_title     : 'font-size: 12pt; margin: 10px 0 5px 0;',
        s_step1     : 'background:url(' + assetServer + 'bullet_1.gif) 0 1em no-repeat;',
        s_step2     : 'background:url(' + assetServer + 'bullet_2.gif) 0 1em no-repeat;',
        s_step3     : 'background:url(' + assetServer + 'bullet_3.gif) 0 1em no-repeat;',
        s_step4     : 'background:url(' + assetServer + 'bullet_4.gif) 0 1em no-repeat;',
        s_steps     : 'margin:0;padding:0 10px 0 0;',
        s_num       : 'background:#f57208;padding:1px 4px;color:white;font-weight:bold;',
        s_numdiv    : 'margin:4px 0;',
        s_step_li   : 'padding:5px 0 0 35px; margin:0;min-height:35px; list-style:none; font-size:9pt; color:#333;',
        s_error     : 'padding:8px; background:#f9e5f0; border:2px solid #d00; font-family:monospace;',
        s_bt        : 'width:90px; height:20px; display:block; border:1px solid #666; text-decoration:none; text-align:center; margin:auto; font-size:9pt;',
        s_bt_cancel : 'visibility:hidden; position:absolute; top:8px; left:280px; background:#999 url(' + siteSprite + ') 0 -700px repeat-x;',
        s_bt_ok     : 'visibility:hidden; position:absolute; top:8px; left:380px; background:#ff800e url(' + siteSprite + ') 0 -655px repeat-x;',
        s_bt_span   : 'font:bold 100% arial, sans-serif; line-height:20px; color:#fff;',
        s_ft        : 'position:relative; height:38px; margin:0; font-size:8pt; border-top:1px solid #ccc;' + 
                       'background: #fff url(' + assetServer + 'bp-logo-sm.gif) 5px 8px no-repeat;',
        s_st_con    : 'margin-top:10px;width:510px;height:15px;border:1px solid #333;',
        s_st_bar    : 'width:0%;height:15px;background-color:#b67cd1;'
     };

    var dialogTmpl = 
    '<div style="{s_div}">' +
    '  <div style="{s_body}"><h1 style="{s_title}">{title}</h1>{body}</div>' +
    '  <div id="installNoteId" style="{s_note}">{note}</div>' +
    '  <div style="{s_ft}">' + 
    '    <a id="bpt_install_bt_cancel" style="{s_bt}{s_bt_cancel}" href="#"><span style="{s_bt_span}">{bt1}</span></a>' + 
    '    <a id="bpt_install_bt_ok" style="{s_bt}{s_bt_ok}" href="#"><span id=\"bstart\" style="{s_bt_span}">{bt2}</span></a>' + 
    '  </div>' +
    '</div>';
    
    // Please wait while we load BrowserPlus for the first time

    var startState = 
      '<li style="{s_step_li}{s_step1}">' + 
    '<p style="{s_p}">Click <b>Start Install</b> to begin BrowserPlus installation.  Installation should take less than a minute, and you won\'t even need to restart your browser. </p>' +
      '</li>';
            
    var browserData = {
        MacJava: {
            stateText1 :
                '<li style="{s_step_li}{s_step1}">' + 
                '<p style="{s_p}">Click <b>Start Install</b> to run the installer. </p>' +
                '</li>' +
                '<p style="{s_p}">You will be prompted to verify you trust software signed by Yahoo!, click the <b>Trust</b> button.</p>' +
                '<center><img src="'+assetServer+'java_trust.jpg" /></center></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step2};">' +
                '<p style="{s_p}">In just a moment the installer will open. Click <b>Install</b> to complete your installation.</b></p>' +
                '<center><img src="'+ assetServer+'install_begin.jpg" /></center></li>' + 
                '<div id="statusBarContainer" style="{s_st_con}">' + 
                '  <div id="statusBarProgress" style="{s_st_bar}"></div>' + 
                '</div>'
        },
        MacFirefox: {
            stateText1 : 
                '<li style="{s_step_li}{s_step1}">' +
                '<p style="{s_p}">Click <b>Start Install</b> to begin your download.</p>' +
                '</li>' + 
                '<li style="{s_step_li}{s_step2}">' +
                '<p style="{s_p}">Firefox will prompt you confirm the download.  Click <b>OK</b> to continue.</p>' +
                '<img src="'+assetServer+'save_file_macfirefox.jpg" /></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step3};"><p style="{s_p}">' + 
                '<div style="{s_numdiv}"><span style="{s_num}">1</span> <b>Double-click</b> BrowserPlus Installer.</div>' +
                '<div style="{s_numdiv}"><span style="{s_num}">2</span> Choose to <b>Open</b> the application.</div>' +
                '<div style="{s_numdiv}"><span style="{s_num}">3</span> Press <b>Install</b>.</div></p></li>' +
                '<img src="'+ assetServer+'mac_open_install.jpg" />'
        },
        MacSafari: {
            stateText1 : 
                '<li style="{s_step_li}{s_step1}">' +
                '<p style="{s_p}">Click <b>Start Install</b> to begin your download.</p>' + 
                '<img src="'+ assetServer+'mac_package.jpg" /></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step2};"><p style="{s_p}">' + 
                '<div style="{s_numdiv}"><span style="{s_num}">1</span> <b>Double-click</b> BrowserPlus Installer.</div>' +
                '<div style="{s_numdiv}"><span style="{s_num}">2</span> Choose to <b>Open</b> the application.</div>' +
                '<div style="{s_numdiv}"><span style="{s_num}">3</span> Press <b>Install</b>.</div></p></li>' +
                '<img src="'+ assetServer+'mac_open_install.jpg" />'
        },
        WindowsJava: {
            stateText1 :
                '<li style="{s_step_li}{s_step1}">' + 
                '<p style="{s_p}">Click <b>Start Install</b> to run the installer. </p>' +
                '</li>' +
                '<p style="{s_p}">You will be prompted to verify you trust software signed by Yahoo!, click the <b>Trust</b> button.</p>' +
                '<center><img src="'+assetServer+'java_trust.jpg" /></center></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step2}">' +
                '<p style="{s_p}">In just a moment the installer will open. Click <b>Install</b> to complete your installation.</b></p>' +
                '<center><img src="'+ assetServer+'install_begin.jpg" /></center></li>' + 
                '<div id="statusBarContainer" style="{s_st_con}">' + 
                '  <div id="statusBarProgress" style="{s_st_bar}"></div>' + 
                '</div>'
        },
        WindowsChrome: {
            stateText1 : 
                '<li style="{s_step_li}{s_step1}">' + 
                '<p style="{s_p}">Click <b>Start Install</b> to begin your download.</p>' +
                '</li>' +
                '<li style="{s_step_li}{s_step2}">' + 
                '<p style="{s_p}">When the download is complete, click on the icon in the bottom bar:</p>' +
                '<img src="'+assetServer+'chrome_save.jpg" /></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step3}">' +
                '<p style="{s_p}">Once you click on the downloaded installer, Chrome will confirm that you wish to run the ' + BPName + 
                ' installation. Click <b>Run</b> to begin the installation.  After installation, <b>restart</b> your browser ' +
                'for ' + BPName + ' to take effect.</p>' +
                '<img src="'+ assetServer+'chrome_security.jpg" /></li>'
        },
        WindowsSafari: {
            stateText1 : 
                '<li style="{s_step_li}{s_step1}">' +
                '<p style="{s_p}">Click <b>Start Install</b> to begin your download.</p>' +
                '</li>' + 
                '<li style="{s_step_li}{s_step2}">' +
                '<p style="{s_p}">A Security Warning like the one below will appear. Click <b>Run</b> to confirm the download.</p>' +
                '<img src="'+assetServer+'run_file_winsafari.jpg" /></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step3}">' +
                '<p style="{s_p}">When the installer opens, click <b>Install</b> to complete your installation.</b></p>' +
                '<center><img src="'+ assetServer+'win_install_begin.jpg" /></center></li>'
        },
        WindowsFirefox: {
            stateText1 : 
                '<li style="{s_step_li}{s_step1}">' +
                '<p style="{s_p}">Click <b>Start Install</b> to begin your download.</p>' +
                '</li>' +
                '<li style="{s_step_li}{s_step2}">' +
                '<p style="{s_p}">Firefox will prompt you confirm the download. Click <b>Save File</b> to continue.</p>' +
                '<img src="'+assetServer+'save_file_winfirefox.jpg" /></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step3}">' +
                '<p style="{s_p}">Firefox is downloading the installer.  Click <b>Save File</b> to continue.</p>' +
                '<img src="'+assetServer+'save_file_2_winfirefox.jpg" />' +
                '</li>' +
                '<li style="{s_step_li}{s_step4}">' +
                '<p style="{s_p}">Once the download has completed, click <b>Open</b> in the Downloads window to start the installer. ' + 
                '(<b>Note</b>: if the Downloads window does not appear, type Ctrl+J). A dialog may prompt you to confirm that ' + 
                'you want run the installer.</p>' +
                '<img src="'+assetServer+'open_exe_winfirefox.jpg" /></li>'
        },
        WindowsExplorer: {
            stateText1 : 
                '<li style="{s_step_li}{s_step1}">' +
                '<p style="{s_p}">Click <b>Start Install</b> to begin your download.</p>' +
                '</li>' + 
                '<li style="{s_step_li}{s_step2}">' +
                '<p style="{s_p}">A Security Warning like the one below will appear. Click <b>Run</b> to confirm the download.</p>' +
                '<img src="'+assetServer+'run_file_winie7.jpg" /></li>',
            stateText2 : 
                '<li style="{s_step_li}{s_step3}">' +
                '<p style="{s_p}">Internet Explorer is downloading the installer.  After the first Security Warning, a second warning will ' + 
                'appear.  Click <b>Run</b> a second time to start the installer.</p>' +
                '<img src="'+assetServer+'run_signed_file_winie7.jpg" />' +
                '<p style="{s_p}">After the install is complete the Information Bar may appear to confirm you want to use ' + BPName + '. ' + 
                'Choose <b>Run ActiveX Control</b> from the info bar and confirm any other security dialogs that result.</p>' +
                '<img src="'+assetServer+'activex_infobar_winie7.jpg" /></li>'
        }
    };

    /**
     * Outputs an applet tag with the specified attributes and parameters, where
     * both attributes and parameters are associative arrays.  Each key/value 
     * pair in attributes becomes an attribute of the applet tag itself, while
     * key/value pairs in parameters become <PARAM> tags.  No version checking 
     * or other special behaviors are performed; the tag is simply written to 
     * the page using document.writeln().
     *
     * As document.writeln() is generally only safe to use while the page is 
     * being rendered, you should never call this function after the page 
     * has been completed.
     */
    var writeAppletTag = function(attributes, parameters) {
        var s = '<' + 'applet ';
        for (var attribute in attributes) {
            s += (' ' + attribute + '="' + attributes[attribute] + '"');
        }
        s += '>';
    
        if (parameters != 'undefined' && parameters != null) {
            var codebaseParam = false;
            for (var parameter in parameters) {
                if (parameter == 'codebase_lookup') {
                    codebaseParam = true;
                }
                s += '<param name="' + parameter + '" value="' + 
                    parameters[parameter] + '">';
            }
            if (!codebaseParam) {
              s += '<param name="codebase_lookup" value="false">';
            }
        }
        s += '<' + '/' + 'applet' + '>';

	    var div = document.createElement("div");
        div.style.visibility = "hidden";
        try { div.style.borderStyle = "hidden"; } catch (e) { }
        div.style.width = 0;
        div.style.height = 0;
        div.style.border = 0;
        div.style.position = "absolute";
        div.style.top = 0;
        div.style.left = 0;
        div.innerHTML = s;
        document.body.appendChild(div);
    };

    var removeAppletTag = function(id) {
      try {
        document.body.removeChild(document.getElementById(id));
      }
      catch(e) {
        try { console.log("couldn't remove applet tag: " + e); } catch(e) {}
      }
    }

    var ua = function() {
        var o={ie:0, opera:0, gecko:0, webkit: 0};
        var ua=navigator.userAgent, m;
        //console.log("ua="+ua);
        // Modern KHTML browsers should qualify as Safari X-Grade
        if ((/KHTML/).test(ua)) {
            o.webkit=1;
        }

        // Modern WebKit browsers are at least X-Grade
        m=ua.match(/AppleWebKit\/([^\s]*)/);
        if (m&&m[1]) {
            o.webkit=parseFloat(m[1]);
        }

        if (!o.webkit) { // not webkit
            m=ua.match(/Opera[\s\/]([^\s]*)/);
            if (m&&m[1]) {
                o.opera=parseFloat(m[1]);
            } else { // not opera or webkit
                m=ua.match(/MSIE\s([^;]*)/);
                if (m&&m[1]) {
                    o.ie=parseFloat(m[1]);
                } else { // not opera, webkit, or ie
                    m=ua.match(/Gecko\/([^\s]*)/);
                    if (m) {
                        o.gecko=1; // Gecko detected, look for revision
                        m=ua.match(/rv:([^\s\)]*)/);
                        if (m&&m[1]) {
                            o.gecko=parseFloat(m[1]);
                        }
                    }
                }
            }
        }
        return o;
    }();
    
    var isIE = ua.ie;
    var isOpera = ua.opera;

    var substitute = function(s, o) {
        var i, j, k, key, v, meta, saved=[], token, SPACE=' ', LBRACE='{', RBRACE='}';

        for (;;) {
            i = s.lastIndexOf(LBRACE);
            if (i < 0) { break;}
            j = s.indexOf(RBRACE, i);
            if (i + 1 >= j) { break; }

            //Extract key and meta info 
            token = s.substring(i + 1, j);
            key = token;
            meta = null;
            k = key.indexOf(SPACE);
            if (k > -1) {
                meta = key.substring(k + 1);
                key = key.substring(0, k);
            }

            // lookup the value
            v = o[key];
            s = s.substring(0, i) + v + s.substring(j + 1);
        }

        // restore saved {block}s
        for (i=saved.length-1; i>=0; i=i-1) {
            s = s.replace(new RegExp("~-" + i + "-~"), "{"  + saved[i] + "}", "g");
        }

        return s;
    };

    var get = function(el) {
        return (el && el.nodeType) ? el : document.getElementById(el);
    };
    
    var css = function(el, property, val) {
        el = get(el);
        switch(property)
        {
            case 'opacity':
                if (isIE) {
                    if ( isString(el.style.filter) ) {
                        el.style.filter = 'alpha(opacity=' + val * 100 + ')';
                        if (!el.currentStyle || !el.currentStyle.hasLayout) {
                            el.style.zoom = 1;
                        }
                    }
                } else {
                    el.style.opacity = val;
                }
                break;
            case 'z-index':
                el.style[property] = val;
                el.style.zIndex = val;
                break;
            case 'float':
                property = isIE ? "styleFloat" : "cssFloat";
                el.style[property] = val;
                break;
            default:
                el.style[property] = val;
                break;
        }
    };
    
    var isString = function(o) {
        return typeof o === 'string';
    };

    function stylize(el, params)
    {
        var key;
        for (key in params) {
            if (params.hasOwnProperty(key)) {
                css(el, key, params[key]);
            }
        }
    }

    var addListener = function (el, type, fn) {
        if (isString(el)) { el = get(el); }

        if (el.addEventListener){
            el.addEventListener(type, fn, false);
        } else if (el.attachEvent) {
            el.attachEvent("on"+type, fn);
        }
    };

    var removeListener = function(el, type, fn) {
        if (isString(el)) { el = get(el); }

        if (el.removeEventListener){
            el.removeEventListener(type, fn, false);
        } else if (el.detachEvent) {
            el.detachEvent("on"+type, fn);
        }
        
    };

    var getViewportHeight = function() {
        var height = self.innerHeight; // Safari, Opera
        var mode = document.compatMode;

        if ( (mode || isIE) && !isOpera ) { // IE, Gecko
            height = (mode == 'CSS1Compat') ?
                document.documentElement.clientHeight : // Standards
                document.body.clientHeight; // Quirks
        }
        return height;
    };

    var getViewportWidth = function() {
        var width = self.innerWidth;  // Safari
        var mode = document.compatMode;

        if (mode || isIE) { // IE, Gecko, Opera
            width = (mode == 'CSS1Compat') ?
                document.documentElement.clientWidth : // Standards
                document.body.clientWidth; // Quirks
        }
        return width;
    };
    
    var resizeCB = function() {
        // we only need to move the dialog based on scroll position if
        //   we're using a browser that doesn't support position: fixed, like < IE 7
        var left = window.XMLHttpRequest === null ? document.documentElement.scrollLeft : 0;
        var top = window.XMLHttpRequest === null ? document.documentElement.scrollTop : 0;
        var div = get(DialogId);
        var h = div.offsetHeight;
        var w = div.offsetWidth;

        div.style.left = Math.floor(Math.max((left + (getViewportWidth() - w) / 2), 0)) + 'px';
        div.style.top  = "100px";
    };

    var replaceSelectsWithSpans = function()
    {
        var i, selects = document.getElementsByTagName('select');

        for (i = 0; i < selects.length; i++)
        {
            var select = selects[i];

            if (select.clientWidth === 0 || select.clientHeight === 0 || 
                select.nextSibling === null || select.nextSibling.className === 'selectReplacement') {
                continue;
            }

            var span = document.createElement('span');

            span.style.height = (select.clientHeight - 4) + 'px';
            span.style.width = (select.clientWidth - 6) + 'px';
            span.className = 'selectReplacement';
            stylize(span, CSS.s_select);

            span.innerHTML = select.options[select.selectedIndex].innerHTML + 
                '<img src="' + assetServer + 'select_arrow.gif" alt="drop down" style="position: absolute; right: 1px; top: 1px;" />';


            select.cachedDisplay = select.style.display;
            select.style.display = 'none';
            select.parentNode.insertBefore(span, select.nextSibling);
        }
    };

    var removeSelectSpans = function()
    {
        var i, selects = document.getElementsByTagName('select');

        for (i = 0; i < selects.length; i++)
        {
            var select = selects[i];

            if (select.clientWidth === 0 || select.clientHeight === 0 || 
                select.nextSibling === null || select.nextSibling.className != 'selectReplacement') {
                continue;
            }

            select.parentNode.removeChild(select.nextSibling);
            select.style.display = select.cachedDisplay;
        }
    };

    var removeButtonListeners = function() {
        if (OkAction) {
            removeListener("bpt_install_bt_ok", "click", OkAction);
        }
        if (CancelAction) {
            removeListener("bpt_install_bt_cancel", "click", CancelAction);
        }        
    };

    var startJavaDownload = function(downloadPath, currentBrowser) {
        // load the applet!
        var attributes = {
            codebase:'http://bp.yahooapis.com/toolbox/installer/1.0.10/' + 'assets/',
            code:'com.yahoo.browserplus.installer.bplusloader.class',
            archive:'bplusloader_signed.jar',
            width:0, 
            height:0,
            id:'bplusInstallerApplet'    		  
        };
        var parameters = {
            installerBaseURL: InstallURL
        };
        writeAppletTag(attributes, parameters);

        removeButtonListeners();
        var body = "<ul style=\"{s_steps}\">" + browserData[currentBrowser].stateText2 + '</ul>';
        var note = "Waiting for installation to complete...";
        CancelAction = null;
        OkAction = cancelCB;
        var title = InstallTitle + " <img src=\"" + assetServer + "waiting-ball-sm.gif\">";

        var firstPoll = true; 
        var lastPercent = -1;
        var noteId; 
        var progress; 

        var timerId = setInterval(function() {
		    var status, percent, applet =
              document.getElementById('bplusInstallerApplet');
          
            try {
                percent = applet.status().percent;
                status = String(applet.status().status);

                // render the dialog on the first successful poll of the java
                // applet.  only at this point do we know java is installed
                if (firstPoll) {
                    renderDialog(DialogId,
                                 {
                                    "title": title,
                                    "body": body,
                                    "note": note,
                                    "okLabel": "Cancel"
                                 });
                    noteId = document.getElementById("installNoteId");
                    progress = document.getElementById("statusBarProgress");
                    firstPoll = false;
                } 

                if (percent != lastPercent) {
                    lastPercent = percent;
                    css(progress, "width", percent + "%");
                }

		    } catch (ex) {
			    status = "error";
		    }

            if (noteId) noteId.innerHTML = status;

            if (status === "error" || status === "complete") {
                clearInterval(timerId);
            }
            if (status === "error") {
                // fallback to the non-java installation
                var csi = BrowserPlus.clientSystemInfo();
                currentBrowser = csi.os + csi.browser;
                startDownload(downloadPath, currentBrowser);
            }
		}, 200);

        BrowserPlus.initWhenAvailable({},function(res){
            if (res.success) {
                cancelCB();
                userInitCB(res);
            } else {
                createDialog(res, false);
            }
        });
    };


    var startDownload = function(downloadPath, currentBrowser) {
        removeButtonListeners();
        var body = "<ul style=\"{s_steps}\">" + browserData[currentBrowser].stateText2 + '</ul>';
        var note = "Waiting for installation to complete...";
        CancelAction = null;
        OkAction = cancelCB;
        var title = InstallTitle + " <img src=\"" + assetServer + "waiting-ball-sm.gif\">";
        renderDialog(DialogId, {"title": title, "body": body, "note": note, "okLabel": "Cancel"});

        BrowserPlus.initWhenAvailable({},function(res){
            if (res.success) {
                cancelCB();
                userInitCB(res);
            } else {
                createDialog(res, false);
            }
        });

        if (downloadPath) {
            var iframe = document.createElement("iframe");
            iframe.src = downloadPath;
            iframe.style.display = "none";
            document.body.appendChild(iframe);
        }
    };

    var cancelCB = function() {
        removeAppletTag('bplusInstallerApplet');
        removeButtonListeners();
        removeListener(window, "resize", resizeCB);

        if (window.XMLHttpRequest === null) {
            removeSelectSpans();
        }
        
        css(OverlayId, "display", "none");
        css(DialogId,  "display", "none");
    };

    var renderDialog = function(el, obj)
    {
        var key;
        el = get(el);
        
        var params = {
            "title" : obj.title,
            "body"  : obj.body,
            "note"  : obj.note,
            "bt1"   : (obj.cancelLabel || "Cancel"),
            "bt2"   : (obj.okLabel || "OK")
        };
        
        for (key in Styles) {
            if (Styles.hasOwnProperty(key)) {
                params[key] = Styles[key];
            }
        }

        el.innerHTML = substitute(dialogTmpl, params);
    
        if (obj.okAction) {
            css("bpt_install_bt_ok", "visibility", "visible");
            addListener("bpt_install_bt_ok", "click", obj.okAction);
            OkAction = obj.okAction;
        } else {
            css("bpt_install_bt_ok", "visibility", "hidden");
        }

        if (obj.cancelAction) {
            css("bpt_install_bt_cancel", "visibility", "visible");
            addListener("bpt_install_bt_cancel", "click", obj.cancelAction);
            CancelAction = obj.cancelAction;
        } else {
            // IE workaround
            try {    
              css("bpt_install_bt_cancel", "visibility", "hidden");
            } catch(ex) {
              // silently ignore  
            }    
        }
    };

    var createDialog = function(res, runningJava) {

        var downloadPath, supported="";
        var currentSystem = BrowserPlus.clientSystemInfo();

        var obj = {
            browser: "",
            title: "",
            body: "",
            note: "",
            cancelAction: null,
            cancelLabel: "Cancel",
            okAction: cancelCB,
            okLabel: "OK",
            error: false
        };

        if (currentSystem.os === "Mac") {
            downloadPath = InstallURL + "osx/";    
            supported = "At this time, " + BPName + " supports " + MacBrowsers + " on " + MacOS;
        } else if (currentSystem.os === "Windows") {
            downloadPath = InstallURL + "win32/";    
            supported = "At this time, " + BPName + " supports " + WindowsBrowsers + " on " + WindowsOS;
        }
        
        if (res.error === "bp.notInstalled" || res.error === "bpPlugin.platformBlacklisted") {

            obj.browser = currentSystem.os + "Java";

            if (currentSystem.supported === "unsupported") {
                obj.title = BPName + " Unavailable";
                obj.body = "<p style=\"{s_p}\">At this time, " + BPName + " is only supported on " + MacOS + ", " + 
                    WindowsOS + ". Please see our " + SupportLink + " for more information.</p>";
            } else if (!browserData[obj.browser]) {
                obj.title = BPName + " Unavailable";
                obj.body = "<p style=\"{s_p}\">" + supported + ".</p> <p style=\"{s_p}\">Please see the " + 
                    SupportLink + " for more information.</p>";
                obj.note = "<b>Note:</b> If you still wish to download the installer for use with other browsers " + 
                    "on your computer, you can <a href=\"" + downloadPath + "\">download the installer</a>.";
            } else {
                if (res.error === "bpPlugin.platformBlacklisted") {
                    obj.title = BPName + " Update Required";
                    obj.body = "<p style=\"{s_p}\">Security updates require that you install a new version of " + BPName + "</b>.</p>";
                } else {
                    obj.title = InstallTitle;
                }

                obj.body += startState;

                obj.okLabel = "Start Install";
                obj.okAction = function() {
                    if (runningJava) {
                        document.getElementById("bstart").innerHTML = "Downloading";
                        startJavaDownload(downloadPath, obj.browser);
                    } else {
                        // fallback to the non-java installation
                        var csi = BrowserPlus.clientSystemInfo();
                        currentBrowser = csi.os + csi.browser;
                        startDownload(downloadPath, currentBrowser);
                    }
                };
                obj.cancelAction = cancelCB;
            }
            
        } else {
            obj.title = "Error Loading " + BPName;
            obj.body += "<p style=\"{s_p}\">A problem occured when trying to initialize browserplus.</p>" +
                "<p style=\"{s_error}\">" + res.error + (res.verboseError ? ": " + res.verboseError : "") + "</p>" + 
                "<p style=\"{s_p}\">You can report this problem on the " + ForumLink + ".</p>" +
                "<p style=\"{s_p}\">You can try reinstalling the software by <a href=\"" + downloadPath + 
                "\">downloading the installer</a> and restarting your web browser.</p>";

            obj.error = true;
        }
        
        var overlay, dialog;
        if (!OverlayInstalled) {
            OverlayInstalled = true;
            overlay = document.createElement("div");
            overlay.id = OverlayId;
            stylize(overlay, CSS.s_overlay);
            document.body.appendChild(overlay);

            dialog = document.createElement("div");
            dialog.id = DialogId;
            stylize(dialog, CSS.s_dialog);
            document.body.appendChild(dialog);

        } else {
            overlay = get(OverlayId);
            dialog = get(DialogId);
        }

        css(overlay, "display", "block");
        // special < IE7 -only processing for windowed elements, like select    
        if (window.XMLHttpRequest === null) {
            replaceSelectsWithSpans();
        }

        renderDialog(dialog, obj);
        css(dialog, "display", "block");
        resizeCB();
        addListener(window, "resize", resizeCB);
    };
    
 
    return {
        show: function(initArgs, callback, config) {
            var cfg = config || {};
            BrowserPlus.init(initArgs, function(res) {
                var sys = BrowserPlus.clientSystemInfo();
                var runJava;
                
                if (res.success) {
                    // that's easy, BrowserPlus is installed and we're done
                    callback(res);
                } else {
                    userInitArgs = initArgs;
                    userInitCB = callback;

                    // at present, we'll only do the java installation
                    // on firefox.  More platforms will turn on by default
                    // as they get more testing.
                    if (sys.os === "Mac" && sys.browser !== "Safari") {
                        runJava = (cfg['macJava'] !== false);
                    } else if (sys.os === "Mac") {
                        runJava = (cfg['macJava'] === true);
                    } else {
                        runJava = (cfg['winJava'] === true);
                    }
                    createDialog(res, runJava);
                }
            });
        }
    };
}();

