/*
This is the actual express handler for incoming requests.
function handleIncomingRequest(actionType, alias, req, res, next) {
    if (typeof req.uniqueId === 'undefined') {
      req.uniqueId = ++uniqueRequestId;
      req.startAt = Date.now();
    }
    if (!req.action) {
      req.action = actionType;
    }
    if (typeof this[actions][actionType] === 'undefined') {
      let msg = 'The requested resource was not found';
      if (this[config].actionPath !== req.url) {
        msg += `: ${req.method} ${req.url}`;
      }
      return handleRequestError.call(this, thorin.error('TRANSPORT.NOT_FOUND', msg, 404), req, res, next);
    }
    req._hasDebug = this[actions][actionType].hasDebug;
    req.exposeType = (this[actions][actionType].defaultHandle === true);
    // check if it was disabled.
    if (this[disabledActions][actionType] === true) {
      return handleRequestError.call(this, thorin.error('TRANSPORT.UNAVAILABLE', 'The requested URL is temporary unavailable: ' + req.url, 502), req, res, next);
    }
    if (thorin.env !== 'production' && req._hasDebug) {
      let logMsg = '[START ' + req.uniqueId + '] - ' + req.action;
      logMsg += " (" + req.method.toUpperCase() + ' ' + req.originalUrl.substr(0, 64) + ')';
      logger('trace', logMsg);
    }
    // build the incoming data.
    const inputData = {};
    // insert query
    parseRequestInput(req.query, inputData);
    // insert body
    parseRequestInput(req.body, inputData);
    // insert param
    parseRequestInput(req.params, inputData);

    // The HTTP Transport will attach the .redirect(url) option in the intent.
    // NOTE: redirects will ignore attached results or errors.

    // attach the source ip address.
    let redirectTo = null, redirectCode = 302, isFinished = false;
    const actionObj = this[actions][actionType];
    const intentObj = new thorin.Intent(actionType, inputData, (wasError, data, intentObj) => {
      isFinished = true;
      let hasCors = false,
        corsDomain, corsCredentials, corsMethods;
      if (intentObj.hasCors()) {
        hasCors = true;
        let corsData = intentObj.getCors();
        corsDomain = corsData.domain || '*';
        corsCredentials = corsData.credentials || false;
        if (corsData.methods) {
          corsMethods = corsData.methods;
        }
      } else if (actionObj && actionObj.cors) {
        hasCors = true;
        corsDomain = actionObj.cors.domain || '*';
        corsCredentials = actionObj.cors.credentials || false;
        if (actionObj.cors.methods) {
          corsMethods = actionObj.cors.methods;
        }
      }
      if (hasCors) {
        if (!corsMethods) {
          corsMethods = ['OPTIONS'];
          if (req.method !== 'OPTIONS') {
            corsMethods.push(req.method);
          }
        } else if (corsMethods.indexOf('OPTIONS') === -1) {
          corsMethods.push('OPTIONS');
        }
        try {
          res.header('Access-Control-Allow-Origin', corsDomain);
          res.header('Access-Control-Allow-Methods', corsMethods.join(', '));
          res.header('Access-Control-Allow-Credentials', corsCredentials);
          res.header('Access-Control-Allow-Headers', req.headers['access-control-request-headers'] || '*');
          res.header('Access-Control-Max-Age', '600');
        } catch (e) {
        }
      }
      let resultHeaders = intentObj.resultHeaders();
      if (resultHeaders && !res.headersSent) {
        Object.keys(resultHeaders).forEach((name) => {
          if(this[config].ignoreHeaders && this[config].ignoreHeaders.indexOf(name) !== -1) return;
          let value = resultHeaders[name];
          if (typeof value === 'string' || value instanceof Array || typeof value === 'number') {
            try {
              res.header(name, value);
            } catch (e) {
            }
          }
        });
      }
      if (redirectTo != null) {
        // redirect the request.
        handleIntentRedirect.call(this, req, res, intentObj, redirectTo, redirectCode);
        return;
      }
      let sendFn = (wasError ? handleIntentError : handleIntentSuccess);
      sendFn.call(this, req, res, next, data, intentObj);
    });
    if (req.filter) {
      intentObj.__setRawFilter(req.filter);
    }
    if (req.meta) {
      intentObj.__setRawMeta(req.meta);
    }
    // IF we are coming from an alias, attach it.
    if (actionType !== req.action) {
      intentObj.match = req.action;
    }
    if (alias) {
      intentObj.alias = alias;
      intentObj.url = req.url;
    }
    /* Attach the result object if needed */
    if (actionObj.exposeRequest) {
      intentObj.req = req;
    }
    if (actionObj.exposeResponse) {
      intentObj.res = res;
    }
    /* Attach the redirect functionality */
    intentObj.redirect = function PerformRedirect(url, _code) {
      if (typeof url !== 'string') return this;
      if (typeof _code === 'number') {
        redirectCode = _code;
      } else if (typeof _code === 'object' && _code) {
        // we have redirect with querystring
        let clean = [],
          keys = Object.keys(_code);
        for (let i = 0; i < keys.length; i++) {
          let k = keys[i];
          if (typeof _code[k] === 'undefined' || _code[k] == null) continue;
          clean[k] = _code[k];
        }
        try {
          let qstring = qs.stringify(clean);
          if (url.indexOf('?') === -1) {
            url += '?' + qstring;
          } else {
            url += '&' + qstring;
          }
        } catch (e) {
        }
      }
      redirectTo = url;
      intentObj._canRender = false;
      // IF code is set to false, we do not directly send()
      if (_code === false) {
        return this;
      }
      return this.send();
    };
    // set up authorization information.
    let authToken = getAuthorizationData(this[config].authorization, req);
    if (authToken) {
      intentObj._setAuthorization('TOKEN', authToken);
    }
    intentObj.transport = 'http';
    // set up client information (headers, ip)
    const clientData = {
      ip: req.ip,
      headers: req.headers,
      xhr: req.xhr
    };
    try {
      if (!clientData.xhr && req.headers.accept.indexOf('json') !== -1) {
        clientData.xhr = true;
      }
    } catch (e) {
    }
    intentObj.client(clientData);

    function onRequestClose() {
      req.removeListener('close', onRequestClose);
      if (isFinished) return;
      try {
        intentObj.__trigger(thorin.Intent.EVENT.CLOSE);
      } catch (e) {
      }
    }

    req.on('close', onRequestClose);
    thorin.dispatcher.triggerIntent(intentObj);
  }