/*
 *  @(#)AbstractEditableListAttribute.java
 *
 * Copyright (C) 2002-2003 Matt Albrecht
 * groboclown@users.sourceforge.net
 * http://groboutils.sourceforge.net
 *
 *  Part of the GroboUtils package at:
 *  http://groboutils.sourceforge.net
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the 
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in 
 *  all copies or substantial portions of the Software. 
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL 
 *  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 *  DEALINGS IN THE SOFTWARE.
 */
package net.sourceforge.groboutils.pmti.v1.defimpl;

import net.sourceforge.groboutils.pmti.v1.IEditableListAttribute;
import net.sourceforge.groboutils.pmti.v1.IListAttribute;
import net.sourceforge.groboutils.pmti.v1.IAttributeInfo;

import java.util.Vector;
import java.util.Enumeration;


/**
 * A simple name-value association for a specific kind of issue attribute.
 * All implementations of <tt>IAttribute</tt> are immutable, unless they also
 * implement <tt>IEditableAttribute</tt>.
 *
 * @author     Matt Albrecht <a href="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
 * @version    $Date: 2003/02/10 22:51:57 $
 * @since      July 12, 2002
 */
public abstract class AbstractEditableListAttribute
        implements IEditableListAttribute
{
    private Vector vals;
    private IAttributeInfo info;
    private boolean changedVals = false;
    
    
    public AbstractEditableListAttribute( IListAttribute a )
    {
        if (a == null)
        {
            throw new IllegalArgumentException("no null arguments");
        }
        this.info = a.getInfo();
        
        Enumeration enum = a.getValues();
        this.vals = new Vector();
        while (enum.hasMoreElements())
        {
            this.vals.addElement( enum.nextElement() );
        }
    }
    
    
    
    //-------------------------------------------------------------------------
    // IAttribute
    
    
    /**
     * Returns the enumeration for all values in this attribute.
     */
    public Object getValue()
    {
        return getValues();
    }
    
    
    /**
     * Returns the meta-information for this attribute.
     */
    public IAttributeInfo getInfo()
    {
        return this.info;
    }
    
    
    //-------------------------------------------------------------------------
    // IListAttribute
    
    
    /**
     * A synonym for <tt>getValue()</tt>, but redefined here to explicitly
     * declare the returned type.
     */
    public Enumeration getValues()
    {
        // clone the vector since this implementation is not immutable.
        return ((Vector)this.vals.clone()).elements();
    }
    
    
    /**
     * 
     */
    public int getValueCount()
    {
        return this.vals.size();
    }
    
    
    /**
     * 
     */
    public boolean containsValue( Object value )
    {
        return this.vals.contains( value );
    }


    
    //-------------------------------------------------------------------------
    // IEditableAttribute
    
    
    /**
     * This list version needs special handling for when the value is an
     * array.
     * 
     * @exception IllegalArgumentException thrown if the value argument is
     *      invalid.
     */
    public void setValue( Object value )
    {
        if (!isValidValue( value ))
        {
            throw new IllegalArgumentException("Value "+value+
                " is not a valid value" );
        }
        this.changedVals = true;
        
        this.vals.removeAllElements();
        if (value instanceof Object[])
        {
            Object[] o = (Object[])value;
            for (int i = 0; i < o.length; ++i)
            {
                this.vals.addElement( o[i] );
            }
        }
        else
        {
            this.vals.addElement( value );
        }
    }
    
    
    /**
     * @return <tt>true</tt> if the <tt>setValue( Object )</tt> method has
     *      been called on this instance and the actual value has changed
     *      (via inspection with <tt>==</tt> and <tt>equals()</tt>),
     *      otherwise <tt>false</tt>.
     */
    public boolean hasValueChanged()
    {
        return this.changedVals;
    }
    
    
    /**
     * Specialization of the original purpose.  Allows for the value to
     * be an array, in which case it checks each element.  In the
     * case of an array, the array is invalid if any one element inside is
     * invalid.  Do not override this method with an explicit array form -
     * the Java calling methodology is NOT dynamic, so if this class is
     * known as an IEditableAttribute, then this method will be invoked, not
     * the array form.
     */
    public boolean isValidValue( Object value )
    {
        if (value != null && value instanceof Object[])
        {
            Object[] o = (Object[])value;
            for (int i = 0; i < o.length; ++i)
            {
                if (!innerIsValidValue( o[i] ))
                {
                    // an element is invalid - the whole array is invalid.
                    return false;
                }
            }
            // all elements are valid
            return true;
        }
        else
        return innerIsValidValue( value );
    }
    
    
    /**
     * Simplified form of the value validation check.  This method
     * should not perform array checking.
     */
    protected abstract boolean innerIsValidValue( Object value );
    
    
    
    //-------------------------------------------------------------------------
    // IEditableListAttribute
    
    
    
    
    /**
     * This method still performs array checking.
     *
     * @exception IllegalArgumentException thrown if the value argument is
     *      invalid.
     */
    public void addValue( Object value )
    {
        if (!isValidValue( value ))
        {
            throw new IllegalArgumentException("value "+value+" is invalid");
        }
        this.changedVals = true;
        if (value != null && value instanceof Object[])
        {
            Object[] o = (Object[])value;
            for (int i = 0; i < o.length; ++i)
            {
                this.vals.addElement( o[i] );
            }
        }
        else
        {
            this.vals.addElement( value );
        }
    }
    
    
    /**
     * Does nothing if the value is not in the list of known values.
     */
    public void removeValue( Object value )
    {
        this.vals.removeElement( value );
    }
}

