/* ParameterInfo.java
 * =========================================================================
 * This file is part of the GrInvIn project - http://www.grinvin.org
 * 
 * Copyright (C) 2005-2008 Universiteit Gent
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or (at
 * your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * A copy of the GNU General Public License can be found in the file
 * LICENSE.txt provided with the source distribution of this program (see
 * the META-INF directory in the source jar). This license can also be
 * found on the GNU website at http://www.gnu.org/licenses/gpl.html.
 * 
 * If you did not receive a copy of the GNU General Public License along
 * with this program, contact the lead developer, or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

package org.grinvin.params;

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

import org.grinvin.io.IOFormatException;
import org.grinvin.util.InternationalizedProperties;

import org.jdom.Element;

/**
 * Contains information on a single parameter of an invariant, graph factory,
 * etc.
 */
public class ParameterInfo {
    
    //
    private String name;
    
    /**
     * Return the name (or id) of this parameter which distinguishes it from other
     * parameters in a given list.
     */
    public String getName() {
        return name;
    }
    
    /**
     * Set the name of this parameter.
     */
    public void setName(String name) {
        this.name= name;
    }
    
    //
    private InternationalizedProperties properties;
    
    /**
     * Return the internationalized properties object for this parameter.
     * Currently the following property keys should be supported:
     * <ul>
     * <li><tt>parameter.caption</tt> Display name of this parameter.</li>
     * <li><tt>parameter.description</tt> Textual description of this parameter.</li>
     * </ul>
     */
    public InternationalizedProperties getProperties() {
        return this.properties;
    }
    
    /**
     * Set the internationalized properties object for this parameter.
     */
    public void setProperties(InternationalizedProperties properties) {
        this.properties = properties;
    }
    
    /**
     * Return the display name of this parameter.
     * @return  {@code getProperties().getProperty("parameter.caption")}
     */
    public String getCaption() {
        return getProperties().getProperty("parameter.caption");
    }
    
    /**
     * Return a textual description of this parameter.
     * @return  {@code getProperties().getProperty("parameter.description")}
     */
    public String getDescription() {
        return getProperties().getProperty("parameter.description");
    }
    
    //
    private Class type;
    
    
    /**
     * Return the type of this parameter. Corresponding parameter values
     * should be represented by objects of this type.
     */
    public Class getType() {
        return type;
    }
    
    /**
     * Set the type of this parameter.
     */
    public void setType(Class type) {
        this.type = type;
    }
    
    //
    private ParameterEditor editor;
    
    /**
     * Return an editor for this parameter. This editor should handle objects
     * that belong to the class that corresponds to the type of this parameter.
     */
    public ParameterEditor getEditor() {
        return editor;
    }
    
    /**
     * Set the editor for this parameter. This editor should handle objects
     * that belong to the class that corresponds to the type of this parameter.
     */
    public void setEditor(ParameterEditor editor) {
        this.editor = editor;
    }
    
    /**
     * Install a default editor for this parameter, depending on the type
     * of this parameter.
     * @throws IllegalArgumentException when a default editor for this type
     * is not supported.
     */
    public void setDefaultEditor() {
        ParameterEditor ed = map.get(type);
        if (ed == null)
            throw new IllegalArgumentException("No default editor known for type: " + type);
        else
            this.editor = ed;
    }
    
    /**
     * Load parameter information from a JDOM element.
     */
    public void fromElement(Element element) throws IOFormatException {
        try {
            Element el = element.getChild("name");
            if (el == null)
                throw new IOFormatException("Invalid format: missing 'name' element");
            setName(el.getTextNormalize());
            
            el = element.getChild("type");
            if (el == null)
                throw new IOFormatException("Invalid format: missing 'type' element");
            Class clazz = Class.forName(el.getTextNormalize());
            setType(clazz);
            
            el = element.getChild("i18n");
            if (el == null)
                throw new IOFormatException("Invalid format: missing 'i18n' element");
            InternationalizedProperties iprops = new InternationalizedProperties();
            iprops.fromElement(el);
            setProperties(iprops);
            
            // TODO: allow specific editor
            setDefaultEditor();
        } catch (ClassNotFoundException ex) {
            throw new IOFormatException("Invalid input format: unknown class for type", ex);
        }
    }
    
    //
    private static final Map<Class,ParameterEditor> map;
    
    static {
        map = new HashMap<Class,ParameterEditor> ();
        map.put(Integer.class, new IntegerEditor());
        map.put(Double.class, new DoubleEditor());
        map.put(Boolean.class, new BooleanEditor());
        map.put(IntegerList.class, new IntegerListEditor()); 
            // TODO: check desirability of this class
    }
    
    
}
