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

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

    /**
     * @class vtkWeb.Session
     * vtkWeb Session object on which RPC method calls can be made.
     *
     *     session.call("vtk:render", request).then( function (reply) {
     *        // Do something with the reply
     *     });
     */
    /**
     * @member vtkWeb.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 {vtkWeb.Future} of the RPC call
     */
    /**
     * @class vtkWeb.Future
     * Object on which can be attached a callback.
     */
    /**
     * @member vtkWeb.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 running vtkWeb session
     *
     * @member vtkWeb.connect
     *
     * @param {vtkWeb.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: {vtkWeb.Session}
     *      }
     *
     *
     * @param {Function} readyCallback
     * Callback function called when a connection that has been extended with
     * a valid {@link vtkWeb.Session}.
     *
     * @param {Function} closeCallback
     * Callback function called when the session end.
     *
     *      vtkWeb.connect(
     *          connection,
     *          function(connection) {
     *             // Now that we have a valid session let's add a viewport to
     *             // see the 3D view of our vtkWeb pipeline.
     *             var viewport = vtkWeb.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 = "vtkweb-secret"; // Default value
        }

        GLOBAL.ab.connect(wsuri, function (session) {
            try {
                session.authreq("vtkweb").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("vtk", "http://vtk.org/vtk#");
                        session.prefix("event", "http://vtk.org/event#");
                        connection.session = session;
                        connections[connection.sessionURL] = connection;
                        if (onReady) {
                            onReady(connection);
                        }
                    }, function(error) {
                        alert("Authentication error: " + error);
                        GLOBAL.close();
                    }).otherwise(function(error){
                        alert(error);
                        GLOBAL.close();
                    });
                });
            } catch(e) {
                console.log(e);
            }
        }, function (code, reason) {
            delete connections[connection.sessionURL];
            if (onClose) {
                onClose(code, reason);
            }
        },{
            'maxRetries': 0,
            'retryDelay': 2000
        });
    }

    /**
     * Return any existing session for a given connection or Wamp URL
     *
     * @member vtkWeb.connect
     *
     * @param {String} sessionURL
     * The sessionURL String.
     *
     * @return {vtkWeb.Connection} that contains a {@link vtkWeb.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 vtkWeb.Connection}
     *
     * @member vtkWeb.connect
     */
    function getConnections() {
        return connections;
    }


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

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

    // ----------------------------------------------------------------------
    // Local module registration
    // ----------------------------------------------------------------------
    try {
      // Tests for presence of autobahn, then registers this module
      if (GLOBAL.ab !== undefined) {
        module.registerModule('vtkweb-connect');
      } else {
        console.error('Module failed to register, autobahn is missing');
      }
    } catch(err) {
      console.error('Caught exception while registering module: ' + err.message);
    }

}(window, jQuery));
