"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.randomValueOfTypeLiteral = exports.randomTreeOfTypeLiteral = exports.randomTreeOfType = exports.randomValueOfType = exports.randomTreeOfAnd = exports.randomValueOfAnd = exports.randomTreeOfOr = exports.randomValueOfOr = exports.randomTreeOfTypeExpression = exports.randomValueOfTypeExpression = exports.randomTreeOfArrayLiteral = exports.randomValueOfArrayLiteral = exports.randomTreeOfObjectLiteral = exports.randomValueOfObjectLiteral = exports.getTreeNodeTypeName = exports.randomLiteralType = exports.MAP_TYPE_EXPRESSION_TO_LITERAL = exports.mapTree = exports.propValue = void 0;
const randomInArray_1 = require("../../client/id/randomInArray");
const parser_1 = require("../../spec/parser");
const f_1 = require("../../system/f/object/Keys/f");
const array_1 = require("../../util/array");
function propValue({ value }) {
    return value;
}
exports.propValue = propValue;
function mapTree(values) {
    return values.map((v) => (0, parser_1.getTree)(v));
}
exports.mapTree = mapTree;
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 = ['{}', '{foo:"bar"}'];
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 getTreeNodeTypeName = (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{}'; // TODO
        case parser_1.TreeNodeType.ArrayExpression:
            return 'number[]'; // TODO
    }
};
exports.getTreeNodeTypeName = getTreeNodeTypeName;
function randomValueOfObjectLiteral(specs, type_tree) {
    return propValue(randomTreeOfObjectLiteral(specs, type_tree));
}
exports.randomValueOfObjectLiteral = randomValueOfObjectLiteral;
function randomTreeOfObjectLiteral(specs, type_tree) {
    const children = [];
    for (const type_key_value of type_tree.children) {
        const [type_key_tree, type_value_tree] = type_key_value.children;
        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(propValue).join(',')}}`,
        children,
        type: parser_1.TreeNodeType.ObjectLiteral,
    };
}
exports.randomTreeOfObjectLiteral = randomTreeOfObjectLiteral;
function randomValueOfArrayLiteral(specs, tree_type) {
    return propValue(randomTreeOfArrayLiteral(specs, tree_type));
}
exports.randomValueOfArrayLiteral = randomValueOfArrayLiteral;
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(propValue).join(',')}]`,
        type: parser_1.TreeNodeType.ArrayLiteral,
        children,
    };
}
exports.randomTreeOfArrayLiteral = randomTreeOfArrayLiteral;
function randomValueOfTypeExpression(specs, type_tree, delimiter_open, delimiter_close) {
    return propValue(randomTreeOfTypeExpression(specs, type_tree, delimiter_open, delimiter_close));
}
exports.randomValueOfTypeExpression = randomValueOfTypeExpression;
function randomTreeOfTypeExpression(specs, type_tree, delimiter_open, delimiter_close) {
    const { children: type_children, type: type_type } = type_tree;
    const type_type_tree = type_children[0];
    const generics = (0, parser_1._findGenerics)(type_type_tree);
    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.getTreeNodeTypeName)(chosen_tree_type);
            generic_type_map[generic] = chosen_type;
        }
    }
    const literal_type_tree = (0, parser_1._applyGenerics)(type_type_tree, generic_type_map);
    const size = Math.floor(Math.random() * 3);
    const range = (0, array_1.rangeArray)(size);
    const children = range.map(() => randomTreeOfType(specs, literal_type_tree));
    const value = `${delimiter_open}${children
        .map(propValue)
        .join(',')}${delimiter_close}`;
    const type = exports.MAP_TYPE_EXPRESSION_TO_LITERAL[type_type];
    return {
        value,
        children,
        type,
    };
}
exports.randomTreeOfTypeExpression = randomTreeOfTypeExpression;
function randomValueOfOr(specs, tree) {
    return (0, randomInArray_1.randomInArray)(tree.children.map((c) => randomValueOfType(specs, c)));
}
exports.randomValueOfOr = randomValueOfOr;
function randomTreeOfOr(specs, tree) {
    const { children } = tree;
    const child = (0, randomInArray_1.randomInArray)(children);
    return randomTreeOfType(specs, child);
}
exports.randomTreeOfOr = randomTreeOfOr;
function randomValueOfAnd(type_tree) {
    return propValue(randomTreeOfAnd(type_tree));
}
exports.randomValueOfAnd = randomValueOfAnd;
function randomTreeOfAnd(type_tree) {
    // TODO
    return parser_1.NULL_TREE;
}
exports.randomTreeOfAnd = randomTreeOfAnd;
function randomValueOfType(specs, type_tree) {
    return propValue(randomTreeOfType(specs, type_tree));
}
exports.randomValueOfType = randomValueOfType;
function randomTreeOfType(specs, type_tree) {
    const { type } = type_tree;
    if ((0, parser_1.isLiteralType)(type)) {
        return type_tree;
    }
    if (type === parser_1.TreeNodeType.Or) {
        return randomTreeOfOr(specs, type_tree);
    }
    else if (type === parser_1.TreeNodeType.And) {
        return randomTreeOfAnd(type_tree);
    }
    else if (type === parser_1.TreeNodeType.ObjectLiteral) {
        return randomTreeOfObjectLiteral(specs, type_tree);
    }
    else if (type === parser_1.TreeNodeType.ArrayLiteral) {
        return randomTreeOfArrayLiteral(specs, type_tree);
    }
    else if (type === parser_1.TreeNodeType.ArrayExpression) {
        return randomTreeOfTypeExpression(specs, type_tree, '[', ']');
    }
    else if (type === parser_1.TreeNodeType.ObjectExpression) {
        return randomTreeOfTypeExpression(specs, type_tree, '{', '}');
    }
    else {
        return randomTreeOfTypeLiteral(specs, type);
    }
}
exports.randomTreeOfType = randomTreeOfType;
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.Class) {
        return (0, parser_1.getTree)(`\${unit:{id:"${(0, randomInArray_1.randomInArray)((0, f_1.keys)(specs))}"}}`);
    }
    else if (type === parser_1.TreeNodeType.Any) {
        return randomTreeOfTypeLiteral(specs, (0, randomInArray_1.randomInArray)(LITERAL_TREE_NODE_TYPE));
    }
    return parser_1.NULL_TREE;
}
exports.randomTreeOfTypeLiteral = randomTreeOfTypeLiteral;
function randomValueOfTypeLiteral(specs, type_tree) {
    return propValue(randomTreeOfTypeLiteral(specs, type_tree));
}
exports.randomValueOfTypeLiteral = randomValueOfTypeLiteral;
//# sourceMappingURL=randomValue.js.map