/**
* pretty-data - nodejs plugin to pretty-print or minify data in XML, JSON and CSS formats.
*
* Version - 0.40.0
* Copyright (c) 2012 Vadim Kiryukhin
* vkiryukhin @ gmail.com
* http://www.eslinstructor.net/pretty-data/
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
*	pd.xml(data ) - pretty print XML;
*	pd.json(data) - pretty print JSON;
*	pd.css(data ) - pretty print CSS;
*	pd.sql(data)  - pretty print SQL;
*
*	pd.xmlmin(data [, preserveComments] ) - minify XML;
*	pd.jsonmin(data)                      - minify JSON;
*	pd.cssmin(data [, preserveComments] ) - minify CSS;
*	pd.sqlmin(data)                       - minify SQL;
*
* PARAMETERS:
*
*	@data  			- String; XML, JSON, CSS or SQL text to beautify;
* 	@preserveComments	- Bool (optional, used in minxml and mincss only);
*				  Set this flag to true to prevent removing comments from @text;
*	@Return 		- String;
*
* USAGE:
*
*	var pd  = require('pretty-data').pd;
*
*	var xml_pp   = pd.xml(xml_text);
*	var xml_min  = pd.xmlmin(xml_text [,true]);
*	var json_pp  = pd.json(json_text);
*	var json_min = pd.jsonmin(json_text);
*	var css_pp   = pd.css(css_text);
*	var css_min  = pd.cssmin(css_text [, true]);
*	var sql_pp   = pd.sql(sql_text);
*	var sql_min  = pd.sqlmin(sql_text);
*
* TEST:
*	comp-name:pretty-data$ node ./test/test_xml
*	comp-name:pretty-data$ node ./test/test_json
*	comp-name:pretty-data$ node ./test/test_css
*	comp-name:pretty-data$ node ./test/test_sql
*/
function pp() {
    this.shift = ['\n']; // array of shifts
    this.step = '  '; // 2 spaces
    var ix = 0;
    // initialize array with shifts; nesting level == 100 //
    for (ix = 0; ix < 100; ix++) {
        this.shift.push(this.shift[ix] + this.step);
    }
}
// ----------------------- XML section ----------------------------------------------------
pp.prototype.xml = function (text) {
    var ar = text.replace(/>\s{0,}</g, "><")
        .replace(/</g, "~::~<")
        .replace(/xmlns\:/g, "~::~xmlns:")
        .replace(/xmlns\=/g, "~::~xmlns=")
        .split('~::~'), len = ar.length, inComment = false, deep = 0, str = '', ix = 0;
    for (ix = 0; ix < len; ix++) {
        // start comment or <![CDATA[...]]> or <!DOCTYPE //
        if (ar[ix].search(/<!/) > -1) {
            str += this.shift[deep] + ar[ix];
            inComment = true;
            // end comment  or <![CDATA[...]]> //
            if (ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1 || ar[ix].search(/!DOCTYPE/) > -1) {
                inComment = false;
            }
        }
        else 
        // end comment  or <![CDATA[...]]> //
        if (ar[ix].search(/-->/) > -1 || ar[ix].search(/\]>/) > -1) {
            str += ar[ix];
            inComment = false;
        }
        else 
        // <elm></elm> //
        { // @ts-ignore
            // @ts-ignore
            if (/^<\w/.exec(ar[ix - 1]) && /^<\/\w/.exec(ar[ix]) && /^<[\w:\-\.\,]+/.exec(ar[ix - 1]) == /^<\/[\w:\-\.\,]+/.exec(ar[ix])[0].replace('/', '')) {
                str += ar[ix];
                if (!inComment)
                    deep--;
            }
            else 
            // <elm> //
            if (ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) == -1 && ar[ix].search(/\/>/) == -1) {
                str = !inComment ? str += this.shift[deep++] + ar[ix] : str += ar[ix];
            }
            else 
            // <elm>...</elm> //
            if (ar[ix].search(/<\w/) > -1 && ar[ix].search(/<\//) > -1) {
                str = !inComment ? str += this.shift[deep] + ar[ix] : str += ar[ix];
            }
            else 
            // </elm> //
            if (ar[ix].search(/<\//) > -1) {
                str = !inComment ? str += this.shift[--deep] + ar[ix] : str += ar[ix];
            }
            else 
            // <elm/> //
            if (ar[ix].search(/\/>/) > -1) {
                str = !inComment ? str += this.shift[deep] + ar[ix] : str += ar[ix];
            }
            else 
            // <? xml ... ?> //
            if (ar[ix].search(/<\?/) > -1) {
                str += this.shift[deep] + ar[ix];
            }
            else 
            // xmlns //
            if (ar[ix].search(/xmlns\:/) > -1 || ar[ix].search(/xmlns\=/) > -1) {
                str += this.shift[deep] + ar[ix];
            }
            else {
                str += ar[ix];
            }
        }
    }
    return (str[0] == '\n') ? str.slice(1) : str;
};
// ----------------------- JSON section ----------------------------------------------------
pp.prototype.json = function (text) {
    if (typeof text === "string") {
        return JSON.stringify(JSON.parse(text), null, this.step);
    }
    if (typeof text === "object") {
        return JSON.stringify(text, null, this.step);
    }
    return null;
};
// ----------------------- CSS section ----------------------------------------------------
pp.prototype.css = function (text) {
    var ar = text.replace(/\s{1,}/g, ' ')
        .replace(/\{/g, "{~::~")
        .replace(/\}/g, "~::~}~::~")
        .replace(/\;/g, ";~::~")
        .replace(/\/\*/g, "~::~/*")
        .replace(/\*\//g, "*/~::~")
        .replace(/~::~\s{0,}~::~/g, "~::~")
        .split('~::~'), len = ar.length, deep = 0, str = '', ix = 0;
    for (ix = 0; ix < len; ix++) {
        if (/\{/.exec(ar[ix])) {
            str += this.shift[deep++] + ar[ix];
        }
        else if (/\}/.exec(ar[ix])) {
            str += this.shift[--deep] + ar[ix];
        }
        else if (/\*\\/.exec(ar[ix])) {
            str += this.shift[deep] + ar[ix];
        }
        else {
            str += this.shift[deep] + ar[ix];
        }
    }
    return str.replace(/^\n{1,}/, '');
};
// ----------------------- SQL section ----------------------------------------------------
function isSubquery(str, parenthesisLevel) {
    return parenthesisLevel - (str.replace(/\(/g, '').length - str.replace(/\)/g, '').length);
}
function split_sql(str, tab) {
    return str.replace(/\s{1,}/g, " ")
        .replace(/ AND /ig, "~::~" + tab + tab + "AND ")
        .replace(/ BETWEEN /ig, "~::~" + tab + "BETWEEN ")
        .replace(/ CASE /ig, "~::~" + tab + "CASE ")
        .replace(/ ELSE /ig, "~::~" + tab + "ELSE ")
        .replace(/ END /ig, "~::~" + tab + "END ")
        .replace(/ FROM /ig, "~::~FROM ")
        .replace(/ GROUP\s{1,}BY/ig, "~::~GROUP BY ")
        .replace(/ HAVING /ig, "~::~HAVING ")
        //.replace(/ IN /ig,"~::~"+tab+"IN ")
        .replace(/ IN /ig, " IN ")
        .replace(/ JOIN /ig, "~::~JOIN ")
        .replace(/ CROSS~::~{1,}JOIN /ig, "~::~CROSS JOIN ")
        .replace(/ INNER~::~{1,}JOIN /ig, "~::~INNER JOIN ")
        .replace(/ LEFT~::~{1,}JOIN /ig, "~::~LEFT JOIN ")
        .replace(/ RIGHT~::~{1,}JOIN /ig, "~::~RIGHT JOIN ")
        .replace(/ ON /ig, "~::~" + tab + "ON ")
        .replace(/ OR /ig, "~::~" + tab + tab + "OR ")
        .replace(/ ORDER\s{1,}BY/ig, "~::~ORDER BY ")
        .replace(/ OVER /ig, "~::~" + tab + "OVER ")
        .replace(/\(\s{0,}SELECT /ig, "~::~(SELECT ")
        .replace(/\)\s{0,}SELECT /ig, ")~::~SELECT ")
        .replace(/ THEN /ig, " THEN~::~" + tab + "")
        .replace(/ UNION /ig, "~::~UNION~::~")
        .replace(/ USING /ig, "~::~USING ")
        .replace(/ WHEN /ig, "~::~" + tab + "WHEN ")
        .replace(/ WHERE /ig, "~::~WHERE ")
        .replace(/ WITH /ig, "~::~WITH ")
        //.replace(/\,\s{0,}\(/ig,",~::~( ")
        //.replace(/\,/ig,",~::~"+tab+tab+"")
        .replace(/ ALL /ig, " ALL ")
        .replace(/ AS /ig, " AS ")
        .replace(/ ASC /ig, " ASC ")
        .replace(/ DESC /ig, " DESC ")
        .replace(/ DISTINCT /ig, " DISTINCT ")
        .replace(/ EXISTS /ig, " EXISTS ")
        .replace(/ NOT /ig, " NOT ")
        .replace(/ NULL /ig, " NULL ")
        .replace(/ LIKE /ig, " LIKE ")
        .replace(/\s{0,}SELECT /ig, "SELECT ")
        .replace(/~::~{1,}/g, "~::~")
        .split('~::~');
}
pp.prototype.sql = function (text) {
    var ar_by_quote = text.replace(/\s{1,}/g, " ")
        .replace(/\'/ig, "~::~\'")
        .split('~::~'), len = ar_by_quote.length, ar = [], deep = 0, tab = this.step, parenthesisLevel = 0, str = '', ix = 0;
    for (ix = 0; ix < len; ix++) {
        if (ix % 2) {
            ar = ar.concat(ar_by_quote[ix]);
        }
        else {
            ar = ar.concat(split_sql(ar_by_quote[ix], tab));
        }
    }
    len = ar.length;
    for (ix = 0; ix < len; ix++) {
        parenthesisLevel = isSubquery(ar[ix], parenthesisLevel);
        if (/\s{0,}\s{0,}SELECT\s{0,}/.exec(ar[ix])) {
            ar[ix] = ar[ix].replace(/\,/g, ",\n" + tab + tab + "");
        }
        if (/\s{0,}\(\s{0,}SELECT\s{0,}/.exec(ar[ix])) {
            deep++;
            str += this.shift[deep] + ar[ix];
        }
        else if (/\'/.exec(ar[ix])) {
            if (parenthesisLevel < 1 && deep) {
                deep--;
            }
            str += ar[ix];
        }
        else {
            str += this.shift[deep] + ar[ix];
            if (parenthesisLevel < 1 && deep) {
                deep--;
            }
        }
    }
    str = str.replace(/^\n{1,}/, '').replace(/\n{1,}/g, "\n");
    return str;
};
// ----------------------- min section ----------------------------------------------------
pp.prototype.xmlmin = function (text, preserveComments) {
    var str = preserveComments ? text
        : text.replace(/\<![ \r\n\t]*(--([^\-]|[\r\n]|-[^\-])*--[ \r\n\t]*)\>/g, "");
    return str.replace(/>\s{0,}</g, "><");
};
pp.prototype.jsonmin = function (text) {
    return text.replace(/\s{0,}\{\s{1,}/g, "{")
        .replace(/\s{0,}\[$/g, "[")
        .replace(/\[\s{0,}/g, "[")
        .replace(/:\s{0,}\[/g, ':[')
        .replace(/\s{1,}\}\s{0,}/g, "}")
        .replace(/\s{0,}\]\s{0,}/g, "]")
        .replace(/\"\s{0,}\,/g, '",')
        .replace(/\,\s{0,}\"/g, ',"')
        .replace(/\"\s{0,}:/g, '":')
        .replace(/:\s{0,}\"/g, ':"')
        .replace(/:\s{0,}\[/g, ':[')
        .replace(/\,\s{0,}\[/g, ',[')
        .replace(/\,\s{2,}/g, ', ')
        .replace(/\]\s{0,},\s{0,}\[/g, '],[');
};
pp.prototype.cssmin = function (text, preserveComments) {
    var str = preserveComments ? text
        : text.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\//g, "");
    return str.replace(/\s{1,}/g, ' ')
        .replace(/\{\s{1,}/g, "{")
        .replace(/\}\s{1,}/g, "}")
        .replace(/\;\s{1,}/g, ";")
        .replace(/\/\*\s{1,}/g, "/*")
        .replace(/\*\/\s{1,}/g, "*/");
};
pp.prototype.sqlmin = function (text) {
    return text.replace(/\s{1,}/g, " ").replace(/\s{1,}\(/, "(").replace(/\s{1,}\)/, ")");
};
// --------------------------------------------------------------------------------------------
exports.pd = new pp();
//# sourceMappingURL=pretty-data.js.map