fcf.module({
  name: "fcf:NTest/Test.js",
  dependencies: [],
  module: function() {
  	var NTest = fcf.prepareObject(fcf, "NTest");
    fcf.prepareObject(fcf, "uniTest.NDetails");
  	var uniTest = fcf.uniTest;

    NTest.Test = function(a_group, a_name, a_testFunc) {
      var self = this;

      this._group    = a_group;
      this._name     = a_name;
      this._testFunc = a_testFunc;

      this.state     = uniTest.ETestStates.WAIT;
      this.output    = "";
      this.error   = undefined;
      this.message   = undefined;
      this.file      = undefined;
      this.line      = undefined;
      this._callback = undefined;

      this.actions = fcf.actions();

      this.run = function(a_cb) {
        this._callback = a_cb;
        this.actions.then(() => {
          return self._testFunc(self);
        });
        this.actions.then(() => {
          self._onComplete();
        });
        this.actions.catch((a_error)=>{
          self._onError(a_error);
        })
      }

      this.setError = function(a_error){
        if (self.state == uniTest.ETestStates.ERROR)
          return;
        self.state = uniTest.ETestStates.ERROR;
        self.message = a_error.message;
        self.error   = a_error;

        var stackIndex = 0;
        if (a_error.stackArr) {
          for (var i = 0; i < a_error.stackArr.length; ++i) {
            var func = a_error.stackArr[i].function;
            if (func.indexOf("Object.uniTest.") !== 0) {
              stackIndex = i;
              break;
            }
          }
        }
        if (a_error.stackArr && a_error.name && a_error.name.indexOf("ERROR_TEST_") == 0){
          self.file = a_error.stackArr[stackIndex].file;
          self.line = a_error.stackArr[stackIndex].line;
        } else if (a_error.stackArr) {
          self.file = a_error.stackArr[stackIndex].file;
          self.line = a_error.stackArr[stackIndex].line;
        } else if (typeof a_error === "object" && a_error.stack) {
          var stackInfo = fcf.Exception.parseStack(a_error.stack);
          self.file = stackInfo[0].file;
          self.line = stackInfo[0].line;
        } else if (typeof a_error === "string") {
          self.message = a_error;
          self.file = undefined;
          self.line = undefined;
        } else {
          self.file = undefined;
          self.line = undefined;
        }

        var output = "";
        output += "[" + uniTest.testStateToString(self.state) + "] ";
        output = fcf.padEnd(output, 8, " ");
        output += "Test [" + this._group + "]";
        output += "[" + this._name + "]";
        output += " is failed.\n";
        output += fcf.padEnd("", 8, " ") + "Message: " + self.message + "\n";
        output += fcf.padEnd("", 8, " ") + "Position: " + self.file + ":" + self.line + "\n\n";

        self.output += output;
      }

      this._onError = function(a_error) {
        this.setError(a_error);
        self._callback();
      }

      this._onComplete = function(){
        if (self.state === uniTest.ETestStates.WAIT) {
          self.state = uniTest.ETestStates.OK;

          var output = "";
          output += "[" + uniTest.testStateToString(self.state) + "] ";
          output = fcf.padEnd(output, 8, " ");
          output += "Test [" + this._group + "]";
          output += "[" + this._name + "]";
          output += " is completed.\n";

          self.output += output;
        }
        self._callback();
      }
    }

  	return NTest.Test;
  }
});
