"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var typeExpression = require("./typeExpressionParser");
var ts = require("./typesystem");
var _parse = require("./parse");
var restrictions_1 = require("./restrictions");
var metainfo_1 = require("./metainfo");
function parseToType(val, t, contentProvidingNode, typeAttributeContentProvider, isPropertyType) {
    if (typeAttributeContentProvider === void 0) { typeAttributeContentProvider = null; }
    if (isPropertyType === void 0) { isPropertyType = false; }
    if (val == null) {
        return null;
    }
    try {
        var q = val.trim();
        if (q.length > 0) {
            var json = q.charAt(0) == '{';
            if (json || (q.charAt(0) == '<' && q.length > 1 && q.charAt(1) != '<')) {
                var typeChild = contentProvidingNode;
                var n = void 0;
                do {
                    n = typeChild;
                    typeChild = n.childWithKey("type");
                } while (typeChild);
                var contentProvider = n && n.contentProvider && n.contentProvider();
                return new ts.ExternalType("", q, json, contentProvider, typeAttributeContentProvider);
            }
            var node = parse(val);
            var result = parseNode(node, t, isPropertyType);
            return result;
        }
        else {
            return ts.derive(val, [ts.STRING]);
        }
    }
    catch (e) {
        return ts.derive(val, [ts.UNKNOWN]);
    }
}
exports.parseToType = parseToType;
function wrapArray(a, result) {
    while (a > 0) {
        var nt = ts.derive("", [ts.ARRAY]);
        nt.addMeta(new restrictions_1.ComponentShouldBeOfType(result));
        result = nt;
        a--;
    }
    return result;
}
function parseNode(node, t, isPropertyType) {
    if (node.type == "union") {
        var ut = node;
        return ts.union("", [parseNode(ut.first, t, isPropertyType), parseNode(ut.rest, t, isPropertyType)]);
    }
    else if (node.type == "parens") {
        var ps = node;
        var rs = parseNode(ps.expr, t, isPropertyType);
        return wrapArray(ps.arr, rs);
    }
    else {
        var lit = node;
        if (lit.value.charAt(lit.value.length - 1) == '?') {
            var result = getFromRegistry(t, lit.value.substr(0, lit.value.length - 1), isPropertyType);
            if (!result) {
                result = ts.derive(lit.value, [ts.UNKNOWN]);
            }
            result = ts.union(lit.value, [result, ts.NIL]);
            var a = lit.arr;
            return wrapArray(a, result);
        }
        var result = getFromRegistry(t, lit.value, isPropertyType);
        if (!result) {
            result = ts.derive(lit.value, [ts.UNKNOWN]);
            var chained = t.getByChain(lit.value);
            if (chained) {
                result.addMeta(new metainfo_1.ImportedByChain(lit.value));
            }
        }
        var a = lit.arr;
        return wrapArray(a, result);
    }
}
function getFromRegistry(t, name, isPropertyType) {
    if (_parse.AccumulatingRegistry.isInstance(t)) {
        return t.get(name, isPropertyType);
    }
    return t.get(name);
}
function storeToString(t) {
    if (t.isSubTypeOf(ts.ARRAY)) {
        var cm = t.oneMeta(restrictions_1.ComponentShouldBeOfType);
        if (cm) {
            if (cm.value().isUnion()) {
                return "(" + storeToString(cm.value()) + ")" + "[]";
            }
            else
                return storeToString(cm.value()) + "[]";
        }
        return "array";
    }
    if (t instanceof ts.UnionType) {
        var ut = t;
        return ut.options().map(function (x) { return storeToString(x); }).join(" | ");
    }
    if (t.isAnonymous()) {
        if (t.isEmpty()) {
            return t.superTypes().map(function (x) { return storeToString(x); }).join(" , ");
        }
    }
    return t.name();
}
exports.storeToString = storeToString;
function visit(node, action) {
    action(node);
    if (node.type == "union") {
        var union = node;
        visit(union.first, action);
        visit(union.rest, action);
    }
    else if (node.type == "parens") {
        var parens = node;
        visit(parens.expr, action);
    }
}
exports.visit = visit;
function serializeToString(node) {
    var arr = 0;
    var str;
    if (node.type == "name") {
        var literal = node;
        str = literal.value;
        arr = literal.arr;
    }
    else if (node.type == "union") {
        var union = node;
        str = serializeToString(union.first) + " | " + serializeToString(union.rest);
    }
    else if (node.type == "parens") {
        var parens = node;
        str = "(" + serializeToString(parens.expr) + ")";
        arr = parens.arr;
    }
    while (--arr >= 0) {
        str += "[]";
    }
    return str;
}
exports.serializeToString = serializeToString;
function parse(str) {
    var result = typeExpression.parse(str);
    result = checkNil(result);
    return result;
}
exports.parse = parse;
function checkNil(node) {
    if (node.type == "name") {
        var lit = node;
        var value = lit.value;
        if (value && value.length && value.charAt(value.length - 1) == "?") {
            var rValue = value.substring(0, value.length - 1);
            var rExpr = parse(rValue);
            var result = {
                type: "union",
                first: rExpr,
                rest: {
                    type: "name",
                    value: "nil"
                }
            };
            if (typeof lit.arr === "number" && lit.arr > 0) {
                result = {
                    type: "parens",
                    expr: result,
                    arr: lit.arr
                };
            }
            return result;
        }
        else {
            return lit;
        }
    }
    else if (node.type == "union") {
        var union = node;
        union.first = checkNil(union.first);
        union.rest = checkNil(union.rest);
    }
    else if (node.type == "parens") {
        var parens = node;
        parens.expr = checkNil(parens.expr);
    }
    return node;
}
//# sourceMappingURL=typeExpressions.js.map