package com.github.structlog4j.yaml;

import com.github.structlog4j.IFormatter;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.nodes.Tag;

/**
 * Basic YAML formatter using the standard SnakeYaml library
 *
 * @author Jacek Furmankiewicz
 */
public class YamlFormatter implements IFormatter<Map<String,String>> {

    // SnakeYaml object is not threadsafe, need Thread local instance for max performance
    private static final ThreadLocal<Yaml> YAML = new ThreadLocal<Yaml>() {
        @Override
        protected Yaml initialValue() {
            DumperOptions options = new DumperOptions();
            options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
            options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN);

            return new Yaml(options);
        }
    };

    private static final String FIELD_MESSAGE = "message";
    private static final String FIELD_MESSAGE_2 = "message2";

    private static final YamlFormatter INSTANCE = new YamlFormatter();
    public static YamlFormatter getInstance() {return INSTANCE;}

    @Override
    public final Map<String,String> start(Logger log) {
        return new HashMap<>(10);
    }

    @Override
    public final IFormatter<Map<String,String>> addMessage(Logger log, Map<String,String> bld, String message) {
        bld.put(FIELD_MESSAGE,message);
        return this;
    }

    @Override
    public final IFormatter<Map<String,String>> addKeyValue(Logger log, Map<String,String> bld, String key, Object value) {
        // avoid overriding the "message" field
        if (key.equals(FIELD_MESSAGE)) {
            key = FIELD_MESSAGE_2;
            log.warn("Key 'message' renamed to 'message2' in order to avoid overriding default YAML message field. Please correct in your code.");
        }

        bld.put(key, String.valueOf(value));
        return this;
    }

    @Override
    public final String end(Logger log, Map<String,String> bld) {
        return YAML.get().dump(bld).trim();
    }

}