//==============================================================================
// AbstractWritableDocument.java
//==============================================================================

package tribble.archive;

import java.io.IOException;

import java.lang.String;
import java.lang.StringBuilder;
import java.lang.System;
import java.lang.UnsupportedOperationException;


/*******************************************************************************
* Generic read-only archive document.
*
* <p>
* An <i>archive document</i> is composed of content data (such as an image,
* text, or other kind of user data) and one or more <i>properties</i>.
*
* <p>
* Most of the methods in this base class that implement the
* {@link ArchiveDocument} interface do not throw any checked exceptions.
*
* <p>
* Note: This requires Java 1.5 or later.
*
* <!-- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ -->
* <dl>
* <dt> <b>Source code:</b> </dt>
*  <dd>
*   <a href="../../../src/java/tribble/archive/AbstractWritableDocument.java"
*    >http://david.tribble.com/src/java/tribble/archive/AbstractWritableDocument.java</a>
*  </dd>
* <dt> <b>Documentation:</b> </dt>
*  <dd>
*   <a href="AbstractWritableDocument.html"
*    >http://david.tribble.com/docs/tribble/archive/AbstractWritableDocument.html</a>
*  </dd>
* </dl>
*
* <!-- ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ -->
* @version	API 2.0, $Revision: 1.1 $ $Date: 2008/04/03 22:03:56 $
* @since	2008-04-03
* @author	David R. Tribble (david&#64;tribble.com)
*	Copyright ©2004 by David R. Tribble, all rights reserved.
*/

public abstract class AbstractWritableDocument
    extends AbstractDocument
    implements WritableDocument
{
    static final String		REV =
        "@(#)tribble/archive/AbstractWritableDocument.java $Revision: 1.1 $ $Date: 2008/04/03 22:03:56 $\n";


// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
// Constructors

    /***************************************************************************
    * Constructor.
    *
    * @param	props
    * The properties which define the documents in the archive.
    *
    * @since	API 2.0, 2008-04-03
    */
    protected AbstractWritableDocument(DocumentProperty[] props)
    {
        super(props);
    }


// ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
// Methods

    /***************************************************************************
    * Establish the ID of this archive document.
    *
    * @param	id
    * A name that identifies the document within the archive.
    * Whether or not this name is unique is up to the implementation.
    *
    * @throws	IOException
    * Thrown if an error occurred while accessing the document.
    *
    * @throws	UnsupportedOperationException (unchecked)
    * Thrown if this operation is not allowed by the implementation, i.e.,
    * if IDs are assigned to archive documents by some other means.
    *
    * @throws	IllegalStateException (unchecked)
    * Thrown if {@link #close} has been called for this object.
    *
    * @since	API 2.0, 2008-04-03
    */
    //@Override
    public void setID(String id)
        throws IOException, UnsupportedOperationException
    {
        checkOpen();
        m_id = id;
    }


    /***************************************************************************
    * Establish the data size for this archive document.
    *
    * @param	len
    * The size (typically in bytes) of the document data, or -1 if the size is
    * not known.
    *
    * @throws	IllegalStateException (unchecked)
    * Thrown if {@link #close} has been called for this object.
    *
    * @since	API 2.0, 2008-04-03
    */
    //@Override
    public void setSize(long len)
    {
        checkOpen();
        m_size = len;
    }


    /***************************************************************************
    * Set the value of a property in this archive document.
    *
    * @param	prop
    * The name of the document property to set.
    *
    * @param	val
    * The new property value.
    *
    * @throws	IOException
    * Thrown if an error occurred while modifying the document.
    *
    * @throws	IllegalStateException (unchecked)
    * Thrown if {@link #close} has been called for this object.
    *
    * @since	API 2.0, 2008-04-03
    */
    //@Override
    public void setProperty(String prop, Object val)
        throws IOException
    {
        // Sanity checks
        checkOpen();
        if (m_props == null)
            throw new IOException("Document has no properties");

        // Set the document property value
        for (int i = 0;  i < m_props.length;  i++)
        {
            if (m_props[i].getName().equals(prop))
            {
                m_propVals[i] = val;
                return;
            }
        }

        throw new IOException("Document has no such property: " + prop);
    }


    /***************************************************************************
    * Add a property to this archive document.
    *
    * @param	prop
    * A property to add to this document.
    *
    * @throws	IOException
    * Thrown if the property already exists in this document, or if an error
    * occurred while modifying the document.
    *
    * @throws	UnsupportedOperationException (unchecked)
    * Thrown if this method is not supported by the implementation of this
    * interface.
    *
    * @throws	IllegalStateException (unchecked)
    * Thrown if {@link #close} has been called for this object.
    *
    * @since	API 2.0, 2008-04-03
    */
    //@Override
    public void addProperty(WritableProperty prop)
        throws UnsupportedOperationException, IOException
    {
        // Sanity check
        checkOpen();

        // Ensure that there are properties
        if (m_props == null)
            m_props = new DocumentProperty[0];

        synchronized (m_props)
        {
            String		name;
            int			nProps;
            DocumentProperty[]	newProps;

            // Ensure that the document property does not already exist
            name = prop.getName();
            nProps = m_props.length;

            for (int i = 0;  i < nProps;  i++)
            {
                if (m_props[i].getName().equals(name))
                    throw new IOException("Document property already exists: "
                        + name);
            }

            // Add the new property to the document
            newProps = new DocumentProperty[nProps + 1];
            for (int i = 0;  i < nProps;  i++)
            {
                newProps[i] = m_props[i];
                m_props[i] = null;
            }
            newProps[nProps] = prop;
            m_props = newProps;
        }
    }
}

// End AbstractWritableDocument.java
