/*
 * Created on Feb 28, 2005
 */
package org.flexdock.plaf;

import java.util.HashMap;

import org.flexdock.plaf.resources.ResourceHandler;
import org.flexdock.plaf.resources.ResourceHandlerFactory;
import org.flexdock.util.ResourceManager;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * @author Christopher Butler
 */
public final class Configurator implements XMLConstants {
    public static final String DEFAULT_PREFS_URI = "org/flexdock/plaf/flexdock-themes-default.xml";
    public static final String PREFS_URI = "flexdock-themes.xml";

    private Configurator() {
        //does nothing
    }

    public static Document loadUserPrefs() {
        return ResourceManager.getDocument(PREFS_URI);
    }

    public static Document loadDefaultPrefs() {
        return ResourceManager.getDocument(DEFAULT_PREFS_URI);
    }

    public static HashMap getNamedElementsByTagName(String tagName) {
        if(isNull(tagName))
            return null;

        HashMap cache = new HashMap(256);
        // load defaults
        Document defaults = Configurator.loadDefaultPrefs();
        loadNamedElementsByTagName(defaults, tagName, cache);
        // overwrite/add with user prefs
        Document user = Configurator.loadUserPrefs();
        loadNamedElementsByTagName(user, tagName, cache);

        return cache;
    }

    private static void loadNamedElementsByTagName(Document document, String tagName, HashMap cache) {
        if(document==null)
            return;

        NodeList elements = document.getElementsByTagName(tagName);

        for(int i=0; i<elements.getLength(); i++) {
            Element elem = (Element)elements.item(i);
            String key = elem.getAttribute(NAME_KEY);
            boolean inherit = "true".equals(elem.getAttribute(INHERITS_KEY));
            if(!isNull(key)) {

                if(inherit) {
                    // mark as overridden, so we don't overwrite it in the cache
                    Element oldValue = (Element)cache.get(key);
                    if(oldValue!=null) {
                        cache.put(OVERRIDDEN_KEY + key, oldValue);
                    }
                }
                cache.put(key, elem);
            }
        }
    }

    public static PropertySet[] getProperties(String tagName) {
        HashMap map = getNamedElementsByTagName(tagName);
        if(map==null)
            return new PropertySet[0];

        String[] names = (String[])map.keySet().toArray(new String[0]);
        return getProperties(names, map);
    }

    public static PropertySet getProperties(String name, String tagName) {
        HashMap map = getNamedElementsByTagName(tagName);
        if(map==null)
            return null;
        return getProperties(name, map);
    }

    public static PropertySet[] getProperties(String[] names, String tagName) {
        HashMap map = names==null? null: getNamedElementsByTagName(tagName);
        if(map==null)
            return new PropertySet[0];
        return getProperties(names, map);
    }

    public static PropertySet[] getProperties(String[] names, HashMap cache) {
        PropertySet[] properties = new PropertySet[names.length];
        for(int i=0; i<names.length; i++) {
            properties[i] = getProperties(names[i], cache);
        }
        return properties;
    }

    private static PropertySet getProperties(String elemName, HashMap cache) {
        Element elem = isNull(elemName)? null: (Element)cache.get(elemName);
        if(elem==null)
            return null;

        PropertySet set = new PropertySet();
        set.setName(elemName);

        // load all the parent properties first, so we can add/overwrite our own later
        String parentName = elem.getAttribute(EXTENDS_KEY);
        PropertySet parent = isNull(parentName)? null: getProperties(parentName, cache);
        if(parent!=null)
            set.setAll(parent);

        // check to see if we're supposed to inherit from an overridden element
        if("true".equalsIgnoreCase(elem.getAttribute(INHERITS_KEY))) {
            PropertySet overridden = getProperties(OVERRIDDEN_KEY + elemName, cache);
            if(overridden!=null)
                set.setAll(overridden);
        }

        // get the default handler name
        String propertyHandlerName = getPropertyHandlerName(elem);

        NodeList list = elem.getElementsByTagName(PROPERTY_KEY);
        int len = list.getLength();
        for(int i=0; i<len; i++) {
            elem = (Element)list.item(i);
            String key = elem.getAttribute(NAME_KEY);
            if(!isNull(key)) {
                String value = elem.getAttribute(VALUE_KEY);
                String handler = elem.getAttribute(HANDLER_KEY);
                Object resource = getResource(value, handler, propertyHandlerName);
                if(resource!=null) {
                    set.setProperty(key, resource);
                }
            }
        }
        return set;
    }

    private static String getPropertyHandlerName(Element elem) {
        String handlerName = elem.getAttribute(PROP_HANDLER_KEY);
        if(isNull(handlerName))
            handlerName = ResourceHandlerFactory.getPropertyHandler(elem.getTagName());
        return isNull(handlerName)? null: handlerName;
    }

    public static Object getResource(String stringValue, String currentHandlerName, String defaultHandlerName) {
        String handlerName = isNull(currentHandlerName)? defaultHandlerName: currentHandlerName;
        if(isNull(handlerName))
            return nullify(stringValue);

        ResourceHandler handler = ResourceHandlerFactory.getResourceHandler(handlerName);
        return handler==null? nullify(stringValue): handler.getResource(stringValue);
    }

    private static String nullify(String data) {
        return isNull(data)? null: data;
    }


    public static boolean isNull(String data) {
        return data == null || data.trim().length() == 0;
    }
}
