package ru.yandex.autodoc.common.out.json.builder;

import ru.yandex.autodoc.common.out.json.JsonObjectWriter;
import ru.yandex.autodoc.common.util.enums.IEnumResolver;

import java.text.DateFormat;
import java.text.DecimalFormat;
import java.util.Date;

/**
 * @author avhaliullin
 */
public class JsonObjectBuilder<C extends ContainerBuilder>
        extends ContainerBuilder {
    private final C container;
    private boolean empty;
    private final boolean handleLifecycle;

    JsonObjectBuilder(JsonAppendable appendable, C container, boolean handleLifecycle, boolean createEmpty) {
        super(appendable);
        this.handleLifecycle = handleLifecycle;
        empty = createEmpty;
        this.container = container;
        if (handleLifecycle) {
            appendable.startObject();
        }
    }

    public JsonValueBuilder<JsonObjectBuilder<C>> key(String key) {
        return key(key, null);
    }

    public JsonValueBuilder<JsonObjectBuilder<C>> key(String key, String description) {
        assertState(State.READY);
        state = State.FOCUS_LOOSE;

        if (!empty) {
            appendable.appendComma();
        }
        empty = false;
        appendable.appendKey(key);
        appendable.commentForLastKey(description);
        return new JsonValueBuilder<>(appendable, this);
    }


    public JsonObjectBuilder<C> keyValue(String key, String value) {
        return keyValue(key, value, null);
    }

    public JsonObjectBuilder<C> keyValue(String key, String value, String description) {
        return key(key, description).value(value);
    }

    public <T> JsonObjectBuilder<C> keyValueEnum(String key, T value, IEnumResolver<T> resolver) {
        return key(key).valueEnum(value, resolver);
    }

    public <T> JsonObjectBuilder<C> keyValueEnum(String key, T value, IEnumResolver<T> resolver, String description) {
        return key(key, description).valueEnum(value, resolver);
    }

    public JsonObjectBuilder<C> keyValueObjectAsString(String key, Object value) {
        return keyValueObjectAsString(key, value, null);
    }

    public JsonObjectBuilder<C> keyValueObjectAsString(String key, Object value, String description) {
        return key(key, description).valueObjectAsString(value);
    }


    public JsonObjectBuilder<C> keyValueInt(String key, Integer value) {
        return keyValueInt(key, value, null);
    }

    public JsonObjectBuilder<C> keyValueInt(String key, Integer value, String description) {
        return key(key, description).valueInt(value);
    }


    public JsonObjectBuilder<C> keyValueLong(String key, Long value) {
        return keyValueLong(key, value, null);
    }

    public JsonObjectBuilder<C> keyValueLong(String key, Long value, String description) {
        return key(key, description).valueLong(value);
    }


    public JsonObjectBuilder<C> keyValueDouble(String key, Double value) {
        return keyValueDouble(key, value, (String) null);
    }

    public JsonObjectBuilder<C> keyValueDouble(String key, Double value, String description) {
        return key(key, description).valueDouble(value);
    }


    public JsonObjectBuilder<C> keyValueDouble(String key, Double value, DecimalFormat format) {
        return keyValueDouble(key, value, format, null);
    }

    public JsonObjectBuilder<C> keyValueDouble(String key, Double value, DecimalFormat format, String description) {
        return key(key, description).valueDouble(value, format);
    }


    public JsonObjectBuilder<C> keyValueBoolean(String key, Boolean value) {
        return keyValueBoolean(key, value, null);
    }

    public JsonObjectBuilder<C> keyValueBoolean(String key, Boolean value, String description) {
        return key(key, description).valueBoolean(value);
    }


    public JsonObjectBuilder<C> keyValueDateTime(String key, Date value) {
        return keyValueDateTime(key, value, null);
    }

    public JsonObjectBuilder<C> keyValueDateTime(String key, Date value, String description) {
        return key(key, description).valueDateTime(value);
    }


    public JsonObjectBuilder<C> keyValueDate(String key, Date value) {
        return keyValueDate(key, value, (String) null);
    }

    public JsonObjectBuilder<C> keyValueDate(String key, Date value, String description) {
        return key(key, description).valueDate(value);
    }

    public JsonObjectBuilder<C> keyValueDate(String key, Date value, DateFormat dateFormat) {
        return keyValueDate(key, value, dateFormat, null);
    }

    public JsonObjectBuilder<C> keyValueDate(String key, Date value, DateFormat dateFormat, String description) {
        return key(key, description).valueDate(value, dateFormat);
    }


    public JsonObjectBuilder<C> keyValueNull(String key) {
        return keyValueNull(key, null);
    }

    public JsonObjectBuilder<C> keyValueNull(String key, String description) {
        return key(key, description).valueNull();
    }


    public JsonObjectBuilder<C> writeObject(JsonObjectWriter writer) {
        return writer.writeObject(this);
    }

    public JsonObjectBuilder<C> comment(String comment) {
        appendable.comment(comment);
        return this;
    }

    public C endObject() {
        return endObject(false);
    }

    public C endObject(boolean asMapObject) {
        assertState(State.READY);
        state = State.CLOSED;
        container.focusReturn();

        if (handleLifecycle) {
            if (asMapObject) {
                appendable.endMapObject();
            } else {
                appendable.endObject();
            }
        }
        return container;
    }
}
