// Copyright 2020 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

// Provide host with details about funcs and views in this smart contract

import {ScFuncContext, ScViewContext} from "./context";
import {exportName} from "./host";

// Note that we do not use the Wasm export symbol table on purpose
// because Wasm does not allow us to determine whether the symbols
// are meant as view or func, or meant as extra public callbacks
// generated by the compilation of the the Wasm code.
// There are only 2 symbols the ISC host will actually look for
// in the export table:
// on_load (which must be defined by the SC code) and
// on_call (which is defined here as part of WasmLib)

export type ScFuncContextFunc = (f: ScFuncContext) => void;
export type ScViewContextFunc = (v: ScViewContext) => void;

export class ScExportMap {
    names: string[];
    funcs: ScFuncContextFunc[];
    views: ScViewContextFunc[];
}

// \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\ // \\

// context for onLoad function to be able to tell host which
// funcs and views are available as entry points to the SC
export class ScExports {
    // constructs the symbol export context for the onLoad function
    static export(exportMap: ScExportMap): void {
        exportName(-1, "WASM::TYPESCRIPT");

        for (let i = 0; i < exportMap.funcs.length; i++) {
            exportName(i as i32, exportMap.names[i]);
        }

        let offset = exportMap.funcs.length;
        for (let i = 0; i < exportMap.views.length; i++) {
            exportName((i as i32) | 0x8000, exportMap.names[offset + i]);
        }
    }

    // general entrypoint for the host to call any SC function
    // the host will pass the index of one of the entry points
    // that was provided by onLoad during SC initialization
    static call(index: i32, exportMap: ScExportMap): void {
        if ((index & 0x8000) == 0) {
            // mutable full function, invoke with a func context
            let func = exportMap.funcs[index];
            func(new ScFuncContext());
            return;
        }
        // immutable view function, invoke with a view context
        let view = exportMap.views[index & 0x7fff];
        view(new ScViewContext());
    }
}

