'use strict';

exports.__esModule = true;

var _declaration = require('postcss/lib/declaration');

var _declaration2 = _interopRequireDefault(_declaration);

var _comment = require('postcss/lib/comment');

var _comment2 = _interopRequireDefault(_comment);

var _atRule = require('postcss/lib/at-rule');

var _atRule2 = _interopRequireDefault(_atRule);

var _rule = require('postcss/lib/rule');

var _rule2 = _interopRequireDefault(_rule);

var _root = require('postcss/lib/root');

var _root2 = _interopRequireDefault(_root);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Parser = function () {
    function Parser(input) {
        _classCallCheck(this, Parser);

        this.input = input;

        this.pos = 0;
        this.root = new _root2.default();
        this.current = this.root;
        this.spaces = '';

        this.prevIndent = undefined;
        this.step = undefined;

        this.root.source = { input: input, start: { line: 1, column: 1 } };
    }

    Parser.prototype.loop = function loop() {
        var part = void 0;
        while (this.pos < this.parts.length) {
            part = this.parts[this.pos];

            if (part.comment) {
                this.comment(part);
            } else if (part.atrule) {
                this.atrule(part);
            } else if (part.colon) {
                var next = this.nextNonComment(this.pos);

                if (next.end || next.atrule) {
                    this.decl(part);
                } else {
                    var moreIndent = next.indent.length > part.indent.length;
                    if (!moreIndent) {
                        this.decl(part);
                    } else if (moreIndent && next.colon) {
                        this.rule(part);
                    } else if (moreIndent && !next.colon) {
                        this.decl(part);
                    }
                }
            } else if (part.end) {
                this.root.raws.after = part.before;
            } else {
                this.rule(part);
            }

            this.pos += 1;
        }

        for (var i = this.tokens.length - 1; i >= 0; i--) {
            if (this.tokens[i].length > 3) {
                var last = this.tokens[i];
                this.root.source.end = {
                    line: last[4] || last[2],
                    column: last[5] || last[3]
                };
                break;
            }
        }
    };

    Parser.prototype.comment = function comment(part) {
        var token = part.tokens[0];
        var node = new _comment2.default();
        this.init(node, part);
        node.source.end = { line: token[4], column: token[5] };
        this.commentText(node, token);
    };

    Parser.prototype.atrule = function atrule(part) {
        var atword = part.tokens[0];
        var params = part.tokens.slice(1);

        var node = new _atRule2.default();
        node.name = atword[1].slice(1);
        this.init(node, part);

        if (node.name === '') this.unnamedAtrule(atword);

        while (!part.end && part.lastComma) {
            this.pos += 1;
            part = this.parts[this.pos];
            params.push(['space', part.before + part.indent]);
            params = params.concat(part.tokens);
        }

        node.raws.afterName = this.firstSpaces(params);
        this.keepTrailingSpace(node, params);
        this.checkSemicolon(params);
        this.checkCurly(params);
        this.raw(node, 'params', params, atword);
    };

    Parser.prototype.decl = function decl(part) {
        var node = new _declaration2.default();
        this.init(node, part);

        var between = '';
        var colon = 0;
        var value = [];
        var prop = '';
        for (var i = 0; i < part.tokens.length; i++) {
            var token = part.tokens[i];
            if (token[0] === ':') {
                between += token[1];
                colon = token;
                value = part.tokens.slice(i + 1);
                break;
            } else if (token[0] === 'comment' || token[0] === 'space') {
                between += token[1];
            } else if (between !== '') {
                this.badProp(token);
            } else {
                prop += token[1];
            }
        }

        if (prop === '') this.unnamedDecl(part.tokens[0]);
        node.prop = prop;

        var next = this.parts[this.pos + 1];

        while (!next.end && !next.atrule && !next.colon && next.indent.length > part.indent.length) {
            value.push(['space', next.before + next.indent]);
            value = value.concat(next.tokens);
            this.pos += 1;
            next = this.parts[this.pos + 1];
        }

        var last = value[value.length - 1];
        if (last && last[0] === 'comment') {
            value.pop();
            var comment = new _comment2.default();
            this.current.push(comment);
            comment.source = {
                input: this.input,
                start: { line: last[2], column: last[3] },
                end: { line: last[4], column: last[5] }
            };
            var prev = value[value.length - 1];
            if (prev && prev[0] === 'space') {
                value.pop();
                comment.raws.before = prev[1];
            }
            this.commentText(comment, last);
        }

        for (var _i = value.length - 1; _i > 0; _i--) {
            var t = value[_i][0];
            if (t === 'word' && value[_i][1] === '!important') {
                node.important = true;
                if (_i > 0 && value[_i - 1][0] === 'space') {
                    node.raws.important = value[_i - 1][1] + '!important';
                    value.splice(_i - 1, 2);
                } else {
                    node.raws.important = '!important';
                    value.splice(_i, 1);
                }
                break;
            } else if (t !== 'space' && t !== 'newline' && t !== 'comment') {
                break;
            }
        }

        node.raws.between = between + this.firstSpaces(value);
        this.checkSemicolon(value);
        this.raw(node, 'value', value, colon);
    };

    Parser.prototype.rule = function rule(part) {
        var node = new _rule2.default();
        this.init(node, part);

        var selector = part.tokens;
        var next = this.parts[this.pos + 1];

        while (!next.end && next.indent.length === part.indent.length) {
            selector.push(['space', next.before + next.indent]);
            selector = selector.concat(next.tokens);
            this.pos += 1;
            next = this.parts[this.pos + 1];
        }

        this.keepTrailingSpace(node, selector);
        this.checkCurly(selector);
        this.raw(node, 'selector', selector);
    };

    /* Helpers */

    Parser.prototype.indent = function indent(part) {
        var indent = part.indent.length;
        var isPrev = typeof this.prevIndent !== 'undefined';

        if (!isPrev && indent) this.indentedFirstLine(part);

        if (!this.step && indent) {
            this.step = indent;
            this.root.raws.indent = part.indent;
        }

        if (isPrev && this.prevIndent !== indent) {
            var diff = indent - this.prevIndent;
            if (diff > 0) {
                if (diff !== this.step) {
                    this.wrongIndent(this.prevIndent + this.step, indent, part);
                } else {
                    this.current = this.current.last;
                }
            } else if (diff % this.step !== 0) {
                var m = indent + diff % this.step;
                this.wrongIndent(m + ' or ' + (m + this.step), indent, part);
            } else {
                for (var i = 0; i < -diff / this.step; i++) {
                    this.current = this.current.parent;
                }
            }
        }

        this.prevIndent = indent;
    };

    Parser.prototype.init = function init(node, part) {
        this.indent(part);

        if (!this.current.nodes) this.current.nodes = [];
        this.current.push(node);

        node.raws.before = part.before + part.indent;
        node.source = {
            start: { line: part.tokens[0][2], column: part.tokens[0][3] },
            input: this.input
        };
    };

    Parser.prototype.checkCurly = function checkCurly(tokens) {
        for (var _iterator = tokens, _isArray = Array.isArray(_iterator), _i2 = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
            var _ref;

            if (_isArray) {
                if (_i2 >= _iterator.length) break;
                _ref = _iterator[_i2++];
            } else {
                _i2 = _iterator.next();
                if (_i2.done) break;
                _ref = _i2.value;
            }

            var token = _ref;

            if (token[0] === '{') {
                this.error('Unnecessary curly bracket', token[2], token[3]);
            }
        }
    };

    Parser.prototype.checkSemicolon = function checkSemicolon(tokens) {
        for (var _iterator2 = tokens, _isArray2 = Array.isArray(_iterator2), _i3 = 0, _iterator2 = _isArray2 ? _iterator2 : _iterator2[Symbol.iterator]();;) {
            var _ref2;

            if (_isArray2) {
                if (_i3 >= _iterator2.length) break;
                _ref2 = _iterator2[_i3++];
            } else {
                _i3 = _iterator2.next();
                if (_i3.done) break;
                _ref2 = _i3.value;
            }

            var token = _ref2;

            if (token[0] === ';') {
                this.error('Unnecessary semicolon', token[2], token[3]);
            }
        }
    };

    Parser.prototype.keepTrailingSpace = function keepTrailingSpace(node, tokens) {
        var lastSpace = tokens[tokens.length - 1];
        if (lastSpace && lastSpace[0] === 'space') {
            tokens.pop();
            node.raws.sssBetween = lastSpace[1];
        }
    };

    Parser.prototype.firstSpaces = function firstSpaces(tokens) {
        var result = '';
        for (var i = 0; i < tokens.length; i++) {
            if (tokens[i][0] === 'space' || tokens[i][0] === 'newline') {
                result += tokens.shift()[1];
                i -= 1;
            } else {
                break;
            }
        }
        return result;
    };

    Parser.prototype.raw = function raw(node, prop, tokens, altLast) {
        var token = void 0,
            type = void 0;
        var length = tokens.length;
        var value = '';
        var clean = true;
        for (var i = 0; i < length; i += 1) {
            token = tokens[i];
            type = token[0];
            if (type === 'comment' || type === 'space' && i === length - 1) {
                clean = false;
            } else {
                value += token[1];
            }
        }
        if (!clean) {
            var sss = tokens.reduce(function (all, i) {
                return all + i[1];
            }, '');
            var raw = tokens.reduce(function (all, i) {
                if (i[0] === 'comment' && i[6] === 'inline') {
                    return all + '/* ' + i[1].slice(2).trim() + ' */';
                } else {
                    return all + i[1];
                }
            }, '');
            node.raws[prop] = { value: value, raw: raw };
            if (sss !== raw) node.raws[prop].sss = sss;
        }
        node[prop] = value;

        var last = void 0;
        for (var _i4 = tokens.length - 1; _i4 >= 0; _i4--) {
            if (tokens[_i4].length > 2) {
                last = tokens[_i4];
                break;
            }
        }
        if (!last) last = altLast;

        node.source.end = {
            line: last[4] || last[2],
            column: last[5] || last[3]
        };
    };

    Parser.prototype.nextNonComment = function nextNonComment(pos) {
        var next = pos;
        var part = void 0;
        while (next < this.parts.length) {
            next += 1;
            part = this.parts[next];
            if (part.end || !part.comment) break;
        }
        return part;
    };

    Parser.prototype.commentText = function commentText(node, token) {
        var text = token[1];
        if (token[6] === 'inline') {
            node.raws.inline = true;
            text = text.slice(2);
        } else {
            text = text.slice(2, -2);
        }

        var match = text.match(/^(\s*)([^]*[^\s])(\s*)\n?$/);
        if (match) {
            node.text = match[2];
            node.raws.left = match[1];
            node.raws.inlineRight = match[3];
        } else {
            node.text = '';
            node.raws.left = '';
            node.raws.inlineRight = '';
        }
    };

    // Errors

    Parser.prototype.error = function error(msg, line, column) {
        throw this.input.error(msg, line, column);
    };

    Parser.prototype.unnamedAtrule = function unnamedAtrule(token) {
        this.error('At-rule without name', token[2], token[3]);
    };

    Parser.prototype.unnamedDecl = function unnamedDecl(token) {
        this.error('Declaration without name', token[2], token[3]);
    };

    Parser.prototype.indentedFirstLine = function indentedFirstLine(part) {
        this.error('First line should not have indent', part.number, 1);
    };

    Parser.prototype.wrongIndent = function wrongIndent(expected, real, part) {
        var msg = 'Expected ' + expected + ' indent, but get ' + real;
        this.error(msg, part.number, 1);
    };

    Parser.prototype.badProp = function badProp(token) {
        this.error('Unexpected separator in property', token[2], token[3]);
    };

    return Parser;
}();

exports.default = Parser;
module.exports = exports['default'];
//# sourceMappingURL=data:application/json;base64,[encoded data, 32568 characters]