const express = require('express');
const libPath = require('path');

fcf.module({
  name: "fcf:NServer/Request.js",
  dependencies: ["fcf:NRender/Render.js"],
  module: function(Render) {
    fcf.prepareObject(fcf, "NServer");

    /**
    * @params a_settings
    *     - object application
    *     - object render
    *     - object routeData
    *     - object expressResponse
    *     - object expressRequest
    **/
    fcf.NServer.Request = class Router {

      constructor(a_settings){
        this._buffer          = "";
        this._file            = undefined;
        this._request         = a_settings.expressRequest;
        this._response        = a_settings.expressResponse;
        this._nexts           = [];
        this._errorProcessor  = undefined;
        this._innerData       = {};
        this._status          = 200;
        this._formData        = a_settings.formData;
        this._files           = a_settings.files;
        this._routeData       = a_settings.routeData;
      }

      getRouteData() {
        return this._routeData;
      }

      getRequest() {
        return this._request;
      }

      getResponse() {
        return this._response;
      }

      getFormData(){
        return this._formData;
      }

      getFiles(){
        return this._files;
      }

      getStatus() {
        return this._status;
      }

      setStatus(a_status) {
        this._status = a_status;
      }

      setHeader(a_item, a_value){
        this._response.header(a_item, a_value);
      }

      getCookie(a_name){
        if (!this._request.headers.cookie)
          return;
        let matches = this._request.headers.cookie.match(new RegExp(
          "(?:^|; )" + a_name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
        ));
        return matches ? decodeURIComponent(matches[1]) : undefined;
      }

      setCookie(a_name, a_value, a_options){
        this._response.cookie(a_name, a_value, a_options);
      }

      redirect(a_path){
        this._response.redirect(a_path);
        this.next();
      }

      send(a_object) {
        this._buffer += typeof a_object === "object" ? JSON.stringify(a_object) : a_object;
        this.next();
      }

      sendText(a_object) {
        this._buffer = a_object;
        this.next();
      }

      sendObject(a_object) {
        this._buffer = JSON.stringify(a_object);
        this.next();
      }

      sendError(a_error) {
        this._status = 500;
        this._buffer = a_error instanceof Error ? JSON.stringify(new fcf.Exception(a_error))
                                                : JSON.stringify(a_error);
        this.next();
      }

      sendFile(a_filePath) {
        this._file = fcf.getPath(a_filePath);
        if (this._file.indexOf(":\\") == -1 && this._file[0] != "/")
          this._file = libPath.join(process.cwd(), this._file)
        this.next();
      }

      sendErrorPage(a_error) {
        if (fcf.empty(this._nexts))
          return;

        let self = this;

        this._buffer = "";

        this.setHeader("Content-Type", "text/html");

        let modules = {};
        for(let k in fcf.settings.libraries) {
          let url = fcf.getPath(k, false);
          modules[k] = url.substr(0, 1) != "/" ? "/" + url : url;
        }

        fcf.log.err("FCF", a_error);

        if (this._errorProcessor){
          this._status = 500;
          this._errorProcessor(a_error, this);
        } else {
          this._status = typeof a_error == "object" && a_error.responseCode ? a_error.responseCode : 500;
          let pageNotFound = fcf.Exception.is(a_error, "ERROR_ROUTER_URL_INCORRECT") || 
                             fcf.Exception.is(a_error, "ERROR_ROUTER_URL_NOT_FOUND") || 
                             fcf.Exception.is(a_error, "ERROR_ROUTER_URL_NOTFULL") || 
                             fcf.Exception.is(a_error, "ERROR_404");
          fcf.application.getRender().render( {
                                            template: pageNotFound ? "@page:page404" : "@page:system-error-page",
                                            args:     {error: a_error, url: fcf.getContext().get("route").url},
                                            external: true,
                                            root:     true,
                                            route:    this.getRouteData(),
                                            context:  fcf.getContext(),
                                            request:  this,
                                            onResult: function(a_error, a_template) {
                                                self._buffer += a_template.content;
                                                self.next();
                                              }
                                            } );
        }
      }

      _complete() {
        let self = this;
        this._response.status(this._status);
        if (self._file){
          this._response.sendFile(self._file);
        } else {
          this._response.send(self._buffer);
        }
      }

      setNext(a_next) {
        let self = this;
        this._nexts.push(a_next);
      }

      next() {
        if (fcf.empty(this._nexts))
          return;
        let next = this._nexts.shift();
        next();
      }


    }

    return fcf.NServer.Request;
  }
});
