/**
 * Container class for Hello releated methods and data.  This object is 
 * attached to the 'window' object in the browser's DOM space.
 *
 * @param optionalHostID            optional create parameter to forces the host ID
 */
var AdobeHello = function( optionalHostID )
{
    try
    {
        this.oname              = "AdobeHello";

        // public data
        this.forceOffline       = false;
        this.alertMode          = false;
        this.productInterface   = (void 0);

        // private data
        var debugMode           = false;
        var productConfig       = { oname : "productConfig" };
        var csInterface         = (void 0);

        // set host application ID
        if ( typeof optionalHostID === "undefined" )
        {
            csInterface = new CSInterface();
        
            // object initialization / constructor
            productConfig.hostID = csInterface.getApplicationID();
        }
        else
        {
            productConfig.hostID = optionalHostID;
        }

        // build host application interface
        if ( productConfig.hostID === "IDSN" )  // InDesign
        {
            productConfig.interface = new HelloInDesign();
        }
        else if ( productConfig.hostID === "ILST" ) // Illustrator
        {
            productConfig.interface = new HelloIllustrator();
        }
        else if ( productConfig.hostID === "PHXS" ) // Photoshop
        {
            productConfig.interface = new HelloPhotoshop();
        }
        else if ( productConfig.hostID === "MUSE" ) // Muse
        {
            productConfig.interface = new HelloMuse();
        }
        else if ( productConfig.hostID === "DRWV" ) // Dreamweaver
        {
            productConfig.interface = new HelloDreamweaver();
        }
        // exposed for DW since we cant seem to call methods??
        this.productInterface = productConfig.interface;
    }
    catch( e )
    {
        alert( "AdobeHello: Exception " + e.message );
    }

    /**
     * Write out to the CEP log and optionally display an alert.
     *
     * @param msg           string object containing the message to log/display
     * @param showAlert     (optional) show the alert box with the message
     */
    AdobeHello.prototype.logMessage = function( msg, showAlert )
    {
        // check for optional param, if not present the go with the class data member's value.
        var doAlert = ( typeof showAlert === "undefined" ) ? this.alertMode : showAlert;
        
        if ( doAlert )
        {
            alert( msg );
        }
        console.log( "<< AdobeHello >> "+msg )
    }
    
    /**
     * Retrieve the point product interface object from this container.
     *
     * @return An [object] containing the point product data & methods.
     */
    AdobeHello.prototype.getProductInterface = function()
    {
        try
        {
            return productConfig.interface;
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::getProductInterface exception: " + e.message  );
        }
    }

    /**
     * Send a CEP event to the host application.  This event should be registered and listened
     * for in the host application.
     *
     * @param eventType         string object containing the event type to send to the host application
     * @param eventData         data object(most likely a string object) to be sent along in the event
     */
    AdobeHello.prototype.sendEvent = function( eventType, eventData )
    {
        try
        {
            if ( typeof csInterface !== "undefined" )
            {
                // to be backwards compatible, some point products may overrided the extension ID's
                var extensionID   = ( typeof productConfig.interface.overrideExtensionID !== "undefined" )  ? productConfig.interface.overrideExtensionID : csInterface.getExtensionID();
                var event         = new CSEvent();
                
                event.type        = eventType;
                event.scope       = "APPLICATION";
                event.data        = eventData;
                event.appId       = csInterface.getApplicationID;
                event.extensionId = extensionID;
                
                // if we are watching events - lets skip all the HighBeam ones
                if ( (eventType.indexOf("LOGPIP") < 0) && (debugMode === true) && (this.alertMode === true) )
                {
                    this.logMessage( "("+extensionID+") sendEvent: "+event.type+((event.data && event.data !== "" )?(" with data: "+event.data):"") );
                }
                
                csInterface.dispatchEvent(event);
            }
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::sendEvent exception: " + e.message  );
        }
    }
    
    /**
     * Execute a script evaluation in the CEP/host application DOM.  This method triggers
     * the specified JavaScript action on the host application and calls the supplied 
     * callback when completed.
     *
     * @param script            string object containing the JavaScript to execute
     * @param callback          fucntion object to call when script execution is complete
     */
    AdobeHello.prototype.evalScript = function( script, callback )
    {
        try
        {
            if ( callback === null || (typeof callback === "undefined") )
            {
                callback = function(result){ };
            }
            
            if ( typeof window.__adobe_cep__ !== "undefined" && window.__adobe_cep__ )
            {
                window.__adobe_cep__.evalScript( script, callback );
            }
            else
            {
                callback( null );
            }
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::evalScript exception: " + e.message  );
        }
    }

    /**
     * Send an event to the host application indicating that the data contained within the
     * event should be logged in HighBeam.
     *
     * @param category          string object containing the HighBeam category to log
     * @param subCategory       string object containing the HighBeam sub-category to log
     * @param eventName         string object containing the HighBeam event name to log
     */
    AdobeHello.prototype.logPIPEvent = function( category, subCategory, eventName )
    {
        try
        {
            var pipLog = {
                            "dataType"    : "event",
                            "category"    : category,
                            "subcategory" : subCategory,
                            "eventname"   : eventName
                         };
            
            var eventData = JSON.stringify( pipLog );
            
            if ( (typeof productConfig.interface.useJSONPIPData !== "undefined") && productConfig.interface.useJSONPIPData === false )
            {
                eventData = category + "," + subCategory + "," + eventName;
            }

            this.sendEvent( productConfig.interface.events.pipEventType, eventData );
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::logPIPEvent exception: " + e.message  );
        }
    }
    
    /**
     * Wrapper/shortcut method for logging HighBeam events corresponding to Hello interactions.
     * This method simply calls 'logPIPEvent' with the category & subCategory already set.
     *
     * @param eventName         string object containing what is essentially the eventName\
     *                          parameter to 'logPIPEvent'
     */
    AdobeHello.prototype.logHelloInteractionPIPEvent = function( eventName )
    {
        this.logPIPEvent( "ProjectHello", "Interaction", eventName );
    }
    
    /**
     * Sends an event to the host application indicating an action is about to 
     * close the Hello UI without the user taking action.
     */
    AdobeHello.prototype.sendAboutToCloseEvents = function()
    {
        try
        {
            this.sendEvent( productConfig.interface.events.aboutToCloseEvent, "" );
            this.logHelloInteractionPIPEvent( "DialogAutoDismiss" );
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::sendAboutToCloseEvents exception: " + e.message  );
        }
    }

    /**
     * Closes the extension.
     */
    AdobeHello.prototype.closeHello = function()
    {
        try
        {
            if ( window.__adobe_cep__ )
            {
                window.__adobe_cep__.closeExtension();
            }
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::closeHello exception: " + e.message  );
        }
    }

    /**
     * Sends a event to the host application requesting the equivalent of a menu
     * selection action.
     *
     * @param menuString        string object containing the action ID to execute, which
     *                          will be interpreted by the host application to trigger the
     *                          action equivalent to the user selecting the corresponding 
     *                          menu item.
     */
    AdobeHello.prototype.sendExecuteMenuCommandEvent = function( menuString )
    {
        this.sendEvent( productConfig.interface.events.handleExecuteMenuCommand, menuString );
    }

    /**
     * Send the open a recent file event to the host application.
     *
     * @param fileName          string object containing the file name to open, or the
     *                          constant "open" to trigger the open file UI in the host
     *                          application
     */
    AdobeHello.prototype.sendRecentFileOpenEvent = function( fileName )
    {
        this.sendEvent( productConfig.interface.events.handleRecentFileOpen, fileName );
    }

    /**
     * Opens the specifed URL in an external browser window.
     *
     * @param url           the requested URL to nagivate to
     */
    AdobeHello.prototype.openLinkInDefaultBrowser = function( url )
    {
        try
        {
            if ( typeof window.cep.util.openURLInDefaultBrowser !== "undefined" )
            {
                this.logHelloInteractionPIPEvent( "OpenExtLink:" + url );
                window.cep.util.openURLInDefaultBrowser( url );
            }
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::openLinkInDefaultBrowser("+url+") exception: " + e.message );
        }
    }
    
    /**
     * Determine if the current browser is running on a MS Windows based OS.
     *
     * @return A boolean value indicating true if the browser is on Windows, false otherwise.
     */
    AdobeHello.prototype.isWindowsOS = function()
    {
        try
        {
            return ( navigator.userAgent.indexOf('Mac OS X') === -1 );
        }
        catch( e )
        {
            this.logMessage( "AdobeHello::isWindowsOS" + e.message );
        }
    }
    
    /**
     * (WIP) Check URL reachability. This method will check if a request can
     * reach the specified URL and then call the supplied callback method with
     * the result.
     * 
     * @param testURL           string object containing the URL to test
     * @param callback          function object which to call on test complete
     */
    AdobeHello.prototype.checkHelloReachability = function( testURL, callback )
    {
        // validate callback parameter
        if ( typeof callback === "undefined" )
        {
            callback = function( isReachable, xhr ) { };
        }
        
        // make sure we have a url to check
        if ( typeof testURL !== "undefined" )
        {
            /*
            var ImageObject = new Image();
            
            ImageObject.src = "https://helpx.qa.adobe.com/illustrator/hello/v1_5/images/AiCreateInitialExp.jpg"; // try to get image

            callback( (ImageObject.height>0) ? true : false, ImageObject.height );
             */
            
            // prevent ajax from being cancelled in the middle - this is done
            // when a navigation is done in the middle of the ajax call running
            // and since we have a 2 sec timeout on the ajax, it's a possiblity
            $(document).ajaxError(  function(e, xhr, settings, exception)
                                    {
                                        if ( xhr.readyState == 0 || jqxhr.status == 0 )
                                        {
                                            return; //Skip this error
                                        }
                                    });
            
            $.ajax({    url: testURL,
                        type: "HEAD",
                        timeout:2000,
                        success :   function( response, textS, xhr )
                                    {
                                        callback( true, xhr );
                                    },
                        error : function( xhr, textStatus, errorThrown )
                                {
                                    callback( false, xhr );
                                }
                   });
        }
        else
        {
            callback( false, void 0 );  // leave the other param undefined
        }
    }

    /**
     * Generates a hardcoded JSON for the Hello data. This method is useful in debugging or when the
     * host application is unable to provide the Hello JSON data. HOWEVER, the contents of this method 
     * SHOULD BE REMOVED prior to release, but the method can stay in place...
     * 
     * @param addRecents        add the array object into the JSON for the example recent files list
     * @return A string object containing the generated JSON data.
     */
    AdobeHello.prototype.getDebugJSON = function( addRecents )
    {
        var appID           = "1233"; // Muse - but not supported yet
        var appVer          = "10.0";
        var recentFileIcon  = "museicon_small";
        var newDocTypes     = '{"docType": "site","name": "Muse Site","tip": "New Site","icon": "museicon_small"}';
        
        if ( productConfig.hostID === "IDSN" )  // InDesign
        {
            appID           = "1235";
            appVer          = "10.0";
            recentFileIcon  = "id_docgeneric_small";
            newDocTypes     = '{"docType": "document","name": "InDesign Document","tip": "New Document","icon": "id_docgeneric_small"},{"docType": "book","name": "InDesign Book","tip": "New Book","icon": "id_book_small"},{"docType": "folio","name": "InDesign Folio","tip": "New Folio","icon": "id_docgeneric_small"},{"docType": "library","name": "InDesignLibrary","tip": "New Library","icon": "id_library_small"}';
        }
        else if ( productConfig.hostID === "ILST" ) // Illustrator
        {
            appID           = "1232";
            appVer          = "18.0";
            recentFileIcon  = "aiicon_small";
            newDocTypes     = '{"docType": "document","name": "InDesign Document","tip": "New Document","icon": "aiicon_small"}';
            
        }
        else if ( productConfig.hostID === "PHXS" ) // Photoshop
        {
            appID           = "1234";
            appVer          = "14.0";
            recentFileIcon  = "psicon_small";
            newDocTypes     = '{"docType": "print","name": "Photo Document","tip": "New Document","icon": "psicon_small"}';
        }
        
        var recentFiles = "";
        
        if ( typeof addRecents !== "undefined" && addRecents === true )
        {
            recentFiles = '{"fullpath": "0","name": "MyTestDocument","tip": "/Users/mortimer/mydocument","icon": "'+recentFileIcon+'"},';
        }
        
        return ( '{"appid": "'+appID+'","appversion": "'+appVer+'","language": "en_US","countryCode": "US","platform": "mac","adobeid": "MORTIMER@ADOBE.COM","delegateGuid": "530746314404CB3E992015D5","userTrackingEnabled": "true","appStartClockTime": "1412010596","accountType": "paid","secondsLeftInTrial": "31416602","greeting": "Hello Michael!","dontShowAgain": "false","newDocTypes":['+newDocTypes+'],"recentFiles":['+recentFiles+'{"fullpath": "open","name": "Open...","tip": "Select an existing file to work with.","icon": "openicon"}],"visitCounter":{"newfeatureCount": "0","getstartedCount": "0","tipsntechniquesCount": "0"},"launchCounter": "0","lastError": ""}' );
    }
};

/**
 * Handle the redirect to the proper Hello URL.
 */
function redirectToAppropriateHelloPage()
{
    // create our product & CEP info object
    if ( typeof window.__adobe_hello === "undefined" )
    {
        window.__adobe_hello = new AdobeHello();
    }
    
    // set default URL to offline
    var productInterface = window.__adobe_hello.getProductInterface();
    var helloURL         = productInterface.url.offline;  //Initializing to offline case by default
    var pipEventName     = "DisplayOfflineHello";
    
    // make sure we are online and switch URL
    if ( window.navigator.onLine === true && window.__adobe_hello.forceOffline === false )
    {
//        window.__adobe_hello.checkHelloReachability(productInterface.url.online, function( isReachable, xhr )
//                                               {
//                                                   alert("Is "+(isReachable ? " ":"not ")+"reachable status code: "+xhr);
//                                               });
        helloURL     =  productInterface.url.online;
        pipEventName = "DisplayRemoteHello";
    }

    // switch to the proper Hello URL
    window.__adobe_hello.logHelloInteractionPIPEvent( pipEventName );
    window.location = helloURL;
}

/**
 * Called from the Hello URL's main.js which could be either online or offline...
 * This method sets up the window.projectHello object and the window.__adobe_hello object.
 */
function onLoaded()
{
    try
    {
        // new one needed here since we are now on a different DOM from the one created in redirectToAppropriateHelloPage
        if ( typeof window.__adobe_hello === "undefined" )
        {
            window.__adobe_hello = new AdobeHello('DRWV');
        }
        
        var productInterface = window.__adobe_hello.getProductInterface();

        // attach and setup the projectHello object
        window.projectHello =   {
                                    hostAppGetPersonalizationInfo 		: function(callback) { productInterface.getUserJsonData(callback); },
                                    hostAppOpenDoc						: function(fullPath) { productInterface.openExistingDocument(fullPath); },
                                    hostAppCreateNewDoc			        : function(documentType, suppressNewDocUI) { productInterface.openDocumentOfType(documentType, suppressNewDocUI); },
                                    hostAppSetDoNotShowAgainPreference	: function(dontShowAgain) { productInterface.setDontShowAgainPreference(dontShowAgain); },
                                    hostAppRetryLoadFromServer	        : function() { productInterface.retryLoadFromServer(); },
                                    hostAppNotifyDoneWithUI		        : function() { productInterface.notifyDoneWithDialog(); },
                                    hostAppNotifyFailedToLoad	        : function(errorString) { productInterface.notifyFailedToLoad(errorString); },
                                    hostAppNotifyInContentTutorial		: function(isInContentTutorial) { productInterface.notifyInContentTutorial(isInContentTutorial); },
                                    hostAppNotifyContentTabChanged      : function(currentTab) { productInterface.notifyContentTabChanged(currentTab); },
                                    openURLInDefaultBrowser         	: function(url) { productInterface.openLinkInDefaultBrowser(url); }
                                };
    }
    catch( e )
    {
        window.__adobe_hello.logMessage( "onLoaded" + e.message );
    }
}
