/**
 * ParaViewWeb JavaScript Library.
 *
 * This module allow the Web client to connect to a remote ParaViewWeb session.
 * The session must already exist and waiting for connections.
 *
 * @class paraview.connect
 *
 * {@img paraview/ParaViewWeb-simple.png
 *  alt Focus on the communication between the client and the ParaView process}
 */
(function (GLOBAL, $) {

    // Connections field used to store a map of the active sessions
    var connections = {}, module = {};

    /**
     * @class pv.Session
     * ParaView Session object on which RPC method calls can be made.
     *
     *     session.call("pv:render", request).then( function (reply) {
     *        // Do something with the reply
     *     });
     */
    /**
     * @member pv.Session
     * @method call
     * Returns a future of the RPC call.
     * @param {String} method
     * Full path method name.
     * @param {Object|String|Number} args
     * Arguments of the RPC call.
     *
     * @return {pv.Future} of the RPC call
     */
    /**
     * @class pv.Future
     * Object on which can be attached a callback.
     */
    /**
     * @member pv.Future
     * @method then
     * @param {Function} callback
     * Function to be called once the RPC called is done. The argument of the
     * function is the response of the RPC method.
     */


    /**
     * Connect to a ParaView running session
     *
     * @member paraview.connect
     *
     * @param {pv.Connection} connection
     * A connection object that should have been generated by the Launcher
     * part if any.
     *
     *      connection = {
     *          sessionURL: "http://localhost:8080/ws"
     *      }
     *
     *      get extended to once the readyCallback get called:
     *
     *      connection = {
     *          sessionURL: "http://localhost:8080/ws",
     *          session: {pv.Session}
     *      }
     *
     *
     * @param {Function} readyCallback
     * Callback function called when a connection that has been extended with
     * a valid {@link pv.Session}.
     *
     * @param {Function} closeCallback
     * Callback function called when the session end.
     *
     *      paraview.connect(
     *          connection,
     *          function(connection) {
     *             // Now that we have a valid session let's add a viewport to
     *             // see the 3D view of our ParaView pipeline.
     *             var viewport = paraview.createViewport(connection.session);
     *             viewport.bind(".viewport-3d");
     *         },
     *         function(code,reason) {
     *             if (code == ab.CONNECTION_UNSUPPORTED) {
     *                  alert("Connection not supported");
     *              } else {
     *                  console.log(reason);
     *              }
     *          }
     *      );
     */
    function connect(connection, readyCallback, closeCallback) {
        var wsuri = connection.sessionURL, onReady = readyCallback, onClose = closeCallback;

        if(!connection.hasOwnProperty("secret")) {
            connection.secret = "paraviewweb-secret"; // Default value
        }

        GLOBAL.ab.connect(wsuri, function (session) {
            try {
                session.authreq("paraviewweb").then(function (challenge) {
                    // derive secret if salted WAMP-CRA
                    var secret = GLOBAL.ab.deriveKey(connection.secret, JSON.parse(challenge).authextra);
                    var signature = session.authsign(challenge, secret);

                    session.auth(signature).then(function(){
                        session.prefix("pv", "http://paraview.org/pv#");
                        session.prefix("event", "http://paraview.org/event#");
                        connection.session = session;
                        connections[connection.sessionURL] = connection;
                        if (onReady) {
                            onReady(connection);
                        }
                    }).otherwise(function(error){
                        alert("Authentication error");
                        GLOBAL.close();
                    });
                });
            } catch(e) {
                console.log(e);
            }
        }, function (code, reason) {
            delete connections[connection.sessionURL];
            if (onClose) {
                onClose(code, reason);
            }
        });
    }

    /**
     * Return any existing session for a given connection or Wamp URL
     *
     * @member paraview.connect
     *
     * @param {String} sessionURL
     * The sessionURL String.
     *
     * @return {pv.Connection} that contains a {@link pv.Session}
     */
    function getConnection(sessionURL) {
        return connections[sessionURL];
    }

    /**
     * Return all the available connections stored in an Object like follow:
     *
     *     {
     *       "ws://localhost:8080/proxy?sessionId=2345": connection
     *     }
     *
     * {@link pv.Connection}
     *
     * @member paraview.connect
     */
    function getConnections() {
        return connections;
    }


    // ----------------------------------------------------------------------
    // Init paraview module if needed
    // ----------------------------------------------------------------------
    if (GLOBAL.hasOwnProperty("paraview")) {
        module = GLOBAL.paraview || {};
    } else {
        GLOBAL.paraview = module;
    }

    // ----------------------------------------------------------------------
    // Export methods to the paraview module
    // ----------------------------------------------------------------------
    module.connect = function (connection, ready, close) {
        connect(connection, ready, close);
    };
    module.getConnection = function (connection) {
        return getConnection(connection);
    };
    module.getConnections = function () {
        return getConnections();
    };
}(window, jQuery));
