# Source: lib/periodicClass.js

    'use strict';
    // const periodicSchema = require('./schema');
    // const periodicModel = require('./model');
    // const periodicConnect = require('./connect');
    const Promisie = require('promisie');
    const express = require('express');
    const events = require('events');
    const cache = require('memory-cache');
    const CoreData = require('periodicjs.core.data');
    const CoreFiles = require('periodicjs.core.files');
    const CoreUtilities = require('periodicjs.core.utilities');
    // const CoreController = require('periodicjs.core.controller');
    const periodicInit = require('./init');
    const periodicExtension = require('./extension');
    const periodicCrud = require('./crud');
    const periodicUtils = require('./utilities');
    const periodicProxyHandler = require('./periodicProxyHandler');
    /**
     * periodic singleton class
     *
     * @class Periodic
     */
    class Periodic {
      /**
       * Creates an instance of periodic.
       * @param {any} [options={}]
       * @param {boolean} options.debug use debugging logs
       *  @param {String} options.app_root the path to the application's root directory
       * @return {object} proxied periodic singleton object
       *
       * @memberOf Periodic
       */
      constructor(options = {}) {
        //https://www.npmjs.com/package/express-react-engine
        this.config = Object.assign({
          debug: false,
          setMaxListeners: 0,
          app_root: process.cwd(),
          configuration: {},
          // settings: {},
        }, options);
        events.EventEmitter.defaultMaxListeners = this.config.setMaxListeners;
        this.__class = {
          init:periodicInit,
          extension:periodicExtension,
          crud:periodicCrud,
          utils:periodicUtils,
          proxyHandler:periodicProxyHandler,
        };
        this.settings = {};
        this.utilities = periodicUtils;
        this.cache = cache;
        this.express = express;
        this.workers;
        this.numWorkers;
        this.cluster;
        this.app = express();
        // this.connections = new Map();
        this.status = new events.EventEmitter();
        this.transforms = {
          pre: {
            CONNECT: {},
            DELETE: {},
            GET: {},
            HEAD: {},
            OPTIONS: {},
            POST: {},
            PUT: {},
          },
          post: {
            CONNECT: {},
            DELETE: {},
            GET: {},
            HEAD: {},
            OPTIONS: {},
            POST: {},
            PUT: {},
          },
        };
        this.controllers = {
          core: new Map(),
          extension: new Map(),
          container: new Map(),
          preTransforms: periodicUtils.middleware.preTransforms(this),
          postTransforms: periodicUtils.middleware.postTransforms(this),
        };
        this.resources = {
          standard_models: [],
          databases: {
            extensions: {},
            container: {},
          },
          commands: {
            extensions: new Map(),
            container: new Map(),
          },
        };
        this.locals = {
          core: new Map(),
          extensions: new Map(),
          container: new Map(),
        };
        this.routers = new Map();
        this.containers = new Map();
        this.extensions = new Map();
        this.servers = new Map();
        this.datas = new Map();
        this.dbs = new Map();
        this.models = new Map();
        this.tasks = {
          resetExtensions: periodicInit.config.loadExtensions.bind(this),
          installExtension: periodicExtension.install.installExtension.bind(this),
          uninstallExtension: periodicExtension.uninstall.uninstallExtension.bind(this),
        };

        this.crud = {
          config: {
            create: periodicCrud.config.create.bind(this),
            update: periodicCrud.config.update.bind(this),
            remove: periodicCrud.config.remove.bind(this),
            init: periodicCrud.config.init.bind(this),
            get: periodicUtils.mock.tempPromise,
            list: periodicUtils.mock.tempPromise,
          },
          ext: {
            create: periodicCrud.ext.create.bind(this),
            update: periodicUtils.mock.tempPromise,
            remove: periodicCrud.ext.remove.bind(this),
            get: periodicUtils.mock.tempPromise,
            list: periodicCrud.ext.list.bind(this),
            init: periodicCrud.ext.init.bind(this, false),
          },
          con: {
            create: periodicUtils.mock.tempPromise,
            update: periodicUtils.mock.tempPromise,
            remove: periodicUtils.mock.tempPromise,
            get: periodicUtils.mock.tempPromise,
            list: periodicUtils.mock.tempPromise,
            init: periodicCrud.ext.init.bind(this, 'container'),
          },
        };
        this.logger = console;
        this.logger.silly = console.log;
        this.logger.debug = console.log;
        this.logger.verbose = console.info;
        this.logger.info = console.info;
        this.logger.warn = console.info;
        this.logger.error = console.error;
        // this.db = undefined;
        // this.app = {}; //express app
        this.core = {
          data: CoreData,
          utilities: new CoreUtilities(this),
          mailer: {},
          files: CoreFiles,
          // controller:
        };
        // console.log('this.core.controller',this.core.controller);

        // this.controller = peroidicController.bind(this);
        // this.container = peroidicContainer.bind(this);
        // this.extension = peroidicExtension.bind(this);
        return new Proxy(this, periodicProxyHandler.call(this));
      }
      /**
         * initialize a periodic application, by creating folder structure, using a CLI application, cluster & fork the main thread, start the web server, use a socket server
         * @param {Boolean} options.debug log debug output
         * @param {String} options.app_root the path to the application's root directory
         * @param {Object} options.settings set initial settings before configurations are loaded
         *
         * @returns {Promise} fully resolved periodic instance
         * @memberOf periodic
         */
      init(options = {}) {
        process.setMaxListeners(this.config.setMaxListeners || 0);
        this.status.emit('initializing', true);
        this.config = Object.assign({}, this.config, options);

        return new Promise((resolve, reject) => {
          const completInit = periodicInit.runtime.completeInitialization.bind(this, resolve, reject);
          Promisie.series([
            periodicInit.timer.startTimer.bind(this),
            periodicInit.setUpFolderStructure.bind(this),
            periodicInit.config.loadConfiguration.bind(this),
            periodicInit.runtime.configRuntimeEnvironment.bind(this),
            periodicInit.config.loadAppSettings.bind(this),
            periodicInit.logger.configureLogger.bind(this),
            periodicInit.config.loadExtensions.bind(this),
            periodicInit.config.setupGenericCoreMailer.bind(this),
            periodicInit.config.setupGenericCoreController.bind(this),
            periodicExtension.setup.setupExtensions.bind(this),
            periodicExtension.setup.setupContainer.bind(this),
            periodicInit.config.loadDatabases.bind(this),
            periodicInit.config.loadExternalRouters.bind(this),
            periodicInit.logger.catchProcessErrors.bind(this),
            periodicInit.express.initializeExpress.bind(this),
            periodicInit.cli.run.bind(this),
            periodicInit.cluster.forkProcess.bind(this),
            periodicInit.server.initializeServers.bind(this),
            periodicInit.timer.endTimer.bind(this),
          ]).then(resolve)
            .catch(completInit);
        });
      }
    }

    module.exports = Periodic;