"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var _ = require("underscore");
var textutil = require("../../util/textutil");
var wrapper = require("../artifacts/raml10parser");
var messageRegistry = require("../../../resources/errorMessages");
var SchemaToModelGenerator = /** @class */ (function () {
    function SchemaToModelGenerator() {
    }
    SchemaToModelGenerator.prototype.generateText = function (schema) {
        var _this = this;
        var obj = JSON.parse(schema);
        var items = obj['items'];
        if (!items)
            return '';
        var text = '';
        var itemsArray = (items instanceof Array) ? items : [items];
        text += 'types:\n';
        itemsArray.forEach(function (e) {
            //console.log('Item: ' + e.title + ' ' + e.type);
            text += '  - ' + e.title + ':\n';
            text += _this.generateObj(e, 3);
        });
        return text;
    };
    SchemaToModelGenerator.prototype.generateObj = function (e, lev) {
        var text = '';
        text += textutil.indent(lev, 'type: ' + e.type) + '\n';
        if (!e.properties)
            return;
        text += textutil.indent(lev, 'properties:\n');
        //console.log('props: ' + e.properties);
        for (var name in e.properties) {
            //console.log('  property: ' + JSON.stringify(p));
            var p = e.properties[name];
            text += textutil.indent(lev + 1, name + ':\n');
            //console.log('  property ' + name + ': ' + p.type);
            if (p.type == 'object') {
                text += this.generateObj(p, lev + 2);
            }
            else {
                text += textutil.indent(lev + 2, 'type: ' + p.type) + '\n';
            }
        }
        return text;
    };
    SchemaToModelGenerator.prototype.generateTo = function (api, schema, title) {
        var _this = this;
        var obj = JSON.parse(schema);
        var items = obj['items'];
        if (!items) {
            if (obj.title)
                title = obj.title;
            //console.log('title: ' + title);
            var type = new wrapper.ObjectTypeDeclarationImpl(title);
            this.generateObjTo(type, obj);
            new wrapper.BasicSecuritySchemeImpl(api).addToProp(type, 'types');
            return [title];
        }
        else {
            var itemsArray = (items instanceof Array) ? items : [items];
            var types = [];
            itemsArray.forEach(function (e) {
                var type = new wrapper.ObjectTypeDeclarationImpl(e.title);
                _this.generateObjTo(type, e);
                new wrapper.BasicSecuritySchemeImpl(api).addToProp(type, 'types');
                types.push(e.title);
            });
            return types;
        }
    };
    SchemaToModelGenerator.prototype.generateObjTo = function (type, e) {
        type.setType(e.type);
        //console.log('type: ' + type.definition().name());
        //util.showTypeProperties(type.definition());
        //type.attrOrCreate('type').setValue(e.type);
        if (!e.properties)
            return;
        //text += textutil.indent(lev, 'properties:\n');
        //console.log('props: ' + e.properties);
        for (var name in e.properties) {
            var p = e.properties[name];
            var field = this.makeTypeField(name, p);
            if (p.type == 'array') {
                //this.generateItemsTo(<wrapper.ArrayFieldImpl>field, p);
            }
            //console.log('  property: ' + JSON.stringify(p));
            //text += textutil.indent(lev+1, name + ':\n');
            //console.log('  property ' + name + ': ' + p.type);
            type.addToProp(field, 'properties');
        }
    };
    SchemaToModelGenerator.prototype.makeTypeField = function (name, p) {
        var field = this.makeType(name, p.type);
        if (p.type)
            field.setType(p.type);
        if (p.type == 'number') {
            var n = field;
            if (p.minimum != undefined)
                (n).setMinimum(p.minimum);
            if (p.maximum != undefined)
                (n).setMaximum(p.maximum);
        }
        if (p.type == 'array') {
            var itype = p.items.type;
            field.setType(itype + '[]');
            var a = field;
            if (p.minItems != undefined)
                a.setMinItems(p.minItems);
            if (p.maxItems != undefined)
                a.setMaxItems(p.maxItems);
            if (p.uniqueItems != undefined)
                a.setUniqueItems(p.uniqueItems);
        }
        if (p.type == 'object') {
            this.generateObjTo(field, p);
        }
        return field;
    };
    SchemaToModelGenerator.prototype.makeType = function (name, type) {
        if (type == 'number')
            return new wrapper.NumberTypeDeclarationImpl(name);
        if (type == 'string')
            return new wrapper.StringTypeDeclarationImpl(name);
        if (type == 'array')
            return new wrapper.ArrayTypeDeclarationImpl(name);
        return new wrapper.ObjectTypeDeclarationImpl(name);
    };
    SchemaToModelGenerator.prototype.generateItemsTo = function (a, obj) {
        var items = obj['items'];
        if (!items)
            return;
        var itemsArray = (items instanceof Array) ? items : [items];
        itemsArray.forEach(function (item) {
            //TODO add items here
        });
    };
    return SchemaToModelGenerator;
}());
exports.SchemaToModelGenerator = SchemaToModelGenerator;
var ModelToSchemaGenerator = /** @class */ (function () {
    function ModelToSchemaGenerator() {
    }
    ModelToSchemaGenerator.prototype.generateSchema = function (node) {
        var obj = this.generateType(node);
        obj["$schema"] = "http://json-schema.org/draft-04/schema#";
        return obj;
    };
    ModelToSchemaGenerator.prototype.isSimpleType = function (name) {
        return name == 'string' || name == 'number' || name == 'boolean' || name == 'object';
    };
    ModelToSchemaGenerator.prototype.generateType = function (type) {
        var typelist = this.allTypes(type);
        var obj = {};
        obj.title = type.attrValue('name');
        var properties = {};
        if (type.attrValue('type')) {
            // support multiple inheritance
            var types = type.attributes('type');
            //var properties = {};
            var inherited = false;
            var simple = false;
            for (var i in types) {
                var typevalue = types[i].value();
                var ll = types[i].lowLevel();
                obj.type = '';
                if (ll.isValueInclude()) {
                    var schema = JSON.parse(typevalue);
                    obj.type = 'object';
                    obj.properties = schema.properties;
                }
                else {
                    //console.log('type value: ' + typevalue);
                    if (this.isSimpleType(typevalue)) {
                        obj.type = typevalue;
                        simple = true;
                        if (inherited)
                            throw new Error(messageRegistry.COULD_NOT_MIX_TYPES_INHERITANCE.message);
                    }
                    else {
                        var t = this.resolveType(type, typevalue);
                        if (t) {
                            var ppp = this.generateTypeExp(typevalue, typelist);
                            //console.log('res: ' + typevalue + '\n' + JSON.stringify(ppp));
                            //_.extend(properties, ppp.properties);
                            if (obj.properties) {
                                _.extend(obj.properties, ppp.properties);
                            }
                            else {
                                obj.properties = ppp.properties;
                            }
                            obj.type = 'object';
                            inherited = true;
                            if (simple)
                                throw new Error(messageRegistry.COULD_NOT_MIX_TYPES_INHERITANCE.message);
                        }
                        else {
                            var ppp = this.generateTypeExp(typevalue, typelist);
                            //console.log('xtype: ' + typevalue + '\n' + JSON.stringify(ppp));
                            obj.type = 'object';
                            inherited = true;
                            if (ppp.anyOf) {
                                obj.anyOf = ppp.anyOf;
                            }
                        }
                    }
                }
            }
        }
        else {
            obj.type = 'object';
        }
        //var ps = this.generateProperties(type);
        //this.generatePropertiesTo(properties, type);
        var ownProps = this.generateProperties(type);
        //_.extend(properties, ownProps);
        //if(Object.getOwnPropertyNames(properties).length > 0) {
        if (obj.properties) {
            //console.log('own.p : ' + obj.properties);
            //console.log('own: ' + JSON.stringify(ownProps));
            //console.log('obj.p1: ' + obj.properties);
            _.extend(obj.properties, ownProps);
            //console.log('obj.p2: ' + obj.properties);
            //console.log('own: ' + JSON.stringify(ownProps));
        }
        else {
            obj.properties = ownProps;
        }
        return obj;
    };
    ModelToSchemaGenerator.prototype.makeUnion = function (typelist, types) {
        var _this = this;
        var anyof = [];
        typelist.forEach(function (t) {
            t = t.trim();
            if (types[t]) {
                anyof.push({
                    type: 'object',
                    properties: _this.generateType(types[t]).properties
                });
            }
            else {
                anyof.push({ type: t });
            }
        });
        return anyof;
    };
    ModelToSchemaGenerator.prototype.generateTypeExp = function (type, types) {
        var obj = {};
        //console.log('type: ' + type);
        if (textutil.endsWith(type, '[]')) {
            obj.type = 'array';
            obj.items = { type: type.substring(0, type.length - 2) };
        }
        else if (type.indexOf('|') > 0) {
            var typelist = type.split('|');
            obj.anyOf = this.makeUnion(typelist, types);
        }
        else {
            if (types[type]) {
                var schema = this.generateType(types[type]);
                obj.type = 'object';
                obj.properties = schema.properties;
            }
            else {
                obj.type = type;
            }
        }
        return obj;
    };
    ModelToSchemaGenerator.prototype.allTypes = function (node) {
        var api = node.root();
        var modelTypes = api.elementsOfKind('types');
        var types = {};
        modelTypes.forEach(function (type) {
            //console.log('  types: ' + type.name());
            types[type.name()] = type;
        });
        return types;
    };
    ModelToSchemaGenerator.prototype.resolveType = function (node, name) {
        var types = this.allTypes(node);
        return types[name];
    };
    ModelToSchemaGenerator.prototype.generateProperty = function (node, optional) {
        var _this = this;
        var types = this.allTypes(node);
        var obj = {};
        var props = node.definition().allProperties();
        props.forEach(function (p) {
            if (p.nameId() == 'name')
                return;
            var value = node.attrValue(p.nameId());
            if (!(value != null && value != undefined && value != 'undefined'))
                return;
            if (p.nameId() == 'type') {
                var t = _this.generateTypeExp(value, types);
                _.extend(obj, t);
                //this.generatePropertyType(obj, value, types);
            }
            else if (p.nameId() == 'enum') {
                var values = node.attributes('enum');
                var arr = values.map(function (a) { return a.value(); });
                obj.enum = arr;
            }
            else {
                obj[p.nameId()] = value;
            }
        });
        if (optional)
            obj.required = false;
        var elements = node.elements();
        var properties = this.generateProperties(node);
        if (Object.getOwnPropertyNames(properties).length > 0) {
            obj.properties = properties;
        }
        return obj;
    };
    ModelToSchemaGenerator.prototype.generateProperties = function (node) {
        var _this = this;
        var props = {};
        var elements = node.elements();
        var empty = true;
        elements.forEach(function (p) {
            var name = p.attrValue('name');
            if (typeof name !== 'string') {
                return;
            }
            name = name.trim();
            var optional = p.optional();
            props[name] = _this.generateProperty(p, optional);
            empty = false;
        });
        return props;
    };
    return ModelToSchemaGenerator;
}());
exports.ModelToSchemaGenerator = ModelToSchemaGenerator;
//# sourceMappingURL=schemaModelGen.js.map