/******************************************************************************
* 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");