// Module    : $RCSfile: AbstractDefaultGUIElementFactory.java,v $
// Version   : $Revision: 0.0 $  $Author: patrick $  $Date: 13.05.2012 $
// Project   : GUIModel
// Creation  : 2012 by patrick
// Copyright : Patrick Harms, 2012

package de.ugoe.cs.quest.eventcore.guimodel;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * TODO comment
 * 
 * @version $Revision: $ $Date: 13.05.2012$
 * @author 2012, last modified by $Author: patrick$
 */
public abstract class AbstractDefaultGUIElementFactory {
    
    /** */
    private Properties mappingsFromConfiguration;

    /**
     * TODO: comment
     * 
     * @param object1
     * @param object2
     * @return
     */
    protected boolean equals(Object object1, Object object2) {
        if (object1 == object2) {
            return true;
        }
        else if (object1 != null) {
            return object1.equals(object2);
        }
        else {
            return object2 == null;
        }
    }

    /**
     * TODO: comment
     * 
     * @param parameterTypes
     * @param parameters
     * @return
     * @throws GUIModelConfigurationException
     */
    protected IGUIElement instantiateGUIElementFromConfiguredMappings(String type,
                                                                      Object... parameters)
        throws GUIModelConfigurationException
    {
        Properties mappings = getMappingsFromConfiguration();

        String className = mappings.getProperty(type);
        if (className != null) {
            try {
                Class<?> clazz = this.getClass().getClassLoader().loadClass(className);

                if (!IGUIElement.class.isAssignableFrom(clazz)) {
                    Logger.getLogger(this.getClass().getName()).warning
                        ("configured GUI element representing class " + className +
                         " is no valid GUIElement " + "derivate.");

                    return null;
                }

                Class<?>[] parameterTypes = new Class<?>[parameters.length];

                for (int i = 0; i < parameters.length; i++) {
                    parameterTypes[i] = parameters[i].getClass();

                    if (Boolean.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = boolean.class;
                    }
                    else if (Integer.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = int.class;
                    }
                    else if (Double.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = double.class;
                    }
                    else if (Character.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = char.class;
                    }
                    else if (Byte.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = byte.class;
                    }
                    else if (Float.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = float.class;
                    }
                    else if (Long.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = long.class;
                    }
                    else if (Short.class.equals(parameterTypes[i])) {
                        parameterTypes[i] = short.class;
                    }
                }

                IGUIElement guiElement =
                    (IGUIElement) clazz.getConstructor(parameterTypes).newInstance(parameters);

                if (guiElement instanceof AbstractDefaultGUIElement) {
                    ((AbstractDefaultGUIElement) guiElement).setOriginalTypeInfo(type);
                }

                return guiElement;
            }
            catch (ClassNotFoundException e) {
                Logger.getLogger(this.getClass().getName()).warning
                    ("configured GUI element representing class " + className +
                     " can not be loaded.");
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className +
                     " can not be loaded.", e);
            }
            catch (SecurityException e) {
                Logger.getLogger(this.getClass().getName()).log
                    (Level.WARNING, "configured GUI element representing class " + className +
                     " can not be instantiated due to security reasons.", e);
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className +
                     " can not be instantiated due to security reasons.", e);
            }
            catch (NoSuchMethodException e) {
                Logger.getLogger(this.getClass().getName()).warning
                    ("configured GUI element representing class " + className +
                     " does not provide an appropriate constructur.");
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className +
                     " does not provide an appropriate constructur.", e);
            }
            catch (IllegalArgumentException e) {
                Logger.getLogger(this.getClass().getName()).warning
                    ("configured GUI element representing class " + className + " does not " +
                     "provide an appropriate constructur accepting the provided parameters.");
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className + " does not " +
                     "provide an appropriate constructur accepting the provided parameters.", e);
            }
            catch (InstantiationException e) {
                Logger.getLogger(this.getClass().getName()).log
                    (Level.WARNING, "configured GUI element representing class " + className +
                     " can not be instantiated.", e);
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className +
                     " can not be instantiated.", e);
            }
            catch (IllegalAccessException e) {
                Logger.getLogger(this.getClass().getName()).log
                    (Level.WARNING, "configured GUI element representing class " + className +
                     " can not be instantiated.", e);
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className +
                     " can not be instantiated.", e);
            }
            catch (InvocationTargetException e) {
                Logger.getLogger(this.getClass().getName()).log
                    (Level.WARNING, "configured GUI element representing class " + className +
                     " can not be instantiated.", e);
                throw new GUIModelConfigurationException
                    ("configured GUI element representing class " + className +
                     " can not be instantiated.", e);
            }
        }

        return null;
    }

    /**
     * TODO: comment
     * 
     * @return
     */
    private synchronized Properties getMappingsFromConfiguration() {
        if (mappingsFromConfiguration != null) {
            return mappingsFromConfiguration;
        }
        else {
            mappingsFromConfiguration = new Properties();

            InputStream inStream =
                this.getClass().getClassLoader().getResourceAsStream("GUIElementMapping.txt");

            if (inStream != null) {
                try {
                    mappingsFromConfiguration.load(inStream);
                }
                catch (IOException e) {
                    Logger.getLogger(this.getClass().getName()).warning
                        ("could not load GUIElementMapping.txt from classpath, but this may be " +
                         "intended");
                }
            }

            return mappingsFromConfiguration;
        }
    }
}
