import { BaseVisitor } from "@wapc/widl/ast";
import { expandType, isReference, capitalize, isVoid, mapArgs, defaultValueForType, } from "./helpers";
import { shouldIncludeHandler } from "../utils";
export class ScaffoldVisitor extends BaseVisitor {
    constructor(writer) {
        super(writer);
    }
    visitDocumentBefore(context) {
        var _a;
        super.visitDocumentBefore(context);
        const types = new TypesVisitor(this.writer);
        (_a = context.document) === null || _a === void 0 ? void 0 : _a.accept(context, types);
    }
    visitAllOperationsBefore(context) {
        const registration = new HandlerRegistrationVisitor(this.writer);
        context.document.accept(context, registration);
    }
    visitOperation(context) {
        if (!shouldIncludeHandler(context)) {
            return;
        }
        const operation = context.operation;
        this.write(`\n`);
        this.write(`function ${operation.name.value}(${mapArgs(operation.arguments)}): ${expandType(operation.type, true, isReference(operation.annotations))} {\n`);
        if (!isVoid(operation.type)) {
            const dv = defaultValueForType(operation.type);
            this.write(`  return ${dv};`);
        }
        this.write(`// TODO: Provide implementation.\n`);
        this.write(`}\n`);
    }
    visitDocumentAfter(context) {
        this.write(`\n`);
        this.write(`// Boilerplate code for waPC.  Do not remove.\n\n`);
        this.write(`import { handleCall, handleAbort } from "@wapc/as-guest";\n\n`);
        this
            .write(`export function __guest_call(operation_size: usize, payload_size: usize): bool {
  return handleCall(operation_size, payload_size);
}

// Abort function
function abort(
  message: string | null,
  fileName: string | null,
  lineNumber: u32,
  columnNumber: u32
): void {
  handleAbort(message, fileName, lineNumber, columnNumber);
}\n`);
    }
}
class HandlerRegistrationVisitor extends BaseVisitor {
    constructor(writer) {
        super(writer);
    }
    visitAllOperationsBefore(context) {
        this.write(`export function wapc_init(): void {\n`);
    }
    visitOperation(context) {
        if (!shouldIncludeHandler(context)) {
            return;
        }
        const operation = context.operation;
        this.write(`  Handlers.register${capitalize(operation.name.value)}(${operation.name.value});\n`);
    }
    visitAllOperationsAfter(context) {
        this.write(`}\n`);
    }
}
class TypesVisitor extends BaseVisitor {
    constructor() {
        super(...arguments);
        this.hasOperations = false;
        this.hasObjects = false;
    }
    visitOperation(context) {
        if (shouldIncludeHandler(context)) {
            this.hasOperations = true;
        }
    }
    visitObject(context) {
        if (!this.hasObjects) {
            this.write(`import { `);
            this.hasObjects = true;
        }
        else {
            this.write(`, `);
        }
        this.write(`${context.object.name.value}`);
    }
    visitObjectsAfter(context) {
        if (this.hasOperations == true) {
            if (!this.hasObjects) {
                this.write(`import { `);
            }
            const className = context.config.handlersClassName || "Handlers";
            if (this.hasObjects) {
                this.write(`, `);
            }
            this.write(`${className}`);
            this.hasObjects = true;
        }
        if (this.hasObjects) {
            const packageName = context.config.package || "./module";
            this.write(` } from "${packageName}";\n\n`);
        }
    }
}
//# sourceMappingURL=scaffold_visitor.js.map