/*
 * ADOBE CONFIDENTIAL
 *
 * Copyright (c) 2015 Adobe Systems Incorporated. All rights reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 */

(function () {
    "use strict";


    var GeneratorConnection = require("../common/js/GeneratorConnection"),
        TemplateManager     = require("./js/TemplateManager"),
        JSXRunner           = require("../common/JSXRunner"),
        pkgjson             = require("../package.json"),
        PreviewGlobal       = require("../common/PreviewGlobal"),
        IPCMessage          = require("preview-common/IPCMessage"),
        _                   = require("lodash");

    var $ = PreviewGlobal.window.$,
        $getTheApp,
        $devices,
        $versionString,
        $content = $("#content"),
        $footer,
        $checkForDevices,
        $refreshDevices;

    var genconn,
        generatorConnected,
        generatorLaunched = false,
        hasConnected = false,
        sameDeviceList = false,
        requestedCheckForDevices = false,
        isCheckingForDevices = false,
        prevDevices;

    var Affordance = {
        BUSY: "busy",
        READY_TO_PAIR: "ready-to-pair",
        NOT_LOGGED_IN: "not-logged-in",
        OFFLINE: "no-internet",
        NO_DEVICES_FOUND: "no-devices"
    };

    var ConnectionStatus  = IPCMessage.connectionStatus,
        cepEvents         = IPCMessage.cepEvents;

    function distributePanes() {
        var $title = $("#header-container"),
            $device = $("#device-container");

        if ($title.is(":visible") && $device.is(":visible")) {
            var contentHeight = $content.height(),
                titleHeight = $title.height(),
                footerHeight = $footer.height();

            if ($footer.is(":visible")) {
                $device.css({height: (contentHeight - titleHeight - footerHeight) - 13});
            } else {
                $device.css({height: (contentHeight - titleHeight)});
            }
        }
    }

    function handleResize() {
        distributePanes();
    }

    function anyDeviceHasError(devices) {
        var i;
        for (i = 0; i < devices.length; i++) {
            if (devices[i].hasOwnProperty("error")) {
                return true;
            }
        }
        return false;
    }

    function updateDeviceList(devices) {
        if ($getTheApp === undefined) {
            return;
        }

        if ($devices) {
            $devices.remove();
        }

        if (devices.length > 0 && devices[0]) {
            // if the same device list as the last time
            $getTheApp.addClass("hidden");
            $getTheApp.remove();
            TemplateManager.renderTemplate("devices", {devices: devices}).then(
                function($template) {
                    $devices = $template;
                    $content.html($devices);
                    $refreshDevices = $("#refresh-devices");
                });
            
            // if the user has requested that we check for new devices, see if any new devices
            //   were added to the list.  If so, we'll show a message saying that there are.
            sameDeviceList = requestedCheckForDevices && _.isEqual(devices, prevDevices);
            prevDevices = _.clone(devices);  //remember last list of devices
            setTimeout(function() {
                if (sameDeviceList) {
                    // same list.  display the "no new devices" message.
                    $("#device-container").hide();
                    $("#footer-container").hide();
                    $("#no-new-devices").show();
                }
                    
                $checkForDevices.prop("disabled", false);
                $refreshDevices.removeClass("spinning").addClass("tips");
                isCheckingForDevices = false;
            }, 1000);   // delay update to debounce any in-progress connections with new devices

            setTimeout(function() {
                $("#no-new-devices").hide();
                $footer = $("#footer-container");
                if (anyDeviceHasError(devices)) {
                    $footer.show();
                } else {
                    $footer.hide();
                }
                
                distributePanes();
            }, 15);
        } else {
            $getTheApp.removeClass("hidden");
            $content.html($getTheApp);
            
            // display a different billboard depending on whether the user had requested the check for devices
            var statusClass = requestedCheckForDevices ? Affordance.NO_DEVICES_FOUND : Affordance.READY_TO_PAIR;
            setTimeout(function() {
                // if we're online and signed in, then display the ready to pair or no devices found panel.
                //   Otherwise, if we're offline or signed out, then leave the current offline or signed out panel.
                if (!$content.hasClass(Affordance.OFFLINE) && !$content.hasClass(Affordance.NOT_LOGGED_IN)) {
                    if (!$getTheApp.hasClass("hidden") && !$content.hasClass(statusClass)) {
                        $content.removeClass().addClass(statusClass);
                    }

                    $checkForDevices.prop("disabled", false);
                    if ($refreshDevices) {
                        $refreshDevices.prop("disabled", false);
                    }
                    isCheckingForDevices = false;
                }
            }, 1500);   // delay update to debounce any in-progress connections with new devices
        }
        
        requestedCheckForDevices = false;
    }

 /*
    function addBogusDevices() {
        updateDeviceList([
            {name: "device with problem", error: "foo"},
            {name: "device with good connection", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "another device with problem", error: "foo"},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "boafdsafasfsdafsadfsadfsadfasdfasdfasdfasdfasdfasdfasdfasdfsdagus", resolution: {height: 6500, width: 1700}},
            {name: "third device with problem", error: "foo"}
        ]);
    }
*/

    // handle IPC messages from the generator
    function _handleGeneratorMessage(message) {
        switch(message.payload.messageType) {
            case IPCMessage.types.PANELOPENEDACK:
                // generator acknowledged our panel opened message.  Ask for the device list.
                genconn.sendMessage({
                    messageType: IPCMessage.types.REQUESTDEVICELIST
                });
                break;
            case IPCMessage.types.DEVICELIST:
                // generator sent the full list of connected devices
                updateDeviceList(message.payload.deviceList);
                break;
            case IPCMessage.types.DEVICECONNECTED:
                // remember if we've connected to the Preview app on a device at least once
                if (!hasConnected) {
                    hasConnected = true;
                }
                break;
            default:
                // unknown message type
                console.log("com.adobe.preview/PSPanel: received unknown Generator message type: " + JSON.stringify(message.payload.messageType));
        }
    }
    
    function disableRunningGenerator() {
        JSXRunner.runJSX("isGeneratorRunning", null, function (isRunning) {
            if (isRunning === "true") {
                JSXRunner.runJSX("disableGenerator");
                generatorLaunched = false;
            }
        });
    }

    function setPanelStatusAffordance(statusClass) {
        if (!$content.hasClass(statusClass)) {
            if ($getTheApp && $getTheApp.length > 0 && $getTheApp.hasClass("hidden")) {
                updateDeviceList([]);

                if (generatorConnected) {
                    // make sure we get an updated device list
                    genconn.sendMessage({
                        messageType: IPCMessage.types.REQUESTDEVICELIST
                    });
                }
            } else {
                var disableButton = (statusClass === Affordance.NOT_LOGGED_IN) || (statusClass === Affordance.OFFLINE);
                if ($checkForDevices) {
                    $checkForDevices.prop("disabled", disableButton);
                }
                if ($refreshDevices) {
                    $refreshDevices.prop("disabled", disableButton);
                }
            }

            $content.removeClass().addClass(statusClass);
        }
    }
    
    PreviewGlobal.window.onUserNoticeOK = function() {
        updateDeviceList(prevDevices);
    };

    PreviewGlobal.window.openGetAppURL = function(url) {
        PreviewGlobal.csInterface.openURLInDefaultBrowser(url);

        // notify generator that the user clicked the get app link in the panel
        if (generatorConnected) {
            genconn.sendMessage({
                messageType: IPCMessage.types.GETAPPLINKCLICK
            });
        }
    };
    
    PreviewGlobal.window.openLearnMoreURL = function(url) {
        PreviewGlobal.csInterface.openURLInDefaultBrowser(url);

        // notify generator that the user clicked the learn more link in the panel
        if (generatorConnected) {
            genconn.sendMessage({
                messageType: IPCMessage.types.LEARNMORELINKCLICK
            });
        }
    };
    
    PreviewGlobal.window.checkForDevices = function() {
        if (generatorConnected && !isCheckingForDevices) {
            // remember that the user clicked the button to request a check for devices
            requestedCheckForDevices = true;
            isCheckingForDevices = true;
            
            if (!$getTheApp.hasClass("hidden")) {
                setPanelStatusAffordance(Affordance.BUSY);
            }
            
            // while displaying the billboard, disable the button while checking.
            $checkForDevices.prop("disabled",  true);
            $refreshDevices = $("#refresh-devices");
            $refreshDevices.addClass("spinning").removeClass("tips");
            
            console.log("com.adobe.preview/PSPanel: requesting check for new devices");
            
            genconn.sendMessage({
                messageType: IPCMessage.types.REQUESTCHECKFORDEVICES
            });
        }
    };

    PreviewGlobal.window.toggleVersionString = function () {
        $versionString.toggle();
    };

    /**
     * Sets preferences to disable generator on next PS launch *AND* to disable Preview from auto-starting
     *   generator whenever the Preview panel is opened.
     *
     * DEBUGGING TIP:
     *   This function is useful when running generator external from Photoshop -- eg. running locally within
     *   node.  To invoke, open Chrome Dev Tools on PSPanel (http://localhost:8198/), and enter the
     *   following command into the console:
     *      window.disableGeneratorAutoStart()
     *   Upon receiving the message, preferences will be set so that, on the next launch of PS, the internal
     *   generator will not be started *AND* Preview will not attempt auto-start it either.
     *  
     */
    PreviewGlobal.window.disableGeneratorAutoStart = function() {
        PreviewGlobal.window.localStorage.setItem("DEV-do-not-auto-start-generator", "internal-generator-off");
        
        disableRunningGenerator();
        
        return "DEV-MODE - auto-start generator disabled";
    };

    // ensure that Generator is running
    function ensureGeneratorRunning() {
        //comment the following line out once and run... then forever you can enjoy not having it auto-start generator
        //window.localStorage.setItem("DEV-do-not-auto-start-generator", "internal-generator-off");

        if (PreviewGlobal.window.localStorage.getItem("DEV-do-not-auto-start-generator") !== "internal-generator-off") {
            // enable Generator if it isn't already running
            JSXRunner.runJSX("isGeneratorRunning", null, function (isRunning) {
                if (isRunning !== "true") {
                    JSXRunner.runJSX("ensureGenerator");
                    generatorLaunched = true;
                }
            });
        } else {
            PreviewGlobal.window.console.warn("RUNNING IN DEV-MODE - NOT AUTO-STARTING GENERATOR. To reset, run this in the panel dev tools console:");
            PreviewGlobal.window.console.log("window.localStorage.removeItem(\"DEV-do-not-auto-start-generator\");");
        }
    }

    // initialize the connection to the generator-preview plugin
    function _connectToGenerator() {
        // connect to Generator
        genconn = GeneratorConnection.connectToGenerator();

        // event handler to receive messages from the generator
        genconn.on("message", _handleGeneratorMessage);

        // try to reopen the connection if it closes
        genconn.on("close", function () {
            setTimeout(genconn.establishConnection.bind(genconn), GeneratorConnection.CONNECTION_RETRY_DELAY);
        });

        var firstConnectionAfterOpen = true;

        genconn.on("started", function () {
            // initialize the connection w/ the generator
            genconn.sendMessage({
                messageType: IPCMessage.types.REGISTERCEP,
                extension: IPCMessage.clients.CEPID_PSPANEL
            });

            // We only want to record a panel open event on the first run. After that, if a new generator
            // connection is established (because generator went away and came back), we want to
            // get an updated device list.
            if (firstConnectionAfterOpen) {
                genconn.sendMessage({
                    messageType: IPCMessage.types.PANELOPENED
                });
                firstConnectionAfterOpen = false;
            } else {
                genconn.sendMessage({
                    messageType: IPCMessage.types.REQUESTDEVICELIST
                });
            }

            generatorConnected = true;
        });
    }

    function setConnectionStatus(status) {
        switch(status) {
        case ConnectionStatus.READY_TO_PAIR:
            setPanelStatusAffordance(Affordance.READY_TO_PAIR);
            break;
        case ConnectionStatus.INITIALIZING:
        case ConnectionStatus.ONLINE:
        case ConnectionStatus.LOGGING_IN:
            setPanelStatusAffordance(Affordance.BUSY);
            break;
        case ConnectionStatus.NOT_LOGGED_IN:
            setPanelStatusAffordance(Affordance.NOT_LOGGED_IN);
            break;
        case ConnectionStatus.OFFLINE:
        case ConnectionStatus.ERROR:
            setPanelStatusAffordance(Affordance.OFFLINE);
            break;
        default:
            console.log("com.adobe.preview/PSPanel: unknown status " + status);
            // just assume we're ready to pair in this case...
            setPanelStatusAffordance(Affordance.READY_TO_PAIR);
        }
    }

    function init() {
        PreviewGlobal.themeManager.init();

        TemplateManager.renderTemplate("getapp").then(function($template) {
            $getTheApp = $template;
            $content.html($getTheApp);

            ensureGeneratorRunning();

            // wait to start the generator connection until after the template renders
            setConnectionStatus(ConnectionStatus.INITIALIZING);
            setTimeout(_connectToGenerator(), 10);

            var event = new PreviewGlobal.window.CSEvent(cepEvents.PANEL_OPENED, "APPLICATION");
            PreviewGlobal.csInterface.dispatchEvent(event);
            
            $versionString = $("#version-string");
            $versionString.text(pkgjson.version);
            
            $checkForDevices = $("#check-for-devices");
            
            // while displaying the billboard, disable the button while checking.
            $checkForDevices.prop("disabled",  true);
        });

        PreviewGlobal.csInterface.addEventListener(IPCMessage.cepEvents.CONNECTION_STATUS, function (e) {
            setConnectionStatus(e.data.newStatus);
        });

        // note: this callback is never called.  Waiting for bug fix: https://watsonexp.corp.adobe.com/#bug=3754552
        PreviewGlobal.window.cep.util.registerExtensionUnloadCallback(function() {
            genconn.sendMessage({
                messageType: IPCMessage.types.PANELCLOSED
            });
            
            // if we launched Generator but it was never used before closing the panel, then disable it
            if (generatorLaunched && !hasConnected) {
                disableRunningGenerator();
            }
        });

        $(PreviewGlobal.window).resize(handleResize);

        $(PreviewGlobal.window.document).on("contextmenu", function() {
            return false;
        });

        //setTimeout(addBogusDevices, 1000);
    }

    init();

}());
