import { Description } from "./Description.js";
import { SelfDescribingValueIterator } from "./SelfDescribingValueIterator.js";


function descriptionOf(value) {
    try {
        return String(value);
    } catch (e) {
        return 'VALUE@0';
    }
}

/**
 *
 * @param {number} value
 * @return {string}
 */
function formatNumber(value) {
    return String(value);
}


export class BaseDescription extends Description {
    appendDescriptionOf(value) {
        value.describeTo(this);
        return this;
    }

    #toJavaScriptSyntax(unformatted) {
        this.appendText('"');

        // TODO escape string
        this.appendText(unformatted);

        this.appendText('"');
    }

    appendValue(value) {
        if (value == null) {
            this.appendText("null");
        } else if (value === undefined) {
            this.appendText("undefined");
        } else if (typeof value === "string") {
            this.#toJavaScriptSyntax(value);
        } else if (typeof value === "number") {
            this.appendText(formatNumber(value));
        } else if (Array.isArray(value)) {
            this.appendValueList("[", ", ", "]", value);
        } else {
            this.appendText('<');
            this.appendText(descriptionOf(value));
            this.appendText('>');
        }
        return this;
    }

    appendValueList(start, separator, end, values) {
        this.appendList(start, separator, end, new SelfDescribingValueIterator(values));
        return this;
    }

    appendList(start, separator, end, values) {
        let separate = false;

        this.appendText(start);

        /**
         *
         */
        const iterator = values[Symbol.iterator]();

        for (let i = iterator.next(); i.done !== true; i = iterator.next()) {
            if (separate) {
                this.appendText(separator);
            }

            this.appendDescriptionOf(i.value);
            separate = true;
        }

        this.appendText(end);

        return this;
    }
}
