/* jslint node: true */
'use strict';

var TextView        = require('./text_view.js').TextView;
var miscUtil        = require('./misc_util.js');
var strUtil         = require('./string_util.js');
var ansi            = require('./ansi_term.js');

//var util          = require('util');
var assert          = require('assert');
var _               = require('lodash');

exports.MaskEditTextView    = MaskEditTextView;

//  ##/##/#### <--styleSGR2 if fillChar
//    ^- styleSGR1
//  buildPattern -> [ RE, RE, '/', RE, RE, '/', RE, RE, RE, RE ]
//  patternIndex -----^

//  styleSGR1: Literal's (non-focus)
//  styleSGR2: Literals (focused)
//  styleSGR3: fillChar

//
//  :TODO:
//  * Hint, e.g. YYYY/MM/DD
//  * Return values with literals in place
//  * Tab in/out results in oddities such as cursor placement & ability to type in non-pattern chars
//  * There exists some sort of condition that allows pattern position to get out of sync

function MaskEditTextView(options) {
    options.acceptsFocus    = miscUtil.valueWithDefault(options.acceptsFocus, true);
    options.acceptsInput    = miscUtil.valueWithDefault(options.acceptsInput, true);
    options.cursorStyle     = miscUtil.valueWithDefault(options.cursorStyle, 'steady block');
    options.resizable       = false;

    TextView.call(this, options);

    this.initDefaultWidth();

    this.cursorPos          = { x : 0 };
    this.patternArrayPos    = 0;

    var self = this;

    this.maskPattern = options.maskPattern || '';

    this.clientBackspace = function() {
        var fillCharSGR = this.getStyleSGR(3) || this.getSGR();
        this.client.term.write('\b' + fillCharSGR + this.fillChar + '\b' + this.getFocusSGR());
    };

    this.drawText = function(s) {
        var textToDraw = strUtil.stylizeString(s, this.hasFocus ? this.focusTextStyle : this.textStyle);

        assert(textToDraw.length <= self.patternArray.length);

        //  draw out the text we have so far
        var i = 0;
        var t = 0;
        while(i < self.patternArray.length) {
            if(_.isRegExp(self.patternArray[i])) {
                if(t < textToDraw.length) {
                    self.client.term.write((self.hasFocus ? self.getFocusSGR() : self.getSGR()) + textToDraw[t]);
                    t++;
                } else {
                    self.client.term.write((self.getStyleSGR(3) || '') + self.fillChar);
                }
            } else {
                var styleSgr = this.hasFocus ? (self.getStyleSGR(2) || '') : (self.getStyleSGR(1) || '');
                self.client.term.write(styleSgr + self.maskPattern[i]);
            }
            i++;
        }
    };

    this.buildPattern = function() {
        self.patternArray   = [];
        self.maxLength      = 0;

        for(var i = 0; i < self.maskPattern.length; i++) {
            //  :TODO: support escaped characters, e.g. \#. Also allow \\ for a '\' mark!
            if(self.maskPattern[i] in MaskEditTextView.maskPatternCharacterRegEx) {
                self.patternArray.push(MaskEditTextView.maskPatternCharacterRegEx[self.maskPattern[i]]);
                ++self.maxLength;
            } else {
                self.patternArray.push(self.maskPattern[i]);
            }
        }
    };

    this.getEndOfTextColumn = function() {
        return this.position.col + this.patternArrayPos;
    };

    this.buildPattern();

}

require('util').inherits(MaskEditTextView, TextView);

MaskEditTextView.maskPatternCharacterRegEx = {
    '#'             : /[0-9]/,              //  Numeric
    'A'             : /[a-zA-Z]/,           //  Alpha
    '@'             : /[0-9a-zA-Z]/,        //  Alphanumeric
    '&'             : /[\w\d\s]/,           //  Any "printable" 32-126, 128-255
};

MaskEditTextView.prototype.setText = function(text) {
    MaskEditTextView.super_.prototype.setText.call(this, text);

    if(this.patternArray) { //  :TODO: This is a hack - see TextView ctor note about setText()
        this.patternArrayPos = this.patternArray.length;
    }
};

MaskEditTextView.prototype.setMaskPattern = function(pattern) {
    this.dimens.width = pattern.length;

    this.maskPattern = pattern;
    this.buildPattern();
};

MaskEditTextView.prototype.onKeyPress = function(ch, key) {
    if(key) {
        if(this.isKeyMapped('backspace', key.name)) {
            if(this.text.length > 0) {
                this.patternArrayPos--;
                assert(this.patternArrayPos >= 0);

                if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
                    this.text = this.text.substr(0, this.text.length - 1);
                    this.clientBackspace();
                } else {
                    while(this.patternArrayPos > 0) {
                        if(_.isRegExp(this.patternArray[this.patternArrayPos])) {
                            this.text = this.text.substr(0, this.text.length - 1);
                            this.client.term.write(ansi.goto(this.position.row, this.getEndOfTextColumn() + 1));
                            this.clientBackspace();
                            break;
                        }
                        this.patternArrayPos--;
                    }
                }
            }

            return;
        } else if(this.isKeyMapped('clearLine', key.name)) {
            this.text               = '';
            this.patternArrayPos    = 0;
            this.setFocus(true);    //  redraw + adjust cursor

            return;
        }
    }

    if(ch && strUtil.isPrintable(ch)) {
        if(this.text.length < this.maxLength) {
            ch = strUtil.stylizeString(ch, this.textStyle);

            if(!ch.match(this.patternArray[this.patternArrayPos])) {
                return;
            }

            this.text += ch;
            this.patternArrayPos++;

            while(this.patternArrayPos < this.patternArray.length &&
                !_.isRegExp(this.patternArray[this.patternArrayPos]))
            {
                this.patternArrayPos++;
            }

            this.redraw();
            this.client.term.write(ansi.goto(this.position.row, this.getEndOfTextColumn()));
        }
    }

    MaskEditTextView.super_.prototype.onKeyPress.call(this, ch, key);
};

MaskEditTextView.prototype.setPropertyValue = function(propName, value) {
    switch(propName) {
        case 'maskPattern'  : this.setMaskPattern(value); break;
    }

    MaskEditTextView.super_.prototype.setPropertyValue.call(this, propName, value);
};

MaskEditTextView.prototype.getData = function() {
    var rawData = MaskEditTextView.super_.prototype.getData.call(this);

    if(!rawData || 0 === rawData.length) {
        return rawData;
    }

    var data    = '';

    assert(rawData.length <= this.patternArray.length);

    var p = 0;
    for(var i = 0; i < this.patternArray.length; ++i) {
        if(_.isRegExp(this.patternArray[i])) {
            data += rawData[p++];
        } else {
            data += this.patternArray[i];
        }
    }

    return data;
};