/**
 * Copyright 2016 the WHATAP project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */

var STAT = {
    NORMAL      : 0,
    COMMENT     : 1,
    ALPHABET    : 2,
    NUMBER      : 3,
    QUOTATION   : 4,
    COLON       : 5,
    DQUOTATION   : 6
};

function EscapeLiteralSQL(sql) {
    if(sql == null) {
        sql = '';
    }
    this.substitute = '#';
    this.substitute_num = '#';
    this.substitute_str_mode = false;
    this.chars = [];
    this.pos = 0;
    this.length = 0;
    this.parsedSql ="";
    this.param = "";
    this.status = -1;
    this.sqlType = 0;

    this.chars = sql.split('');
    this.length = this.chars.length;
}
EscapeLiteralSQL.prototype.setSubstitute = function (chr) {
    this.substitute = chr;

    if(this.substitute_str_mode) {
        this.substitute_num = "'" + chr + "'";
    } else {
        this.substitute_num = this.substitute;
    }
    return this;
};
EscapeLiteralSQL.prototype.setSubstituteStringMode = function (b) {
    if(this.substitute_str_mode === b) {
        return this;
    }
    this.substitute_str_mode = b;
    if(this.substitute_str_mode) {
        this.substitute_num = "'" + this.substitute + "'";
    } else {
        this.substitute_num = this.substitute;
    }
    return this;
};
EscapeLiteralSQL.prototype.process = function () {
    this.status = STAT.NORMAL;
    for(this.pos = 0; this.pos < this.chars.length; this.pos++) {
        switch(this.chars[this.pos]) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                this._number();
                break;
            case ':':
                this._colon();
                break;
            case '.':
                this._dot();
                break;
            case '-':
                this._minus();
                break;
            case '/':
                this._slash();
                break;
            case '*':
                this._astar();
                break;
            case '\'':
                this._quotation();
                break;
            case '\"':
                this._dquotation();
                break;
            default:
                this._others();
        }
    }
    return this;
};
EscapeLiteralSQL.prototype._others = function () {
    switch (this.status) {
        case STAT.COMMENT:
            this.parsedSql += (this.chars[this.pos]);
            break;
        case STAT.ALPHABET:
            this.parsedSql += (this.chars[this.pos]);
            if (this.isProgLetter(this.chars[this.pos]) === false) {
                this.status = STAT.NORMAL;
            }
            break;
        case STAT.NUMBER:
            this.parsedSql += (this.chars[this.pos]);
            this.status = STAT.NORMAL;
            break;
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += (this.chars[this.pos]);
            break;
        default:
            if (this.isProgLetter(this.chars[this.pos])) {
                this.status = STAT.ALPHABET;
                if (this.sqlType === 0) {
                    this.define_crud();
                }
            } else {
                this.status = STAT.NORMAL;
            }
            this.parsedSql += (this.chars[this.pos]);
            break;
    }
};
EscapeLiteralSQL.prototype.isProgLetter = function (ch) {
    return isLetter(ch) || ch === '_';
};
EscapeLiteralSQL.prototype.define_crud = function () {
    this.sqlType = this.chars[this.pos].toUpperCase();
    switch (this.sqlType) {
        case 'S':
        case 'U':
        case 'D':
        case 'I':
            break;
        default:
            this.sqlType = '*';
    }
};
EscapeLiteralSQL.prototype._colon = function () {
    switch (this.status) {
        case STAT.COMMENT:
            this.parsedSql += (this.chars[this.pos]);
            break;
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += (this.chars[this.pos]);
            break;
        default:
            this.parsedSql += (this.chars[this.pos]);
            this.status = STAT.COLON;
            break;
    }
};
EscapeLiteralSQL.prototype._quotation = function () {
    switch (this.status) {
        case STAT.NORMAL:
            if (this.param.length > 0) {
                this.param += ",";
            }
            this.param += this.chars[this.pos];
            this.status = STAT.QUOTATION;
            break;
        case STAT.COMMENT:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.ALPHABET:
            this.parsedSql += this.chars[this.pos];
            status = STAT.QUOTATION;
            break;
        case STAT.NUMBER:
            parsedSql += this.chars[this.pos];
            this.status = STAT.QUOTATION;
            break;
        case STAT.QUOTATION:
            this.param += "'";
            this.parsedSql = this.parsedSql + '\'' + this.substitute + '\'';
            this.status = STAT.NORMAL;
            break;
    }
};
EscapeLiteralSQL.prototype._dquotation = function () {
    switch (this.status) {
        case STAT.NORMAL:
            if (this.param.length > 0) {
                this.param += ",";
            }
            this.param += this.chars[this.pos];
            this.status = STAT.DQUOTATION;
            break;;
        case STAT.COMMENT:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.ALPHABET:
            this.parsedSql += this.chars[this.pos];
            status = STAT.DQUOTATION;
            break;
        case STAT.NUMBER:
            parsedSql += this.chars[this.pos];
            this.status = STAT.DQUOTATION;
            break;
        case STAT.DQUOTATION:
            this.param += '"';
            this.parsedSql = this.parsedSql + '"' + this.substitute + '"';
            this.status = STAT.NORMAL;
            break;
    }
};


EscapeLiteralSQL.prototype._astar = function () {
    switch (this.status) {
        case STAT.COMMENT:
            this.parsedSql += this.chars[this.pos];
            if (this.getNext(this.pos) === '/') {
                this.parsedSql += '/';
                this.pos++;
                this.status = STAT.NORMAL;
            }
            break;
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += this.chars[this.pos];
            break;
        default:
            this.parsedSql += this.chars[this.pos];
            this.status = STAT.NORMAL;
    }
};
EscapeLiteralSQL.prototype._slash = function () {
    switch (this.status) {
        case STAT.COMMENT:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += this.chars[this.pos];
            break;
        default:
            if (this.getNext(this.pos) === '*') {
                this.pos++;
                this.parsedSql += "/*";
                this.status = STAT.COMMENT;
            }
    }
};
EscapeLiteralSQL.prototype._minus = function () {
    switch (this.status) {
        case STAT.COMMENT:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += this.chars[this.pos];
            break;
        default:
            if (this.getNext(this.pos) === '-') {
                this.parsedSql += this.chars[this.pos];
                while (this.chars[this.pos] != '\n') {
                    this.pos++;
                    if (this.pos < this.length) {
                        this.parsedSql += this.chars[this.pos];
                    } else {
                        break;
                    }
                }
            } else {
                this.parsedSql += this.chars[this.pos];
            }
            this.status = STAT.NORMAL;
    }
};
EscapeLiteralSQL.prototype._dot = function () {
    switch (this.status) {
        case STAT.NORMAL:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.COMMENT:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.ALPHABET:
            this.parsedSql += this.chars[this.pos];
            this.status = STAT.NORMAL;
            break;
        case STAT.NUMBER:
            this.param += this.chars[this.pos];
            break;
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += this.chars[this.pos];
            break;
    }
};
EscapeLiteralSQL.prototype._number = function () {
    switch (this.status) {
        case STAT.NORMAL:
            if (this.param.length > 0) {
                this.param += ",";
            }
            this.param += this.chars[this.pos];
            this.parsedSql += this.substitute_num;
            this.status = STAT.NUMBER;
            break;
        case STAT.COMMENT:
        case STAT.COLON:
        case STAT.ALPHABET:
            this.parsedSql += this.chars[this.pos];
            break;
        case STAT.NUMBER:
        case STAT.QUOTATION:
        case STAT.DQUOTATION:
            this.param += this.chars[this.pos];
            break;
    }
};
EscapeLiteralSQL.prototype.getNext = function (x) {
    return x < this.length ? this.chars[x+1] : 0;
};
EscapeLiteralSQL.prototype.getParsedSql = function () {
    return this.parsedSql;
};
EscapeLiteralSQL.prototype.getParameter = function () {
    return this.param;
};

var ASCII_a = 97,
    ASCII_z = 122,
    ASCII_A = 65,
    ASCII_Z = 90;

function isLetter(ch) {
    var str = ch.charCodeAt(0);
    return ((str >= ASCII_a) && (str <= ASCII_z)) || ((str >= ASCII_A) && (str <= ASCII_Z));
}

module.exports = EscapeLiteralSQL;