var fs = require('fs');
var utils = require('../../util/utils');
var Loader = require('pomelo-loader');
var pathUtil = require('../../util/pathUtil');
var logger = require('pomelo-logger').getLogger('pomelo', __filename);
var forwardLogger = require('pomelo-logger').getLogger('forward-log', __filename);
/**
 * Handler service.
 * Dispatch request to the relactive handler.
 *
 * @param {Object} app      current application context
 */
var Service = function(app, opts) {
  this.app = app;
  this.handlerMap = {};
  if(!!opts.reloadHandlers) {
    watchHandlers(app, this.handlerMap);
  }
};

module.exports = Service;

Service.prototype.name = 'handler';

/**
 * Handler the request.
 */
Service.prototype.handle = function(routeRecord, msg, session, cb) {
  // the request should be processed by current server
  var handler = this.getHandler(routeRecord);
  if(!handler) {
    logger.error('[handleManager]: fail to find handler for %j', msg.__route__);
    utils.invokeCallback(cb, new Error('fail to find handler for ' + msg.__route__));
    return;
  }
  var start = Date.now();

  handler[routeRecord.method](msg, session, function(err, resp, opts) {
    var log = {
      route : msg.__route__,
      args : msg,
      time : utils.format(new Date(start)),
      timeUsed : new Date() - start
    };
    forwardLogger.info(JSON.stringify(log));
    utils.invokeCallback(cb, err, resp, opts);
  });
  return;
};

/**
 * Get handler instance by routeRecord.
 *
 * @param  {Object} handlers    handler map
 * @param  {Object} routeRecord route record parsed from route string
 * @return {Object}             handler instance if any matchs or null for match fail
 */
Service.prototype.getHandler = function(routeRecord) {
  var serverType = routeRecord.serverType;
  if(!this.handlerMap[serverType]) {
    loadHandlers(this.app, serverType, this.handlerMap);
  }
  var handlers = this.handlerMap[serverType] || {};
  var handler = handlers[routeRecord.handler];
  if(!handler) {
    logger.warn('could not find handler for routeRecord: %j', routeRecord);
    return null;
  }
  if(typeof handler[routeRecord.method] !== 'function') {
    logger.warn('could not find the method %s in handler: %s', routeRecord.method, routeRecord.handler);
    return null;
  }
  return handler;
};

/**
 * Load handlers from current application
 */
var loadHandlers = function(app, serverType, handlerMap) {
  var p = pathUtil.getHandlerPath(app.getBase(), serverType);
  if(p) {
    handlerMap[serverType] = Loader.load(p, app);
  }
};

var watchHandlers = function(app, handlerMap) {
  var p = pathUtil.getHandlerPath(app.getBase(), app.serverType);
  if (!!p){
    fs.watch(p, function(event, name) {
      if(event === 'change') {
        handlerMap[app.serverType] = Loader.load(p, app);
      }
    });
  }
};

var fs = require('fs');
var utils = require('../../util/utils');
var Loader = require('pomelo-loader');
var pathUtil = require('../../util/pathUtil');
var logger = require('pomelo-logger').getLogger('pomelo', __filename);
var forwardLogger = require('pomelo-logger').getLogger('forward-log', __filename);
/**
 * Handler service.
 * Dispatch request to the relactive handler.
 *
 * @param {Object} app      current application context
 */
var Service = function(app, opts) {
  this.app = app;
  this.handlerMap = {};
  if(!!opts.reloadHandlers) {
    watchHandlers(app, this.handlerMap);
  }

  this.enableForwardLog = opts.enableForwardLog || false;
};

module.exports = Service;

Service.prototype.name = 'handler';

/**
 * Handler the request.
 */
Service.prototype.handle = function(routeRecord, msg, session, cb) {
  // the request should be processed by current server
  var handler = this.getHandler(routeRecord);
  if(!handler) {
    logger.error('[handleManager]: fail to find handler for %j', msg.__route__);
    utils.invokeCallback(cb, new Error('fail to find handler for ' + msg.__route__));
    return;
  }
  var start = Date.now();
  var self = this;
  handler[routeRecord.method](msg, session, function(err, resp, opts) {
    if(self.enableForwardLog) {
      var log = {
        route : msg.__route__,
        args : msg,
        time : utils.format(new Date(start)),
        timeUsed : new Date() - start
      };
      forwardLogger.info(JSON.stringify(log));
    }
    utils.invokeCallback(cb, err, resp, opts);
  });
  return;
};

/**
 * Get handler instance by routeRecord.
 *
 * @param  {Object} handlers    handler map
 * @param  {Object} routeRecord route record parsed from route string
 * @return {Object}             handler instance if any matchs or null for match fail
 */
Service.prototype.getHandler = function(routeRecord) {
  var serverType = routeRecord.serverType;
  if(!this.handlerMap[serverType]) {
    loadHandlers(this.app, serverType, this.handlerMap);
  }
  var handlers = this.handlerMap[serverType] || {};
  var handler = handlers[routeRecord.handler];
  if(!handler) {
    logger.warn('could not find handler for routeRecord: %j', routeRecord);
    return null;
  }
  if(typeof handler[routeRecord.method] !== 'function') {
    logger.warn('could not find the method %s in handler: %s', routeRecord.method, routeRecord.handler);
    return null;
  }
  return handler;
};

/**
 * Load handlers from current application
 */
var loadHandlers = function(app, serverType, handlerMap) {
  var p = pathUtil.getHandlerPath(app.getBase(), serverType);
  if(p) {
    handlerMap[serverType] = Loader.load(p, app);
  }
};

var watchHandlers = function(app, handlerMap) {
  var p = pathUtil.getHandlerPath(app.getBase(), app.serverType);
  if (!!p){
    fs.watch(p, function(event, name) {
      if(event === 'change') {
        handlerMap[app.serverType] = Loader.load(p, app);
      }
    });
  }
};

add enableForwardLog flag to close forward log to improve performance