// # Event Poller

'use strict';

var fs = require('fs'),
    path = require('path'),
    log = require('./logging'),
    listMessageActions = {},
    listAdminCommands = {},
    listEventModules = {},
    listPoll = {},  //TODO this will change in the future because it could have
                    //several parameterized (user-specific) instances of each event module 
    isRunning = true,
    eId = 0,
    db, ml;

//TODO allow different polling intervals (a wrapper together with settimeout per to be polled could be an easy and solution)


function init() {
  if(process.argv.length > 2) log({ logType: parseInt(process.argv[2]) || 0 });
  var args = { logType: log.getLogType() };
  ml = require('./module_loader')(args);
  db = require('./db_interface')(args);
  initAdminCommands();
  initMessageActions();
  pollLoop();
};


function loadEventModule(el, cb) {
  if(db && ml) db.getEventModule(el, function(err, obj) {
    if(err || !obj) {
      if(typeof cb === 'function') cb(new Error('Retrieving Event Module ' + el + ' from DB: ' + err));
      else log.error('EP', 'Retrieving Event Module ' + el + ' from DB!');
    }
    else {
      // log.print('EP', 'Loading Event Module: ' + el);
      try {
        var m = ml.requireFromString(obj, el);
        db.getEventModuleAuth(el, function(mod) {
          return function(err, objA) {
            //TODO authentication needs to be done differently
            if(objA && mod.loadCredentials) mod.loadCredentials(JSON.parse(objA));
          };
        }(m));
        listEventModules[el] = m;
        if(typeof cb === 'function') cb(null, m);
      } catch(e) {
        if(typeof cb === 'function') cb(e);
        else log.error(e);
      }
    }
  });
}

function fetchPollFunctionFromModule(mod, func) {
  for(var i = 1; i < func.length; i++) {
    if(mod) mod = mod[func[i]];
  }
  if(mod) {
    log.print('EP', 'Found active event module "' + func.join('->') + '", adding it to polling list');
    //FIXME change this to [module][prop] = module; because like this identical properties get overwritten
    // also add some on a per user basis information because this should go into a user context for the users
    // that sat up this rule!
    listPoll[func.join('->')] = mod;
  } else {
    log.print('EP', 'No property "' + func.join('->') + '" found');
  }
}

function initMessageActions() {
  listMessageActions['event'] = function(args) {
    var prop = args[1], arrModule = prop.split('->');
    if(arrModule.length > 1){
      if(listEventModules[arrModule[0]]) {
        fetchPollFunctionFromModule(listEventModules[arrModule[0]], arrModule);
      } else {
        log.print('EP', 'Event Module ' + arrModule[0] + ' needs to be loaded, doing it now...');
        loadEventModule(arrModule[0], function(err, obj) {
          if(err || !obj) log.error('EP', 'Event Module "' + arrModule[0] + '" not found: ' + err);
          else {
            log.print('EP', 'Event Module ' + arrModule[0] + ' found and loaded');
            fetchPollFunctionFromModule(obj, arrModule);
          }
        });
      }
    }
  };
  
  //TODO this goes into module_manager, this will receive notification about
  // new loaded/stored event modules and fetch them from the db
  listMessageActions['cmd'] = function(args) {
    var func = listAdminCommands[args[1]];
    if(typeof(func) === 'function') func(args);
  };
  
  process.on('message', function(strProps) {
    var arrProps = strProps.split('|');
    if(arrProps.length < 2) log.error('EP', 'too few parameter in message!');
    else {
      var func = listMessageActions[arrProps[0]];
      if(func) func(arrProps);
    }
  });
}

function initAdminCommands() {
  listAdminCommands['shutdown'] = function(args) {
    log.print('EP', 'Shutting down DB Link');
    isRunning = false;
    if(db) db.shutDown();
  };
}

function checkRemotes() {
  for(var prop in listPoll) {
    try {
      listPoll[prop](
      /*
       * define and immediately call anonymous function with param prop.
       * This places the value of prop into the context of the callback
       * and thus doesn't change when the for loop keeps iterating over listPoll
       * TODO add this example to the documentation and elaborate
       */
        (function(p) {
          return function(err, obj) {
            if(err) {
              err.additionalInfo = 'module: ' + p;
              log.error('EP', err);
            } else {
              process.send({
                event: p,
                eventid: 'polled_' + eId++,
                payload: obj
              });
            }
          };
        })(prop)
      );
    } catch (e) {
      log.error('EP', e);
    }
  }
}

function pollLoop() {
  if(isRunning) {
    checkRemotes();
    setTimeout(pollLoop, 10000);
  }
}
 
init();