package com.github.tminglei.bind;

import java.util.*;

/**
 * object used to hold bind result or errors
 */
public class BindObject implements Iterable<Map.Entry<String, Object>> {
    static final String DEFAULT_KEY = "_default$";

    private final Object errors;
    private final Map<String, Object> data;

    BindObject(Object errors) {
        this.errors = errors;
        this.data = new HashMap<>();
    }
    BindObject(Map<String, Object> data) {
        this.errors = null;
        this.data = data;
    }

    /**
     * @param <T> expected type
     * @return the errors optional
     */
    public <T> Optional<T> errors() {
        return Optional.ofNullable((T) errors);
    }

    /**
     * implementation for interface Iterable
     * @return the field iterator
     */
    @Override
    public Iterator<Map.Entry<String, Object>> iterator() {
        return data.entrySet().iterator();
    }

    /**
     * @return field names
     */
    public Set<String> names() {
        return data.keySet();
    }

    /**
     * @param name field name
     * @return field bind object
     */
    public BindObject node(String name) {
        return (BindObject) data.get(name);
    }

    /**
     * @param <T> expected type
     * @return the final result value
     */
    public <T> T get() {
        return (T) data.get(DEFAULT_KEY);
    }

    /**
     * @param name field name
     * @param <T> expected type
     * @return field value
     */
    public <T> T get(String name) {
        return (T) data.get(name);
    }

    /**
     * convert to specified type (NOTE: only Map is supported currently)
     * @param target target type class
     * @param <T>    target type
     * @return converted object
     */
    public <T> T to(Class<T> target) {
        if (target == Map.class) {
            return (T) FrameworkUtils.bind2map(this);
        } else throw new IllegalArgumentException("Unsupported type: " + target);
    }

    ///--

    @Override
    public String toString() {
        StringBuffer buf = new StringBuffer();
        if (errors != null) {
            buf.append("errors: ");
            buf.append(errors);
        } else {
            buf.append("{ ");
            data.entrySet().stream().forEach(e -> {
                buf.append(e.getKey()).append(": ").append(e.getValue()).append(", ");
            });
            buf.append(" }");
        }
        return buf.toString();
    }

}

@@ -1529,32 +1529,206 @@
 t(name);%0A    %7D%0A%0A
+    /**%0A     * @param name field name%0A     * @return true if exists; false if not%0A     */%0A    public boolean has(String name) %7B%0A        return data.get(name) != null;%0A    %7D%0A%0A
     /**%0A     * c

add `has` method to BindObject