/*
 * 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.
 */

"use strict";

var _                   = require("lodash"),
    MessageDispatcher   = require("./MessageDispatcher"),
    Model               = require("./Model"),
    ImageGenerator      = require("./ImageGenerator"),
    logger              = require("../logger");

var DOCUMENT_CHANGED_DEBOUNCE_INTERVAL  = 500;     // document changed, debounce interval

var _generator,
    _docChangedTimeout,
    _watchingDocument = false;

function getDocumentInfo(document) {
    if (document) {
        var comps = document.comps || [];
        comps = comps.map(function (comp) {
            return {
                id: comp.id,
                name: comp.name,
                applied: comp.applied
            };
        });

        var activeComp = _.find(comps, function (comp) {
                            return !!comp.applied;
                        });
        return {
            id: document.id,
            name: document.file,
            canvas: {
                width: document.bounds.right - document.bounds.left,
                height: document.bounds.bottom - document.bounds.top,
                resolution: document.resolution,
                top: document.bounds.top,
                left: document.bounds.left
            },
            layerComps: comps,
            activeLayerComp: activeComp,
            artboards: ImageGenerator.getArtboardsForConnectMessage(document)
        };
    }
    return undefined;
}

function handleLastDocumentClosed() {
    var message = MessageDispatcher.createMessage({
        messageType: "activeDocumentChange",
        activeDocument: undefined
    });
    MessageDispatcher.sendMessageToAllDevices(message);
}

function updateCurrentContext(document) {
    Model.docInfo.raw = document;
    Model.docInfo.current = getDocumentInfo(document);
}

function getDocumentInfoErrorHandler(err) {
    updateCurrentContext();

    if (err === "Error: No image open") {
        handleLastDocumentClosed();
    } else {
        logger.logMessage("handleDocumentChanged error occurred: " + err, logger.LOGLEVEL_ERROR);
    }
}

function handleDocumentChanged() {
    // debounce our response to document changed messages
    if (_docChangedTimeout) {
        clearTimeout(_docChangedTimeout);
    }
    _docChangedTimeout = setTimeout(function() {
        _generator.getDocumentInfo(undefined, {
            getTextStyles: false
        }).then(updateCurrentContext, getDocumentInfoErrorHandler);
        _docChangedTimeout = undefined;
    }, DOCUMENT_CHANGED_DEBOUNCE_INTERVAL);
}

function handleActiveDocumentChange() {
    var message = MessageDispatcher.createMessage({
        messageType: "activeDocumentChange",
        activeDocument: Model.docInfo.current
    });
    MessageDispatcher.sendMessageToAllDevices(message);
}

function handleDocInfoChange() {
    var message = MessageDispatcher.createMessage({
        messageType: "documentChange",
        activeDocument: Model.docInfo.current
    });
    MessageDispatcher.sendMessageToAllDevices(message);
}

function handleDocumentClosed(documentId) {
    var message = MessageDispatcher.createMessage({
        messageType: "documentClose",
        documentId: documentId
    });
    MessageDispatcher.sendMessageToAllDevices(message);
    
    handleDocumentChanged();
}

function startDocumentWatch() {
    // if not already watching the document, start doing so
    if (!_watchingDocument) {
        logger.logMessage("First device connected: start document watch");
        _watchingDocument = true;
        
        _generator.onPhotoshopEvent("currentDocumentChanged", handleDocumentChanged);
        _generator.onPhotoshopEvent("imageChanged", handleDocumentChanged);
        _generator.onPhotoshopEvent("closedDocument", handleDocumentClosed);

        // initialize current document
        handleDocumentChanged();
    }
}

function stopDocumentWatch() {
    if (_watchingDocument) {
        logger.logMessage("Last device disconnected: stop document watch");
        _watchingDocument = false;
        
        _generator.removePhotoshopEventListener("currentDocumentChanged", handleDocumentChanged);
        _generator.removePhotoshopEventListener("imageChanged", handleDocumentChanged);
        _generator.removePhotoshopEventListener("closedDocument", handleDocumentClosed);
    }
}

// Handle a device state change event
function handleDeviceStateChange(device, oldState, newState) {
    // try to minimize the times we're watching the current document.  Only do so when
    //   we're actually connected to a Preview device
    if (newState === Model.DEVICE_STATE.CONNECTED) {
        // if connecting the first device
        startDocumentWatch();
    } else if (oldState === Model.DEVICE_STATE.CONNECTED) {
        // if closing the Preview app on last device
        if (_.size(Model.devices.devices) <= 1) {
            stopDocumentWatch();
        }
    }
}

function handleDeviceRemoved() {
    // if lost connection to last device
    if (_.size(Model.devices.devices) <= 0) {
        stopDocumentWatch();
    }
}

function init(generator) {
    _generator = generator;
    _watchingDocument = false;  // explicitly reset for unit tests

    Model.docInfo.on(Model.EVENT.DOCINFO_CHANGED, handleDocInfoChange);
    Model.docInfo.on(Model.EVENT.DOCUMENT_CHANGED, handleActiveDocumentChange);
    Model.devices.on(Model.DEVICE_EVENT.STATE_CHANGED, handleDeviceStateChange);
    Model.devices.on(Model.EVENT.DEVICE_REMOVED, handleDeviceRemoved);
}

// for unit testing
exports._DOCUMENT_CHANGED_DEBOUNCE_INTERVAL = DOCUMENT_CHANGED_DEBOUNCE_INTERVAL;
exports._startDocumentWatch = startDocumentWatch;
exports._stopDocumentWatch = stopDocumentWatch;

exports.init = init;
