package leigh.eo.yaml;

import leigh.eo.EO;
import leigh.eo.EOLoop;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import org.yaml.snakeyaml.Yaml;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Map;
import java.util.Set;

/**
 * Implements a YAML parser for {@link EO} objects.
 * <p>
 * This is not a streaming parser; the entire content of the YAML will be read into memory on construction.
 *
 * @author Alex Leigh
 */
public class YamlInput implements Closeable {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(YamlInput.class);
    private final EOLoop loop;
    private int position = 0;

    public YamlInput(InputStream is) {
        Yaml yaml = new Yaml();
        Map<String, Object> parsed = yaml.load(is);
        loop = new EOLoop();
        convert(loop, parsed);
    }

    public EO readEo() {
        if (position >= loop.size()) return null;
        EO obj = loop.get(position);
        position++;
        return obj;
    }

    @Override
    public void close() throws IOException {
        // Do nothing
    }

    public static void convert(EOLoop dst, Map<String, Object> src) {
        for (Map.Entry<String, Object> entry : src.entrySet()) {
            EO child = new EO();
            dst.add(child);
            Object value = entry.getValue();
            //  logger.info("Found type: {}", entry.getValue().getClass());

            // In YAML, a value may be a map, an array, or other.

            if (!(value instanceof Map) && !(value instanceof Set)) {
                child.setValue(entry.getKey(), (Serializable) value);
            } else {
                EOLoop childLoop = child.getValueLoop(entry.getKey());
                convert(childLoop, (Map<String, Object>) value);
            }
        }
    }
}
