/*
 * Copyright 2012 Sakai Foundation (SF) Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 * 
 *     http://www.osedu.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
var express = require('express');
var fs = require('fs');

var Cassandra = require('oae-util/lib/cassandra');
var Context = require('oae-context').Context;
var PrincipalAPI = require('oae-principals');
var Pubsub = require('./pubsub');
var TenantAPI = require('oae-tenants');
var Tenant = require('oae-tenants/lib/model').Tenant;
var fs = require('fs');

var IO = require('./io');
var configAPI = require('oae-config-aggregator');
var PubSub = require('./pubsub');


///////////////////////////
// Setting up the server //
///////////////////////////

/**
 * Start OAE and run the global administrative interface on port 2000 by default, as well as execute the application lifecycle of all the
 * OAE modules in the system. This involves setting up the data schema, starting up tenants in the application, and invoking auxilliary
 * initialization procedures in the proper order.
 *
 * When initializing the container, each OAE module that has a lib/init.js file will be required and the export object will be executed
 * directly. The module will have access to the app object with which to bootstrap. The app object is a JSON object that provides:
 *
 * {
 *      config: { ... },        // The static system configuration information, as provided in ./config.js of the application root directory
 *      server: {ExpressServer} // The running express server object that drives the global administration interface
 * }
 * 
 * @param  {Object}     config      Configuration object contain Cassandra config information
 * @param  {Function}   callback    Standard callback function execute when Sakai OAE has finished starting up
 */
module.exports.init = function(config, callback) {
    callback = callback || function() {};
    var server = express();
    server.use(express.bodyParser());
    server.listen(2000);

    // set up the app object for bootstrap
    var app = {
        config: config,
        server: server
    };

    _bootstrap(app, callback);

    console.log('Starting Sakai OAE');
};

/**
 * Bootstrap the application container. This involves initializing all the OAE modules that are present.
 *
 * @param {Object}          app             The application object that contains all information required to initialize.
 * @param {Function(err)}   callback        The function invoked when bootstrap is complete.
 * @param {Object}          callback.err    An error that occurred, if any.
 */
var _bootstrap = function(app, callback) {
    getAvailableModules(function(modules) {
        if (modules.length) {
            console.log('Starting modules: %s', modules.join(', '));
            // this array will be used as a stack, reverse the order
            modules.reverse();
            _bootstrapModules(modules, app, callback);
        } else {
            callback(new Error('No modules to install, or error aggregating modules.'));
        }
    });
}

/**
 * Bootstrap all the modules given. Order is important, should always bootstrap in the **reverse** order of the array of modules provided.
 *
 * @param {Array<String>}   modules         An array of modules that should be bootstrapped. These need to be located in the ./node_modules directory
 * @param {Object}          app             The application object that contains all the information required to initialize
 * @param {Function(err)}   callback        The function invoked when bootstrap is complete.
 * @Param {Object}          callback.err    An error that occurred, if any
 */
var _bootstrapModules = function(modules, app, callback) {
    if (modules.length === 0) {
        return callback();
    }

    var module = modules.pop();
    var path = "node_modules/" + module + "/lib/init.js";
    var initErr = false;
    IO.pathExists(path, function(exists) {
        if (exists) {
            // initialize the module
            require(module + '/lib/init')(app, function(err) {
                if (err) {
                    return callback(err);
                }
                return _bootstrapModules(modules, app, callback);
            });
        } else {
            return _bootstrapModules(modules, app, callback);
        }
    });
}


/////////////
// Modules //
/////////////

var getAvailableModules = module.exports.getAvailableModules = function(callback) {
    IO.getFileListForFolder("node_modules", function(modules) {
        var finalModules = [];
        var modulePriority = {};

        // aggregate the oae- modules
        modules.forEach(function(module) {
            if (module.substring(0, 4) === 'oae-') {
                // determine module priority
                var filename = "./node_modules/" + module + "/package.json";
                var pkg = JSON.parse(fs.readFileSync(filename, 'utf-8'));
                if (pkg.oae && pkg.oae.priority) {
                    // found a priority in package.json at oae.priority
                    modulePriority[module] = pkg.oae.priority;
                } else {
                    // no priority found, it goes in last
                    modulePriority[module] = Number.MAX_VALUE;
                }

                finalModules.push(module);
            }
        });

        // order by the startup priority
        finalModules.sort(function(a, b) {
            return modulePriority[a] - modulePriority[b];
        });

        callback(finalModules);
    });
};


@@ -5224,28 +5224,8 @@
 me =
- %22./node_modules/%22 +
  mod
@@ -5277,53 +5277,24 @@
 g = 
-JSON.parse(fs.readFileSync(filename, 'utf-8')
+require(filename
 );%0A 

use require to read in json instead of readFileSync