'use strict';

// TODO if RAM is very low we should not fork at all,
// but use a different process altogether

console.info('pid:', process.pid);
console.info('title:', process.title);
console.info('arch:', process.arch);
console.info('platform:', process.platform);
console.info('\n\n\n[MASTER] Welcome to WALNUT!');

function tryConf(pathname, def) {
  try {
    return require(pathname);
  } catch(e) {
    return def;
  }
}

var path = require('path');
var cluster = require('cluster');
//var minWorkers = 2;
var numCores = 2; // Math.max(minWorkers, require('os').cpus().length);
var workers = [];
var state = { firstRun: true };
// TODO Should these be configurable? If so, where?
// TODO communicate config with environment vars?
var walnut = tryConf(
  path.join('..', '..', 'config.walnut')
, { externalPort: 443
  , externalInsecurePort: 80
  }
);

var info = {
  type: 'walnut.init'
, conf: {
    protocol: 'http'
  , externalPort: walnut.externalPort || 443
  , externalPortInsecure: walnut.externalInsecurePort || 80   // TODO externalInsecurePort
  , localPort: walnut.localPort || 3000                       // system / local network
  , trustProxy: true
  , varpath: path.join(__dirname, '..', '..', 'var')
  , etcpath: path.join(__dirname, '..', '..', 'etc')
  }
};

function fork() {
  if (workers.length < numCores) {
    workers.push(cluster.fork());
  }
}

cluster.on('online', function (worker) {
  console.info('[MASTER] Worker ' + worker.process.pid + ' is online');
  fork();

  if (state.firstRun) {
    state.firstRun = false;
    // TODO dyndns in master?
  }

  function touchMaster(msg) {
    if ('walnut.webserver.listening' !== msg.type) {
      console.warn('[MASTER] received unexpected message from worker');
      console.warn(msg);
      return;
    }

    state.workers = workers;
    // calls init if init has not been called
    require('../lib/master').touch(info.conf, state).then(function (newConf) {
      worker.send({ type: 'walnut.webserver.onrequest', conf: newConf });
      newConf.addWorker(worker);
    });
  }

  worker.send(info);
  worker.on('message', touchMaster);
});

cluster.on('exit', function (worker, code, signal) {
  console.info('[MASTER] Worker ' + worker.process.pid + ' died with code: ' + code + ', and signal: ' + signal);

  workers = workers.filter(function (w) {
    return w && w !== worker;
  });

  //console.log('WARNING: worker spawning turned off for debugging ');
  fork();
});

fork();
