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

/*global window*/

"use strict";

var net                 = require("net"),
    util                = require("util"),
    EventEmitter        = require("events").EventEmitter,
    SessionManager      = require("preview-common/SessionManager"),
    IPCPipe             = require("preview-common/IPCPipe"),
    IPCMessage          = require("preview-common/IPCMessage"),
    CommonConfiguration = require("preview-common/CommonConfiguration");


var CONNECTION_RETRY_DELAY  = 3000,
    CONNECTION_RETRY_NOTIFY = 10,       // # of times to retry before logging no generator connection
    CONNECTION_NOTIFY_LIMIT = 3,        // max # of notifications logged
    notifyGenConnRetries    = 0,
    genconn;

/**
 * Handles a connection from this CEP panel to our Generator plugin.
 */
function GeneratorConnection() {
    this._session = null;
    this._startSession = this._startSession.bind(this);
    this._handleMessage = this._handleMessage.bind(this);
    this._handleClose = this._handleClose.bind(this);
}

util.inherits(GeneratorConnection, EventEmitter);

/**
 * Establish a connection. If it cannot be established, keep retrying
 * periodically.
 */
GeneratorConnection.prototype.establishConnection = function () {
    this._session = null;
    var self = this,
        connectToken = {
            host: "127.0.0.1",
            port: IPCPipe.enabled ? IPCPipe.getPath() : CommonConfiguration.port
        },
        timer;

    var conn = net.createConnection(connectToken, function () {
        clearTimeout(timer);
        notifyGenConnRetries = 0;
        self._startSession(conn);
    });

    timer = setTimeout(function () {
        self.establishConnection();
        
        // if we continue to be unable to connect to the Preview generator plugin, then
        //   log an error to the console.
        ++notifyGenConnRetries;
        if ((notifyGenConnRetries <= (CONNECTION_RETRY_NOTIFY * CONNECTION_NOTIFY_LIMIT))
            && ((notifyGenConnRetries % CONNECTION_RETRY_NOTIFY) === 0)) {
            console.log("[com.adobe.preview/PSLoader] unable to connect to 'preview.generate' plug-in after "
                        + (notifyGenConnRetries * CONNECTION_RETRY_DELAY / 1000) + " seconds.");
        }
    }, CONNECTION_RETRY_DELAY);
};

/**
 * Once we have a socket connection, start up a preview protocol session.
 */
GeneratorConnection.prototype._startSession = function (socket) {
    this._session = new SessionManager.Session(socket, "GENERATOR");
    this._session.on("message", this._handleMessage);
    this._session.on("close", this._handleClose);
    this.emit("started");
};

/**
 * Handles messages from the Generator, passing the payload to
 * listeners for the "message" event.
 */
GeneratorConnection.prototype._handleMessage = function (message) {
    this.emit("message", message);
};

/**
 * Send a message to Generator.
 */
GeneratorConnection.prototype.sendMessage = function (payload) {
    if (this._session) {
        this._session.sendMessage({
            recipient: {
                deviceId: "GENERATOR"
            },
            payload: payload
        });
    }
};

/**
 * Send a message to Generator requesting that all active USB connections be immediately disconnected.
 *
 * DEBUGGING TIP:
 *   This function is useful for debugging wifi connections to the Preview app.  To invoke for a given
 *   Preview session, open Chrome Dev Tools on either PSPanel (http://localhost:8198/) or
 *   PSLoader (http://localhost:8199/) and enter the following command into the console:
 *      window.disconnectUSB()
 *   Upon receiving the message, generator will immediately disconnect any currently open USB connections.
 *  
 */
window.disconnectUSB = function () {
    genconn.sendMessage({
        messageType: IPCMessage.types.DISCONNECT_USB
    });
};

/**
 * If the session closes, emit a close event.
 */
GeneratorConnection.prototype._handleClose = function () {
    this._session = null;
    this.emit("close");
};

Object.defineProperty(GeneratorConnection.prototype, "connected", {
    get: function () {
        return this._session !== null;
    }
});

/**
 * Establishes a connection to our Generator plugin.
 *
 * @return {GeneratorConnection} The connection object to talk to generator.
 */
function connectToGenerator() {
    if (genconn) {
        return genconn;
    }
    genconn = new GeneratorConnection();
    genconn.establishConnection();
    return genconn;
}

exports.connectToGenerator = connectToGenerator;
exports.CONNECTION_RETRY_DELAY = CONNECTION_RETRY_DELAY;
