"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getTreeNodeTypeNameFallback = exports.randomLiteralType = exports.MAP_TYPE_EXPRESSION_TO_LITERAL = void 0;
exports.getValue = getValue;
exports.mapTree = mapTree;
exports.randomValueOfObjectLiteral = randomValueOfObjectLiteral;
exports.randomTreeOfObjectLiteral = randomTreeOfObjectLiteral;
exports.randomValueOfArrayLiteral = randomValueOfArrayLiteral;
exports.randomTreeOfArrayLiteral = randomTreeOfArrayLiteral;
exports.randomValueOfTypeExpression = randomValueOfTypeExpression;
exports.randomTreeOfTypeExpression = randomTreeOfTypeExpression;
exports.randomValueOfOr = randomValueOfOr;
exports.randomTreeOfOr = randomTreeOfOr;
exports.randomValueOfAnd = randomValueOfAnd;
exports.randomTreeOfAnd = randomTreeOfAnd;
exports.randomValueOfType = randomValueOfType;
exports.randomTreeOfType = randomTreeOfType;
exports.randomTreeOfTypeLiteral = randomTreeOfTypeLiteral;
exports.randomValueOfTypeLiteral = randomValueOfTypeLiteral;
const parser_1 = require("../../spec/parser");
const array_1 = require("../../util/array");
const randomInArray_1 = require("../../util/array/randomInArray");
const object_1 = require("../../util/object");
function getValue({ value }) {
    return value;
}
function mapTree(values) {
    return values.map((v) => (0, parser_1.getTree)(v));
}
const TREE_VALUE_NUMBER = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const TREE_VALUE_STRING = [`'foo'`, `'bar'`, `'zaz'`];
const TREE_VALUE_BOOLEAN = ['true', 'false'];
const TREE_VALUE_OBJECT = ['{}'];
const TREE_VALUE_ARRAY = ['[]', '[0]', '[0,1,2]'];
const TREE_NUMBER = mapTree(TREE_VALUE_NUMBER);
const TREE_STRING = mapTree(TREE_VALUE_STRING);
const TREE_BOOLEAN = mapTree(TREE_VALUE_BOOLEAN);
const TREE_OBJECT = mapTree(TREE_VALUE_OBJECT);
const TREE_ARRAY = mapTree(TREE_VALUE_ARRAY);
const LITERAL_TREE_NODE_TYPE = [
    parser_1.TreeNodeType.Number,
    parser_1.TreeNodeType.String,
    parser_1.TreeNodeType.Boolean,
    parser_1.TreeNodeType.ObjectExpression,
    parser_1.TreeNodeType.ArrayExpression,
];
exports.MAP_TYPE_EXPRESSION_TO_LITERAL = {
    [parser_1.TreeNodeType.ArrayExpression]: parser_1.TreeNodeType.ArrayLiteral,
    [parser_1.TreeNodeType.ObjectExpression]: parser_1.TreeNodeType.ObjectLiteral,
};
const randomLiteralType = () => {
    return (0, randomInArray_1.randomInArray)(LITERAL_TREE_NODE_TYPE);
};
exports.randomLiteralType = randomLiteralType;
const getTreeNodeTypeNameFallback = (tree_node_type) => {
    switch (tree_node_type) {
        case parser_1.TreeNodeType.Number:
            return 'number';
        case parser_1.TreeNodeType.String:
            return 'string';
        case parser_1.TreeNodeType.Boolean:
            return 'boolean';
        case parser_1.TreeNodeType.ObjectExpression:
            return 'string{}';
        case parser_1.TreeNodeType.ArrayExpression:
            return 'number[]';
    }
};
exports.getTreeNodeTypeNameFallback = getTreeNodeTypeNameFallback;
function randomValueOfObjectLiteral(specs, typeTree) {
    return getValue(randomTreeOfObjectLiteral(specs, typeTree));
}
function randomTreeOfObjectLiteral(specs, typeTree) {
    const children = [];
    for (const type_key_value of typeTree.children) {
        const [type_key_tree, type_value_tree] = type_key_value.children;
        if (type_value_tree.type === parser_1.TreeNodeType.Invalid) {
            continue;
        }
        const { value: key } = type_key_tree;
        let _key = key;
        let value_tree;
        if (key.endsWith('?')) {
            if (Math.random() > 0.5) {
                _key = key.substr(0, key.length - 1);
                value_tree = randomTreeOfType(specs, type_value_tree);
            }
        }
        else {
            value_tree = randomTreeOfType(specs, type_value_tree);
        }
        if (value_tree) {
            const key_tree = (0, parser_1.getTree)(_key);
            const key_value_tree = {
                value: `${key_tree.value}:${value_tree.value}`,
                children: [key_tree, value_tree],
                type: parser_1.TreeNodeType.KeyValue,
            };
            children.push(key_value_tree);
        }
    }
    return {
        value: `{${children.map(getValue).join(',')}}`,
        children,
        type: parser_1.TreeNodeType.ObjectLiteral,
    };
}
function randomValueOfArrayLiteral(specs, tree_type) {
    return getValue(randomTreeOfArrayLiteral(specs, tree_type));
}
function randomTreeOfArrayLiteral(specs, tree_type) {
    const children = [];
    for (const type_child of tree_type.children) {
        const child_tree = randomTreeOfType(specs, type_child);
        children.push(child_tree);
    }
    return {
        value: `[${children.map(getValue).join(',')}]`,
        type: parser_1.TreeNodeType.ArrayLiteral,
        children,
    };
}
function randomValueOfTypeExpression(specs, typeTree, delimiter_open, delimiter_close) {
    return getValue(randomTreeOfTypeExpression(specs, typeTree, delimiter_open, delimiter_close));
}
function randomTreeOfTypeExpression(specs, typeTree, delimiter_open, delimiter_close) {
    const { children: type_children, type: type_type } = typeTree;
    const type_typeTree = type_children[0];
    const generics = (0, parser_1._findGenerics)(type_typeTree);
    const generic_type_map = {};
    if (generics.size > 0) {
        for (const generic of generics) {
            const chosen_tree_type = (0, randomInArray_1.randomInArray)(LITERAL_TREE_NODE_TYPE);
            const chosen_type = (0, exports.getTreeNodeTypeNameFallback)(chosen_tree_type);
            generic_type_map[generic] = chosen_type;
        }
    }
    const literal_typeTree = (0, parser_1._applyGenerics)(type_typeTree, generic_type_map);
    const size = Math.floor(Math.random() * 3);
    const range = (0, array_1.rangeArray)(size);
    const children = range.map(() => randomTreeOfType(specs, literal_typeTree));
    const value = `${delimiter_open}${children
        .map(getValue)
        .join(',')}${delimiter_close}`;
    const type = exports.MAP_TYPE_EXPRESSION_TO_LITERAL[type_type];
    return {
        value,
        children,
        type,
    };
}
function randomValueOfOr(specs, tree) {
    return (0, randomInArray_1.randomInArray)(tree.children.map((c) => randomValueOfType(specs, c)));
}
function randomTreeOfOr(specs, tree) {
    const { children } = tree;
    const child = (0, randomInArray_1.randomInArray)(children);
    return randomTreeOfType(specs, child);
}
function randomValueOfAnd(typeTree) {
    return getValue(randomTreeOfAnd(typeTree));
}
function randomTreeOfAnd(typeTree) {
    // TODO
    return parser_1.NULL_TREE;
}
function randomValueOfType(specs, typeTree) {
    const randomTree = randomTreeOfType(specs, typeTree);
    if (randomTree) {
        return getValue(randomTree);
    }
    else {
        return null;
    }
}
function randomTreeOfType(specs, typeTree) {
    const { type } = typeTree;
    if ((0, parser_1.isLiteralType)(type)) {
        return typeTree;
    }
    if (type === parser_1.TreeNodeType.Or) {
        return randomTreeOfOr(specs, typeTree);
    }
    else if (type === parser_1.TreeNodeType.And) {
        return randomTreeOfAnd(typeTree);
    }
    else if (type === parser_1.TreeNodeType.ObjectLiteral) {
        return randomTreeOfObjectLiteral(specs, typeTree);
    }
    else if (type === parser_1.TreeNodeType.ArrayLiteral) {
        return randomTreeOfArrayLiteral(specs, typeTree);
    }
    else if (type === parser_1.TreeNodeType.ArrayExpression) {
        return randomTreeOfTypeExpression(specs, typeTree, '[', ']');
    }
    else if (type === parser_1.TreeNodeType.ObjectExpression) {
        return randomTreeOfTypeExpression(specs, typeTree, '{', '}');
    }
    else if (type === parser_1.TreeNodeType.Class) {
        const filteredSpecs = (0, object_1.values)(specs).filter((spec) => {
            var _a;
            return (0, parser_1.isTypeMatch)(specs, (_a = spec.type) !== null && _a !== void 0 ? _a : `G`, typeTree.value);
        });
        const randomSpec = (0, randomInArray_1.randomInArray)(filteredSpecs);
        if (randomSpec) {
            return (0, parser_1.getTree)(`\${unit:{id:"${randomSpec.id}"}}`);
        }
        else {
            return null;
        }
    }
    else {
        return randomTreeOfTypeLiteral(specs, type);
    }
}
function randomTreeOfTypeLiteral(specs, type) {
    if (type === parser_1.TreeNodeType.Number) {
        return (0, randomInArray_1.randomInArray)(TREE_NUMBER);
    }
    else if (type === parser_1.TreeNodeType.String) {
        return (0, randomInArray_1.randomInArray)(TREE_STRING);
    }
    else if (type === parser_1.TreeNodeType.Boolean) {
        return (0, randomInArray_1.randomInArray)(TREE_BOOLEAN);
    }
    else if (type === parser_1.TreeNodeType.Object) {
        return (0, randomInArray_1.randomInArray)(TREE_OBJECT);
    }
    else if (type === parser_1.TreeNodeType.Generic) {
        return randomTreeOfTypeLiteral(specs, (0, exports.randomLiteralType)());
    }
    else if (type === parser_1.TreeNodeType.Any) {
        return randomTreeOfTypeLiteral(specs, (0, randomInArray_1.randomInArray)(LITERAL_TREE_NODE_TYPE));
    }
    return parser_1.NULL_TREE;
}
function randomValueOfTypeLiteral(specs, typeTree) {
    return getValue(randomTreeOfTypeLiteral(specs, typeTree));
}
//# sourceMappingURL=randomValue.js.map