FileDocCategorySizeDatePackage
AbstractTagFrameBody.javaAPI DocJaudiotagger 2.0.410547Wed Mar 30 16:12:06 BST 2011org.jaudiotagger.tag.id3

AbstractTagFrameBody.java

/**
 *  @author : Paul Taylor
 *  @author : Eric Farng
 *
 *  Version @version:$Id: AbstractTagFrameBody.java 895 2010-04-15 15:21:45Z paultaylor $
 *
 *  MusicTag Copyright (C)2003,2004
 *
 *  This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
 *  General Public  License as published by the Free Software Foundation; either version 2.1 of the License,
 *  or (at your option) any later version.
 *
 *  This library 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License along with this library; if not,
 *  you can get a copy from http://www.opensource.org/licenses/lgpl-license.php or write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 *  FragmentBody contains the data for a fragment.
 * ID3v2 tags have frames bodys. Lyrics3 tags have fields bodys
 * ID3v1 tags do not have fragments bodys.
 * Fragment Bodies consist of a number of MP3Objects held in an objectList
 * Methods are additionally defined here to restrieve and set these objects.
 * We also specify methods for getting/setting the text encoding of textual
 * data.
 * Fragment bodies should not be concerned about their parent fragment. For
 * example most ID3v2 frames can be applied to ID3v2tags of different versions.
 * The frame header will need modification based on the frame version but this
 * should have no effect on the frame body.
 */
package org.jaudiotagger.tag.id3;

import org.jaudiotagger.tag.datatype.AbstractDataType;
import org.jaudiotagger.tag.datatype.DataTypes;
import org.jaudiotagger.tag.id3.valuepair.TextEncoding;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * A frame body contains the data content for a frame
 */
public abstract class AbstractTagFrameBody extends AbstractTagItem
{
    public void createStructure()
    {
    }

    /**
     * Reference to the header associated with this frame body, a framebody can be created without a header
     * but one it is associated with a header this should be set. It is principally useful for the framebody to know
     * its header, because this will specify its tag version and some framebodies behave slighly different
     * between tag versions.
     */
    private AbstractTagFrame header;

    /**
     * List of data types that make up this particular frame body.
     */
    protected ArrayList<AbstractDataType> objectList = new ArrayList<AbstractDataType>();

    /**
     * Return the Text Encoding
     *
     * @return the text encoding used by this framebody
     */
    public final byte getTextEncoding()
    {
        AbstractDataType o = getObject(DataTypes.OBJ_TEXT_ENCODING);

        if (o != null)
        {
            Long encoding = (Long) (o.getValue());
            return encoding.byteValue();
        }
        else
        {
            return TextEncoding.ISO_8859_1;
        }
    }

    /**
     * Set the Text Encoding to use for this frame body
     *
     * @param textEncoding to use for this frame body
     */
    public final void setTextEncoding(byte textEncoding)
    {
        //Number HashMap actually converts this byte to a long
        setObjectValue(DataTypes.OBJ_TEXT_ENCODING, textEncoding);
    }


    /**
     * Creates a new framebody, at this point the bodys
     * ObjectList is setup which defines what datatypes are expected in body
     */
    protected AbstractTagFrameBody()
    {
        setupObjectList();
    }

    /**
     * Copy Constructor for fragment body. Copies all objects in the
     * Object Iterator with data.
     * @param copyObject
     */
    protected AbstractTagFrameBody(AbstractTagFrameBody copyObject)
    {
        AbstractDataType newObject;
        for (int i = 0; i < copyObject.objectList.size(); i++)
        {
            newObject = (AbstractDataType) ID3Tags.copyObject(copyObject.objectList.get(i));
            newObject.setBody(this);
            this.objectList.add(newObject);
        }
    }


    /**
     *
     * @return the text value that the user would expect to see for this framebody type, this should be overrridden
     * for all framebodies
     */
    public String getUserFriendlyValue()
    {
        return toString();
    }

    /**
     * This method calls <code>toString</code> for all it's objects and appends
     * them without any newline characters.
     *
     * @return brief description string
     */
    public String getBriefDescription()
    {
        String str = "";
        for (AbstractDataType object : objectList)
        {
            if ((object.toString() != null) && (object.toString().length() > 0))
            {
                str += (object.getIdentifier() + "=\"" + object.toString() + "\"; ");
            }
        }
        return str;
    }


    /**
     * This method calls <code>toString</code> for all it's objects and appends
     * them. It contains new line characters and is more suited for display
     * purposes
     *
     * @return formatted description string
     */
    public final String getLongDescription()
    {
        String str = "";
        for (AbstractDataType object : objectList)
        {
            if ((object.toString() != null) && (object.toString().length() > 0))
            {
                str += (object.getIdentifier() + " = " + object.toString() + "\n");
            }
        }
        return str;
    }

    /**
     * Sets all objects of identifier type to value defined by <code>obj</code> argument.
     *
     * @param identifier <code>MP3Object</code> identifier
     * @param value      new datatype value
     */
    public final void setObjectValue(String identifier, Object value)
    {
        AbstractDataType object;
        Iterator<AbstractDataType> iterator = objectList.listIterator();
        while (iterator.hasNext())
        {
            object = iterator.next();
            if (object.getIdentifier().equals(identifier))
            {
                object.setValue(value);
            }
        }
    }

    /**
     * Returns the value of the datatype with the specified
     * <code>identifier</code>
     *
     * @param identifier
     * @return the value of the dattype with the specified
     *         <code>identifier</code>
     */
    public final Object getObjectValue(String identifier)
    {
        return getObject(identifier).getValue();
    }

    /**
     * Returns the datatype with the specified
     * <code>identifier</code>
     *
     * @param identifier
     * @return the datatype with the specified
     *         <code>identifier</code>
     */
    public final AbstractDataType getObject(String identifier)
    {
        AbstractDataType object;
        Iterator<AbstractDataType> iterator = objectList.listIterator();
        while (iterator.hasNext())
        {
            object = iterator.next();
            if (object.getIdentifier().equals(identifier))
            {
                return object;
            }
        }
        return null;
    }

    /**
     * Returns the size in bytes of this fragmentbody
     *
     * @return estimated size in bytes of this datatype
     */
    public int getSize()
    {
        int size = 0;
        AbstractDataType object;
        Iterator<AbstractDataType> iterator = objectList.listIterator();
        while (iterator.hasNext())
        {
            object = iterator.next();
            size += object.getSize();
        }
        return size;
    }

    /**
     * Returns true if this instance and its entire DataType
     * array list is a subset of the argument. This class is a subset if it is
     * the same class as the argument.
     *
     * @param obj datatype to determine subset of
     * @return true if this instance and its entire datatype array list is a
     *         subset of the argument.
     */
    public boolean isSubsetOf(Object obj)
    {
        if (!(obj instanceof AbstractTagFrameBody))
        {
            return false;
        }
        ArrayList<AbstractDataType> superset = ((AbstractTagFrameBody) obj).objectList;
        for (AbstractDataType anObjectList : objectList)
        {
            if (anObjectList.getValue() != null)
            {
                if (!superset.contains(anObjectList))
                {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Returns true if this datatype and its entire DataType array
     * list equals the argument. This datatype is equal to the argument if they
     * are the same class.
     *
     * @param obj datatype to determine equality of
     * @return true if this datatype and its entire <code>MP3Object</code> array
     *         list equals the argument.
     */
    public boolean equals(Object obj)
    {
        if (!(obj instanceof AbstractTagFrameBody))
        {
            return false;
        }
        AbstractTagFrameBody object = (AbstractTagFrameBody) obj;
        boolean check =this.objectList.equals(object.objectList) && super.equals(obj);
        return check;
    }

    /**
     * Returns an iterator of the DataType list.
     *
     * @return iterator of the DataType list.
     */
    public Iterator iterator()
    {
        return objectList.iterator();
    }


    /**
     * Return brief description of FrameBody
     *
     * @return brief description of FrameBody
     */
    public String toString()
    {
        return getBriefDescription();
    }


    /**
     * Create the list of Datatypes that this body
     * expects in the correct order This method needs to be implemented by concrete subclasses
     */
    protected abstract void setupObjectList();

    /**
     * Get Reference to header
     *
     * @return
     */
    public AbstractTagFrame getHeader()
    {
        return header;
    }

    /**
     * Set header
     *
     * @param header
     */
    public void setHeader(AbstractTagFrame header)
    {
        this.header = header;
    }
}