var util = require('util');
var EventEmitter = require('events').EventEmitter;

var StateMachine = function(rli, colors) {
  var questions;
  var currentQuestion;
  var answers;
  var currentOptions;
  var currentOptionsPointer;
  var currentQuestionId;
  var done;

  EventEmitter.call(this);

  var showPrompt = function() {
    rli.write(colors.ANSWER);
    rli.prompt();
  };

  this.onKeypress = function(key) {
    if (!currentOptions || !key) {
      return;
    }

    if (key.name === 'tab' || key.name === 'right' || key.name === 'down') {
      this.suggestNextOption();
    } else if (key.name === 'left' || key.name === 'up') {
      currentOptionsPointer = currentOptionsPointer + currentOptions.length - 2;
      this.suggestNextOption();
    }

    if (!key.ctrl && !key.meta && key.name !== 'enter' && key.name !== 'return') {
      key.name = 'escape';
    }
  };

  this.suggestNextOption = function() {
    if (!currentOptions) {
      return;
    }

    currentOptionsPointer = (currentOptionsPointer + 1) % currentOptions.length;
    rli._deleteLineLeft();
    rli._deleteLineRight();
    rli.write(currentOptions[currentOptionsPointer]);
  };

  this.kill = function() {
    currentOptions = null;
    currentQuestionId = null;
    rli.write('\n' + colors.RESET + '\n');
    rli.close();
  };


  this.onLine = function(line) {
    if (currentQuestionId) {
      rli.write(colors.RESET);
      line = line.trim().replace(colors.ANSWER, '').replace(colors.RESET, '');

      if (currentOptions) {
        currentOptionsPointer = currentOptions.indexOf(line);
        if (currentOptionsPointer === -1) {
          return;
        }
      }

      if (line === '') {
        line = null;
      }

      if (currentQuestion.boolean) {
        line = (line === 'yes' || line === 'true' || line === 'on');
      }

      if (line !== null && currentQuestion.validate) {
        currentQuestion.validate(line);
      }

      if (currentQuestion.multiple) {
        answers[currentQuestionId] = answers[currentQuestionId] || [];
        if (line !== null) {
          answers[currentQuestionId].push(line);
          showPrompt();

          if (currentOptions) {
            currentOptions.splice(currentOptionsPointer, 1);
            currentOptionsPointer = -1;
          }
        } else {
          this.nextQuestion();
        }
      } else {
        answers[currentQuestionId] = line;
        this.nextQuestion();
      }
    }
  };

  this.nextQuestion = function() {
    currentQuestion = questions.shift();

    while (currentQuestion && currentQuestion.condition && !currentQuestion.condition(answers)) {
      currentQuestion = questions.shift();
    }

    this.emit('next_question', currentQuestion);

    if (currentQuestion) {
      currentQuestionId = null;

      rli.write('\n' + colors.question(currentQuestion.question) + '\n');
      rli.write(currentQuestion.hint + '\n');
      showPrompt();

      currentOptions = currentQuestion.options || null;
      currentOptionsPointer = -1;
      currentQuestionId = currentQuestion.id;

      this.suggestNextOption();
    } else {
      currentQuestionId = null;
      currentOptions = null;

      // end
      this.kill();
      done(answers);
    }
  };

  this.process = function(_questions, _done) {
    questions = _questions;
    answers = {};
    done = _done;

    this.nextQuestion();
  };
};

util.inherits(StateMachine, EventEmitter);


module.exports = StateMachine;
