import { BinaryClassSerializationAdapter } from "../storage/binary/BinaryClassSerializationAdapter.js";
import GUIElement, { GUIElementFlag } from "./GUIElement.js";

export class GUIElementSerializationAdapter extends BinaryClassSerializationAdapter {

    klass = GUIElement;
    version = 0;

    /**
     *
     * @param {BinaryBuffer} buffer
     * @param {GUIElement} value
     */
    serialize(buffer, value) {

        if (!value.getFlag(GUIElementFlag.Managed)) {
            throw new Error(`Expected 'Managed' flag to be set, instead it was cleared. Cannot serialize un-managed component`);
        }

        value.anchor.toBinaryBufferFloat32(buffer);
        buffer.writeUTF8String(value.group);

        buffer.writeUint8(value.visible.getValue() ? 1 : 0);

        buffer.writeUTF8String(value.klass);
        //write parameters

        const paramKeys = Object.keys(value.parameters);

        const numParamKeys = paramKeys.length;
        buffer.writeUintVar(numParamKeys);

        for (let i = 0; i < numParamKeys; i++) {
            const paramKey = paramKeys[i];

            buffer.writeUTF8String(paramKey);

            const parameter = value.parameters[paramKey];

            const paramType = typeof parameter;

            if (paramType === "number") {
                buffer.writeUint8(1);

                buffer.writeFloat64(parameter);
            } else if (paramType === "boolean") {
                buffer.writeUint8(2);

                buffer.writeUint8(parameter ? 1 : 0);
            } else if (paramType === "string") {
                buffer.writeUint8(3);

                buffer.writeUTF8String(parameter);
            } else {
                throw new TypeError(`Unsupported parameter type ${paramType}`);
            }

        }
    }

    /**
     *
     * @param {BinaryBuffer} buffer
     * @param {GUIElement} value
     */
    deserialize(buffer, value) {
        value.anchor.fromBinaryBufferFloat32(buffer);

        value.group = buffer.readUTF8String();

        value.visible.set(buffer.readUint8() !== 0);

        value.klass = buffer.readUTF8String();

        const numParamKeys = buffer.readUintVar();

        const params = {};

        for (let i = 0; i < numParamKeys; i++) {
            //read key
            const paramKey = buffer.readUTF8String();

            //read type flag
            const paramTypeHeader = buffer.readUint8();

            let paramValue;
            if (paramTypeHeader === 1) {
                //number
                paramValue = buffer.readFloat64();
            } else if (paramTypeHeader === 2) {
                //boolean
                paramValue = buffer.readUint8() !== 0;
            } else if (paramTypeHeader === 3) {
                //string
                paramValue = buffer.readUTF8String();
            } else {
                throw new TypeError(`Unknown type header value '${paramTypeHeader}' for parameter key '${paramKey}'`);
            }

            params[paramKey] = paramValue;
        }

        value.parameters = params;
    }
}
