content: package com.almalence.plugins.export.ExifDriver.Values;
  
  import com.almalence.plugins.export.ExifDriver.ExifDriver;
  
  /**
   * Parent class of all EXIF datatypes.
   */
  public abstract class ExifValue {
  	protected int dataType;
  
  	public ExifValue(int _dataType) {
  		dataType = _dataType;
  	}
  
  	/**
  	 * Read it's value from a given source
  	 * 
  	 * @param _data
  	 *          Source array to read from
  	 * @param _offset
  	 *          Offset where to start reading
  	 * @param _count
  	 *          Amount of bytes to read
  	 * @param _align
  	 *          Endian - is ignored by ASCII and UNDEFINED
  	 */
  	public abstract void readValueFromData(byte[] _data, int _offset, int _count,
  	    int _align);
  
  	/**
  	 * Returns byte array of components
  	 * 
  	 * @return Array of components
  	 * @throws UndefinedValueAccessException
  	 */
  	public byte[] getBytes() throws UndefinedValueAccessException {
  		throw new UndefinedValueAccessException("Function is undefined in "
  		    + getClass().getSimpleName());
  	}
  
  	/**
  	 * Returns int [] of components
  	 * 
  	 * @return Array of components
  	 * @throws UndefinedValueAccessException
  	 */
  	public int[] getIntegers() throws UndefinedValueAccessException {
  		throw new UndefinedValueAccessException("Function is undefined in "
  		    + getClass().getSimpleName());
  	}
  
  	/**
  	 * Returns int [][2] of components
  	 * 
  	 * @return Array of components
  	 * @throws UndefinedValueAccessException
  	 */
  	public int[][] getRationals() throws UndefinedValueAccessException {
  		throw new UndefinedValueAccessException("Function is undefined in "
  		    + getClass().getSimpleName());
  	}
  
  	/**
  	 * Set byte array of values
  	 * 
  	 * @param _values
  	 * @throws UndefinedValueAccessException
  	 */
  	public void setBytes(byte[] _bytes) throws UndefinedValueAccessException {
  		throw new UndefinedValueAccessException("Function is undefined in "
  		    + getClass().getSimpleName());
  	}
  
  	/**
  	 * Set int[] of values
  	 * 
  	 * @param _values
  	 * @throws UndefinedValueAccessException
  	 */
  	public void setIntegers(int[] _values) throws UndefinedValueAccessException {
  		throw new UndefinedValueAccessException("Function is undefined in "
  		    + getClass().getSimpleName());
  	}
  
  	/**
  	 * Set int[][] array of values
  	 * 
  	 * @param _values
  	 * @throws UndefinedValueAccessException
  	 */
  	public void setRationals(int[][] _values)
  	    throws UndefinedValueAccessException {
  		throw new UndefinedValueAccessException("Function is undefined in "
  		    + getClass().getSimpleName());
  	}
  
  	/**
  	 * Returns size of one single component. For example if Value holds components
  	 * of type UNSIGNED_BYTE, it returns 1.
  	 * 
  	 * @return Size of one single component
  	 * @throws UndefinedValueAccessException
  	 */
  	public final int getComponentSize() {
  		return ExifDriver.COMP_WIDTHS[dataType];
  	}
  
  	/**
  	 * Total size of components. In case that value holds 4 components of type
  	 * UNSIGNED_SHORT, it returns 8;
  	 * 
  	 * @return Total size of components
  	 * @throws UndefinedValueAccessException
  	 */
  	public final int getTotalSize() {
  		return getNbfComponents() * getComponentSize();
  	}
  
  	/**
  	 * Returns of extra space that this value needs. All values store their
  	 * components right into directory if their total amount is less then 4B. In
  	 * opposite case they stores to directory only offset, where the data are
  	 * stored. Extra space is therefore 0 or totalLength of data.
  	 * 
  	 * @return Extra space that this value uses
  	 */
  	public final int getExtraSize() {
  		if (getTotalSize() > 4) {
  			return getTotalSize();
  		} else {
  			return 0;
  		}
  	}
  
  	/**
  	 * Returns number of value's components
  	 * 
  	 * @return Extra space that this value uses
  	 * @throws UndefinedValueAccessException
  	 */
  	public abstract int getNbfComponents();
  
  	/**
  	 * This method implements the special way, in which the value saves it's
  	 * components.
  	 * 
  	 * @param _data
  	 *          - output array
  	 * @param _offset
  	 *          - offset where to save the components
  	 */
  	protected abstract void writeValues(byte[] _data, int _offset);
  
  	/**
  	 * Write this component to specified place in output data.
  	 * 
  	 * @param _data
  	 *          Output data array
  	 * @param _itemOffset
  	 *          Offset of IFD directory record
  	 * @param _valuesOffset
  	 *          Offset of the first free byte in IFD's data
  	 * @return Offset of the first free byte in IFD's data. In case, that the
  	 *         value does not use any extra space, return value will equal to
  	 *         _valuesOffset.
  	 * @throws UndefinedValueAccessException
  	 */
  	public final int writeToData(byte[] _data, int _itemOffset, int _valuesOffset) {
  		ExifDriver.writeNumber(_data, _itemOffset + 2, dataType, 2);
  		ExifDriver.writeNumber(_data, _itemOffset + 4, getNbfComponents(), 4);
  		int valueOffset = _itemOffset + 8;
  		int extraSpace = getExtraSize();
  		if (extraSpace > 0) {
  			ExifDriver.writeNumber(_data, valueOffset, _valuesOffset, 4);
  			writeValues(_data, _valuesOffset);
  			return _valuesOffset + extraSpace;
  		} else {
  			writeValues(_data, valueOffset);
  			return _valuesOffset;
  		}
  	}
  
  	/**
  	 * Returns the datatype of this value
  	 * 
  	 * @return Datatype
  	 */
  	public final int getDataType() {
  		return dataType;
  	}
  
  }
  