ARCS logo.js Augmented Reality Component System

Source: application.js

/******************************************************************************
 * Application implementation
 * ***************************************************************************/
/**
 * Creates an application runnable by the ARCS engine.
 * @class
 * @classdesc The application is the master class of the ARCS engine. 
 * It is initialized using a structured object (possibly described in JSON, 
 * see {@link ARCS.Application#import}) 
 * to load all external scripts describing components, instanciate
 * all components and then start the application
 */
ARCS.Application = function () {
    var context = {},
        sheets = {},
        controller = {},
        libraries = [],
        dependencies = [],
        factories = {},
        self = this,
        autoStart = false,
        currentSheet = "",
        loadLibraries,
        preProcess,
        checkFactories;

    factories.StateMachine = ARCS.Statemachine;

    loadLibraries = function () {
        var i;
        // we will use different instances of require either the one of node 
        // or the one from require.js
        ARCS.Application.currentApplication = self;

        // in node.js, we have a synchronous load
        if (ARCS.isInNode()) {  // this means we are using node.js  
            for (i = 0; i < libraries.length; i++) {
                // store namespaces inside factories
                require("./" + libraries[i] + ".js");
            }
        } else {
            // in browser, we have an asynchronous load 
            // all the work is in fact performed in function arcs_module
            require(libraries);
        }
    };
    
    
    this.loadLibrary = function (libName, cbFunction) {
        ARCS.Application.currentApplication = self;
        if (ARCS.isInNode()) 
        { 
            require("./" + libName + ".js"); 
            if (cbFunction !== undefined) {
                cbFunction();
            }
        }
        else 
        { 
            require(libName, function () {
                if (cbFunction !== undefined) {
                    cbFunction();
                }
            }); 
        }
    };
    
    this.getFactoryList = function() {
        return Object.keys(factories);
    };
    
    this.getSheetList = function() {
        return Object.keys(sheets);
    };
    
    this.getFactory = function (fName) {
        return factories[fName];
    };
    
    this.getSheet = function (sName) {
        return sheets[sName];
    };
    
    this.getComponentList = function () {
        return Object.keys(context);
    };
    
    this.getComponent = function (cName) {
        return context[cName];
    };
    
    this.addSheet = function (sName, sheet) {
        sheets[sName] = sheet; 
    };
    
    this.addComponent = function (cName, component) {
        context[cName] = component;
    };

    this.removeSheet = function (sName) {
        delete sheets[sName];
    };
    
    this.removeComponent = function (cName) {
        delete context[cName];
    };
    
    checkFactories = function () {
        var i, cmpList = Object.keys(context);
        for (i = 0; i < cmpList.length; i++) {
            if (factories[context[cmpList[i]].type] === undefined) {
                return;
            }
        }
        autoStart = false;
        console.log("[ARCS] All factories are operational !");
        preProcess();
    };


    preProcess = function () {
        // first, we should instanciate components
        var i, factory, instance, temp, sheetList, cmpList = Object.keys(context);
        for (i = 0; i < cmpList.length; i++) {
            factory = factories[context[cmpList[i]].type];
            //console.log(context[cmpList[i]].type);
            instance = new factory(context[cmpList[i]].value);
            context[cmpList[i]] = instance;
        }

        temp = context[controller];
        controller = temp;
        // then we should work on sheets

        sheetList = Object.keys(sheets);
        for (i = 0; i < sheetList.length; i++) {
            temp = new ARCS.Sheet(context);
            temp.import(sheets[sheetList[i]], context);
            sheets[sheetList[i]] = temp;
        }

        ARCS.Component.connect(controller, "requestSheet", self, "setSheet");
        ARCS.Component.connect(controller, "requestTermination", self, "finish");
        controller.start();
    };
    /**
     * Sets the current sheet of the application. This method is in fact designed
     * as a slot and may be triggered by a statemachine. If a sheet is already the
     * current one, then it is deactivated before activating this new sheet.
     * @param sheetName {string} name of the sheet to set as a current sheet.
     */
    this.setSheet = function (sheetname) {
        if (currentSheet) {
            sheets[currentSheet].deactivate();
        }
        currentSheet = sheetname;
        sheets[currentSheet].activate();
    };
    /**
     * This is the end my friend. This triggers the end of the application
     */
    this.finish = function () {
        if (currentSheet) {
            sheets[currentSheet].deactivate();
        }
    };
    /**
     * Imports a structured object describing the application. The structured object
     * may be described itself in a JSON format.
     * @param object {object} structured object describing an application.
     * 
     *   
     * @example
     * // JSON format of an application description
     * {
     *      context : {
     *              libraries : [ "library1", "library2"],
     *              components : [
     *                      // this could be also properties from context
     *                      name1: { type: "type", string: "string if needed" }
     *              ],
     *              constants : [
     *                      // the same observation applies here
     *                      name1: { representation : {JSON/objectRepresentation ? } }
     *              ]
     *      },
     *      controller : controllerId,
     *      sheets : {
     *              sheetId : {     
     *                      preconnections : [
     *                              { 
     *                                      destination: "id", 
     *                                      slot : "slot name",
     *                                      value : JSON/objectRepresentation ?
     *                              }, {...}, {...}
     *                      ],
     *                      postconnections : [
     *                              { 
     *                                      destination: "id", 
     *                                      slot : "slot name",
     *                                      value : JSON/objectRepresentation ?
     *                              }, {...}, {...}
     *                      ],
     *                      connections : [
     *                              {
     *                                      source: "id",
     *                                      destination: "id",
     *                                      slot: "slot name",
     *                                      signal: "signal name"
     *                              }, {...}, {...}
     *                      ],
     *                      cleanups : [
     *                              { 
     *                                      destination: "id", 
     *                                      slot : "slot name",
     *                                      value : JSON/objectRepresentation ?
     *                              }, {...}, {...}
     *                      ]
     *              },
     *              { ... }
     *      }
     * }
     * 
     */
    this.import = function (object) {
        libraries = object.context.libraries;
        context = object.context.components;
        sheets = object.sheets;
        controller = object.controller;
    };

    /**
     * Registers a factory using a key. If a factory was previously existing using 
     * the same key, then it is overridden.
     * @param key {string} name of the factory
     * @param factory {object} component factory to register.
     */
    this.setFactory = function (key, factory) {
        factories[key] = factory;
        if (autoStart) { checkFactories(); }
    };

    this.setDependency = function (key) {
        dependencies[key] = {};
    };

    /**
     * Starts the application
     */
    this.start = function () {
        autoStart = true;
        loadLibraries();
    };
};

/**
 * Helper function that registers a factory from the global namespace to a given
 * application. This is defined in order to be callable by modules.
 */
ARCS.Application.setFactory = function (app, key, factory) {
    if (ARCS.Component.check(factory)) {
        app.setFactory(key, factory);
    } else {
        console.warn("[ARCS]",key,"is not a factory for an ARCS component.");
    }
};

ARCS.Application.setDependency = function (app, key) {
    app.setDependency(key);
};



ARCS.Component.create(ARCS.Application);
ARCS.Application.slot("setSheet");
ARCS.Application.slot("finish");