"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ts = require("./typesystem");
var restr = require("./restrictions");
var restrictions_1 = require("./restrictions");
var restrictions_2 = require("./restrictions");
var restrictions_3 = require("./restrictions");
var restrictions_4 = require("./restrictions");
var SchemaWriter = /** @class */ (function () {
    function SchemaWriter() {
        this.map = {};
        this.root = null;
    }
    SchemaWriter.prototype.generateRef = function (t) {
        if (!t) {
            return {};
        }
        if (t.isBuiltin()) {
            return {
                type: this.getType(t)
            };
        }
        else if (t.isAnonymous()) {
            return this.store(t);
        }
        if (t.isPolymorphic()) {
            var tf = t.typeFamily();
            var ut = ts.union(t.name() + "Polymorph", tf);
            return this.store(t);
        }
        var typeInfo = this.store(t);
        if ((!this.root.hasOwnProperty("definitions"))) {
            this.root["definitions"] = {};
        }
        var ob = this.root["definitions"];
        ob[t.name()] = typeInfo;
        return {
            $ref: "#/definitions/" + t.name()
        };
    };
    SchemaWriter.prototype.getType = function (t) {
        if (t.isArray()) {
            return "array";
        }
        else if (t.isBoolean()) {
            return "boolean";
        }
        else if (t.isString()) {
            return "string";
        }
        else if (t.isObject()) {
            return "object";
        }
        else if (t.isNumber()) {
            return "number";
        }
        else if (t.isScalar()) {
            return "string";
        }
        return "unknown";
    };
    SchemaWriter.prototype.getResult = function () {
        return this.root;
    };
    SchemaWriter.prototype.store = function (t) {
        var _this = this;
        if (t.isPolymorphic()) {
            var tf = t.typeFamily();
            var ut = ts.union(t.name() + "Polymorph", tf);
            return this.store(t);
        }
        var res = {};
        if (this.root == null) {
            this.root = res;
            res["$schema"] = "http://json-schema.org/draft-04/schema#";
        }
        var tv = this.getType(t);
        if (tv != null) {
            res["type"] = tv;
        }
        if (t.isArray()) {
            res["additionalItems"] = false;
        }
        if (t.isObject()) {
            res["additionalProperties"] = false;
        }
        if (t instanceof ts.InheritedType) {
            var options = this.options(t.superTypes(), true);
            var optimized = false;
            if (options.length == 1) {
                var m = options[0];
                if (Object.keys(m).length == 1) {
                    if (m["anyOf"]) {
                        res["anyOf"] = m["anyOf"];
                        optimized = true;
                    }
                }
            }
            if (options.length > 0 && !optimized) {
                res["allOf"] = options;
            }
        }
        if (t instanceof ts.UnionType) {
            var ut = t;
            res["anyOf"] = this.options(ut.allOptions(), true);
            //TODO port optimization
            return res;
        }
        var ms = t.meta();
        ms.forEach(function (x) {
            //FILL ME
        });
        var optimize = restr.optimize(t.restrictions());
        var pp = {};
        var properties = {};
        var required = [];
        optimize.forEach(function (x) {
            if (x instanceof restr.AdditionalPropertyIs) {
                var ap = x;
                if (ap.value() == ts.ANY) {
                    res["additionalProperties"] = true;
                }
                else {
                    res["additionalProperties"] = _this.generateRef(ap.value());
                }
            }
            if (x instanceof restrictions_1.MapPropertyIs) {
                var mp = x;
                if (mp.value() == ts.ANY) {
                    pp[mp.regexpValue()] = {};
                }
                else {
                    pp[mp.regexpValue()] = _this.generateRef(mp.value());
                }
            }
            if (x instanceof restrictions_2.ComponentShouldBeOfType) {
                var cs = x;
                res["items"] = _this.generateRef(cs.value());
                res["additionalItems"] = false;
            }
            if (x instanceof restrictions_3.PropertyIs) {
                var pi = x;
                properties[pi.propId()] = _this.generateRef(pi.value());
            }
            if (x instanceof restrictions_4.HasProperty) {
                var rr = x;
                required.push(rr.value());
            }
        });
        if (required.length > 0) {
            res["required"] = required;
        }
        if (Object.keys(properties).length > 0) {
            res["properties"] = properties;
        }
        if (Object.keys(pp).length > 0) {
            res["patternProperties"] = pp;
        }
        return res;
    };
    SchemaWriter.prototype.options = function (allOptions, noBuiltIn) {
        var _this = this;
        var res = [];
        allOptions.forEach(function (t) {
            if (t.isBuiltin() && noBuiltIn) {
                return;
            }
            res.push(_this.generateRef(t));
        });
        return res;
    };
    return SchemaWriter;
}());
exports.SchemaWriter = SchemaWriter;
//# sourceMappingURL=jsonSchemaWriter.js.map