/*
 * Copyright (c) 2004-2017, by Alex Leigh.
 * All rights reserved.
 *
 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE
 * The copyright notice above does not evidence any
 * actual or intended publication of such source code.
 */

package leigh.eo.schema.dao;

import leigh.eo.EO;
import leigh.eo.EOLoop;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Utility class for interacting with Elements.
 *
 * @author Alex Leigh
 */
public final class ElementUtil {
    public static String API_NAME = ElementElementDAO.API_TYPE;
    public static String KEY_API_NAME = "apiName";
    public static String KEY_FIELDS = "fields";

    public static EO create(final String apiName) {
        final EO eo = ElementElementDAO.create();
        ElementElementDAO.setApiName(eo, apiName);
        return eo;
    }

    /**
     * Set the protected status of all fields in <code>element</code> to <code>true</code>.
     *
     * @param element
     */
    public static void protectAll(final EO element) {
        for (final EO field : ElementElementDAO.getFields(element)) {
            if (!FieldElementDAO.assertType(field))
                continue;
            FieldElementDAO.setIsProtected(field, true);
        }
    }

    public static void addField(final EO eo, final EO field) {
        ElementElementDAO.getFields(eo).add(field);
    }

    /**
     * Returns <code>true</code> if this element only contains fields, otherwise, returns <code>false</code>.
     *
     * @param element
     * @return
     */
    public static boolean containsOnlyFields(final EO element) {
        final EOLoop fields = ElementElementDAO.getFields(element);
        return fields.onlyContains(FieldUtil.API_NAME);
    }

    /**
     * Return field/loop of the given API name from the given element. If the element does not
     * contain any fields, or a field by that API name is not found, <code>null</code> is returned.
     *
     * @param element
     * @param apiName
     * @return
     */
    public static EO getField(final EO element, final String apiName) {
        final EOLoop fields = ElementElementDAO.getFields(element);
        if (fields == null) return null;

        // Try the fields first
        Iterator<EO> it = fields.iterator(FieldElementDAO.API_TYPE);
        while (it.hasNext()) {
            final EO field = it.next();
            if (FieldElementDAO.getApiName(field).equals(apiName))
                return field;
        }

        // Then try the loops
        it = fields.iterator(LoopElementDAO.API_TYPE);
        while (it.hasNext()) {
            final EO field = it.next();
            if (LoopElementDAO.getApiName(field).equals(apiName))
                return field;
        }

        // Nothing found? Too bad, so sad.

        return null;
    }

    /**
     * Returns a <code>Set</code> containing the API names for every field within
     * the given element. Only API names for Fields are returns, not Loops or any
     * other kinds of constructs.
     *
     * @param element
     * @return
     */
    public static Map<String, Class> getFieldKeys(final EO element) {

        final HashMap<String, Class> names = new HashMap<>();

        for (final EO field : ElementElementDAO.getFields(element)) {
            if (!FieldElementDAO.assertType(field))
                continue;
            final Class c = FieldUtil.getTypeClass(field);
            names.put(FieldElementDAO.getApiName(field), c);
        }

        return names;
    }

    /**
     * Return the first field in the element. Loops and other types are ignored.
     *
     * @param element
     * @return
     */
    public static EO getFirstField(final EO element) {
        final EOLoop fields = ElementElementDAO.getFields(element);
        if (fields == null) return null;

        // Try the fields first
        Iterator<EO> it = fields.iterator(FieldElementDAO.API_TYPE);
        if (it.hasNext()) {
            return it.next();
        }

        return null;
    }
}