"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateFieldAccessor = exports.generateReadFieldCall = exports.generateReadPrimitiveCall = void 0;
const tslib_1 = require("tslib");
const typescript_1 = tslib_1.__importStar(require("typescript"));
const core_1 = require("@il2js/core");
// eslint-disable-next-line import/no-cycle
const TypeNameHelpers_1 = require("./TypeNameHelpers");
const TypeMappings_1 = require("../TypeMappings");
const Utilities_1 = require("../../../Utilities");
function generateReadPrimitiveCall(field) {
    return typescript_1.factory.createCallExpression(typescript_1.factory.createPropertyAccessExpression(typescript_1.factory.createThis(), typescript_1.factory.createIdentifier('readTypePrimitive')), undefined, [
        // args (offset, type)
        typescript_1.factory.createNumericLiteral(field.Offset),
        typescript_1.factory.createStringLiteral(field.Type.TypeName),
        typescript_1.factory.createNumericLiteral(field.Type.Indirection),
    ]);
}
exports.generateReadPrimitiveCall = generateReadPrimitiveCall;
function typeArgumentsToParameters(typeArguments, context, relativeTo) {
    var _a;
    const parameters = [];
    for (const tArg of typeArguments) {
        if ((_a = tArg.TypeArguments) === null || _a === void 0 ? void 0 : _a.length) {
            parameters.push(typescript_1.factory.createCallExpression(typescript_1.factory.createIdentifier('bindTypeArgs'), undefined, [
                TypeNameHelpers_1.generateTypePath(tArg, typescript_1.factory.createPropertyAccessExpression, context, relativeTo),
                ...typeArgumentsToParameters(tArg.TypeArguments, context, relativeTo),
            ]));
        }
        else if (tArg.IsPrimitive) {
            parameters.push(typescript_1.factory.createStringLiteral(tArg.TypeName));
        }
        else {
            parameters.push(TypeNameHelpers_1.generateTypePath(tArg, typescript_1.factory.createPropertyAccessExpression, context, relativeTo));
        }
    }
    core_1.assert(parameters.length === typeArguments.length);
    return parameters;
}
function generateReadFieldCall(field, context, relativeTo) {
    const parameters = [
        // args (offset, type)
        typescript_1.factory.createNumericLiteral(field.Offset),
        TypeNameHelpers_1.generateTypePath(field.Type, typescript_1.factory.createPropertyAccessExpression, context, relativeTo),
        typescript_1.factory.createNumericLiteral(field.Type.Indirection),
    ];
    if (field.Type.TypeArguments) {
        parameters.push(...typeArgumentsToParameters(field.Type.TypeArguments, context, relativeTo));
    }
    return typescript_1.factory.createCallExpression(typescript_1.factory.createPropertyAccessExpression(typescript_1.factory.createThis(), typescript_1.factory.createIdentifier('readField')), undefined, parameters);
}
exports.generateReadFieldCall = generateReadFieldCall;
function generateFieldAccessor(field, context, relativeTo, isStatic) {
    const isPrimitiveType = field.Type.IsPrimitive;
    const callExpr = isPrimitiveType
        ? generateReadPrimitiveCall(field)
        : generateReadFieldCall(field, context, relativeTo);
    let returnType;
    if (isPrimitiveType) {
        returnType = typescript_1.factory.createTypeReferenceNode(TypeMappings_1.getTypeMapping(field.Type.TypeName));
    }
    else {
        returnType = TypeNameHelpers_1.generateTypeReference(field.Type, context, relativeTo);
    }
    return typescript_1.factory.createGetAccessorDeclaration(undefined, 
    // modifiers
    typescript_1.factory.createModifiersFromModifierFlags(typescript_1.default.ModifierFlags.Public | (isStatic ? typescript_1.default.ModifierFlags.Static : 0)), 
    // field name
    Utilities_1.fixName(field.Name), 
    // parameters
    [], 
    // return type
    returnType, 
    // method body
    typescript_1.factory.createBlock([typescript_1.factory.createReturnStatement(callExpr)], true));
}
exports.generateFieldAccessor = generateFieldAccessor;
//# sourceMappingURL=FieldHelpers.js.map