"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateClass = exports.visitClass = exports.visitType = exports.fixupType = exports.isTypeUsable = exports.findKnownType = void 0;
const tslib_1 = require("tslib");
/* eslint-disable no-param-reassign */
const typescript_1 = tslib_1.__importStar(require("typescript"));
const core_1 = require("@il2js/core");
const Constants_1 = require("./Constants");
// eslint-disable-next-line import/no-cycle
const MemberHelpers_1 = require("./MemberHelpers");
function findKnownType(type, context) {
    return context.types.findType(type);
}
exports.findKnownType = findKnownType;
function isTypeUsable(type, context) {
    var _a;
    if (type.IsPrimitive) {
        return true;
    }
    const name = context.types.getTypeName(type, context);
    if (!Constants_1.BuiltinTypes[name] && !context.types.hasType(type)) {
        return false;
    }
    if ((_a = type.TypeArguments) === null || _a === void 0 ? void 0 : _a.length) {
        return type.TypeArguments.every((t) => isTypeUsable(t, context));
    }
    return true;
}
exports.isTypeUsable = isTypeUsable;
function fixupType(typeDef) {
    if (typeDef.IsArray) {
        typeDef.IsArray = false; // don't recurse :)
        typeDef = Constants_1.BuiltinTypes.ManagedArray(typeDef);
    }
    if (typeDef.IsPrimitive && typeDef.TypeName === 'object') {
        return Constants_1.BuiltinTypes.UnknownObject;
    }
    if (typeDef.TypeArguments) {
        typeDef.TypeArguments = typeDef.TypeArguments.map((typeArg) => fixupType(typeArg));
    }
    return typeDef;
}
exports.fixupType = fixupType;
function visitType(typeDef, context) {
    if (!typeDef)
        return undefined;
    if (typeDef.BaseType && !isTypeUsable(typeDef.BaseType, context)) {
        typeDef.BaseType = undefined;
    }
    if (typeDef.DeclaringType && !isTypeUsable(typeDef.DeclaringType, context)) {
        typeDef.DeclaringType = undefined;
    }
    if (typeDef.TypeArguments) {
        typeDef.TypeArguments = typeDef.TypeArguments.map((typeArg) => fixupType(typeArg));
    }
    return fixupType(typeDef);
}
exports.visitType = visitType;
function visitClass(typeDef, context) {
    if (!typeDef)
        return undefined;
    const type = visitType(typeDef.Type, context);
    if (!type)
        return undefined;
    typeDef.Type = type;
    if (typeDef.Fields) {
        // MODIFY and filter:
        typeDef.Fields = typeDef.Fields.filter((field) => {
            const fieldType = visitType(field.Type, context);
            if (!fieldType) {
                return false;
            }
            field.Type = fieldType;
            return isTypeUsable(field.Type, context);
        });
    }
    if (typeDef.StaticFields) {
        typeDef.StaticFields = typeDef.StaticFields.filter((field) => {
            const fieldType = visitType(field.Type, context);
            if (!fieldType) {
                return false;
            }
            field.Type = fieldType;
            return isTypeUsable(field.Type, context);
        });
    }
    if (typeDef.NestedTypes) {
        typeDef.NestedTypes = core_1.excludeUndefined(typeDef.NestedTypes.map((nestedType) => visitClass(nestedType, context)));
    }
    return typeDef;
}
exports.visitClass = visitClass;
function generateClass(typeDef, context) {
    const def = context ? visitClass(typeDef, context) : typeDef;
    if (!def) {
        return undefined;
    }
    const { className, typeParameters, heritage, members } = MemberHelpers_1.generateClassData(typeDef, context);
    const classDecl = typescript_1.factory.createClassDeclaration(undefined, typescript_1.factory.createModifiersFromModifierFlags(typescript_1.default.ModifierFlags.Export), className, typeParameters, heritage, members);
    return classDecl;
}
exports.generateClass = generateClass;
//# sourceMappingURL=StructHelpers.js.map