/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.media.format.image.iio;

import javax.imageio.metadata.IIOMetadata;

import org.w3c.dom.Node;

/**
 * <code>MediaHeader</code> based on the Standard (Plug-in Neutral) 
 * Metadata Format Specification of the Java Image I/O API.
 *
 * @version <tt>$Revision: 1.1 $</tt>
 * @author <a href="mailto:ricardoarguello@users.sourceforge.net">Ricardo Argüello</a>
 */
public class StandardMediaHeader extends IIOMediaHeader
{
   // FIXME
   private static final long serialVersionUID = 0L;

   private static final String STANDARD_METADATA_FORMAT_NAME =
      "javax_imageio_1.0";

   private static final String[] FIELD_NAMES =
      {
         "colorSpaceType",
         "numChannels",
         "gamma",
         "blackIsZero",
         "compressionTypeName",
         "lossless",
         "numProgressiveScans",
         "bitRate",
         "planarConfiguration",
         "sampleFormat",
         "bitsPerSample",
         "significantBitsPerSample",
         "sampleMSB",
         "pixelAspectRatio",
         "imageOrientation",
         "horizontalPixelSize",
         "verticalPixelSize",
         "horizontalPhysicalPixelSpacing",
         "verticalPhysicalPixelSpacing",
         "horizontalPosition",
         "verticalPosition",
         "horizontalPixelOffset",
         "verticalPixelOffset",
         "horizontalScreenSize",
         "verticalScreenSize",
         "formatVersion",
         "subimageInterpretation",
         "imageCreationYear" };

   /**
    * Constructor.
    *
    * @param metadata
    * @param metadataFormat
    */
   public StandardMediaHeader(IIOMetadata imageMetadata)
   {
      super(imageMetadata, STANDARD_METADATA_FORMAT_NAME);
   }

   /**
    * @see javax.emb.MediaHeader#getFieldNames()
    */
   public String[] getFieldNames()
   {
      return FIELD_NAMES;
   }

   /**
    * @see javax.emb.MediaHeader#getField(java.lang.String)
    */
   public Object getField(String fieldname)
   {
      Object field = null;

      if (fieldname.equals("colorSpaceType"))
      {
         field = getColorSpaceType();
      }

      if (fieldname.equals("numChannels"))
      {
         field = getNumChannels();
      }

      if (fieldname.equals("gamma"))
      {
         field = new Float(getGamma());
      }

      if (fieldname.equals("blackIsZero"))
      {
         field = getBlackIsZero();
      }

      if (fieldname.equals("compressionTypeName"))
      {
         field = getCompressionTypeName();
      }

      if (fieldname.equals("lossless"))
      {
         field = getLossless();
      }

      if (fieldname.equals("numProgressiveScans"))
      {
         field = new Integer(getNumProgressiveScans());
      }

      if (fieldname.equals("bitRate"))
      {
         field = new Float(getBitRate());
      }

      if (fieldname.equals("planarConfiguration"))
      {
         field = getPlanarConfiguration();
      }

      if (fieldname.equals("sampleFormat"))
      {
         field = getSampleFormat();
      }

      if (fieldname.equals("bitsPerSample"))
      {
         field = getBitsPerSample();
      }

      if (fieldname.equals("significantBitsPerSample"))
      {
         field = getSignificantBitsPerSample();
      }

      if (fieldname.equals("sampleMSB"))
      {
         field = getSampleMSB();
      }

      if (fieldname.equals("pixelAspectRatio"))
      {
         field = new Float(getPixelAspectRatio());
      }

      if (fieldname.equals("imageOrientation"))
      {
         field = getImageOrientation();
      }

      if (fieldname.equals("horizontalPixelSize"))
      {
         field = new Float(getHorizontalPixelSize());
      }

      if (fieldname.equals("verticalPixelSize"))
      {
         field = new Float(getVerticalPixelSize());
      }

      if (fieldname.equals("horizontalPhysicalPixelSpacing"))
      {
         field = new Float(getHorizontalPhysicalPixelSpacing());
      }

      if (fieldname.equals("verticalPhysicalPixelSpacing"))
      {
         field = new Float(getVerticalPhysicalPixelSpacing());
      }

      if (fieldname.equals("horizontalPosition"))
      {
         field = new Float(getHorizontalPosition());
      }

      if (fieldname.equals("verticalPosition"))
      {
         field = new Float(getVerticalPosition());
      }

      if (fieldname.equals("horizontalPixelOffset"))
      {
         field = new Integer(getHorizontalPixelOffset());
      }

      if (fieldname.equals("verticalPixelOffset"))
      {
         field = new Integer(getVerticalPixelOffset());
      }

      if (fieldname.equals("horizontalScreenSize"))
      {
         field = new Integer(getHorizontalScreenSize());
      }

      if (fieldname.equals("verticalScreenSize"))
      {
         field = new Integer(getVerticalScreenSize());
      }

      if (fieldname.equals("formatVersion"))
      {
         field = getFormatVersion();
      }

      if (fieldname.equals("subimageInterpretation"))
      {
         field = getSubimageInterpretation();
      }

      if (fieldname.equals("imageCreationYear"))
      {
         field = new Integer(getImageCreationYear());
      }

      return field;
   }

   /**
    * The raw color space of the image.
    *
    * @return "XYZ", "Lab", "Luv", "YCbCr", "Yxy", "YCCK", "PhotoYCC", "RGB", 
    *          "GRAY", "HSV", "HLS", "CMYK", "CMY", "2CLR", "3CLR", "4CLR", 
    *          "5CLR", "6CLR", "7CLR", "8CLR", "9CLR", "ACLR", "BCLR", "CCLR", 
    *          "DCLR", "ECLR" or "FCLR".
    */
   public String getColorSpaceType()
   {
      Node chroma = getChromaNode();
      Node colorSpaceType = getNode(chroma, "ColorSpaceType");
      return getAttribute(colorSpaceType, "name");
   }

   /**
    * The number of channels in the raw image, including alpha.
    *
    * @return number of channels.
    */
   public String getNumChannels()
   {
      Node chroma = getChromaNode();
      Node numChannels = getNode(chroma, "NumChannels");
      return getAttribute(numChannels, "value");
   }

   /**
    * The image gamma.
    *
    * @return gamma.
    */
   public float getGamma()
   {
      Node chroma = getChromaNode();
      Node gamma = getNode(chroma, "Gamma");
      String value = getAttribute(gamma, "value");
      return Float.parseFloat(value);
   }

   /**
    * True if smaller values represent darker shades.
    *
    * @return "TRUE" or "FALSE".
    */
   public String getBlackIsZero()
   {
      Node chroma = getChromaNode();
      Node blackIsZero = getNode(chroma, "BlackIsZero");
      return getAttribute(blackIsZero, "value");
   }

   /**
    * The name of the compression scheme in use.
    *
    * @return compression type name.
    */
   public String getCompressionTypeName()
   {
      Node compression = getCompressionNode();
      Node compressionTypeName = getNode(compression, "CompressionTypeName");
      return getAttribute(compressionTypeName, "value");
   }

   /**
    * True if the compression scheme is lossless.
    *
    * @return lossless.
    */
   public String getLossless()
   {
      Node compression = getCompressionNode();
      Node lossless = getNode(compression, "Lossless");
      return getAttribute(lossless, "value");
   }

   /**
    * The number of progressive scans used in the image encoding.
    *
    * @param number of progressive scans.
    */
   public int getNumProgressiveScans()
   {
      Node compression = getCompressionNode();
      Node numProgressiveScans = getNode(compression, "NumProgressiveScans");
      String value = getAttribute(numProgressiveScans, "value");
      return Integer.parseInt(value);
   }

   /**
    * The estimated bit rate of the compression scheme.
    *
    * @return bit rate.
    */
   public float getBitRate()
   {
      Node compression = getCompressionNode();
      Node bitRate = getNode(compression, "BitRate");
      String value = getAttribute(bitRate, "value");
      return value == null ? 0 : Float.parseFloat(value);
   }

   /**
    * The organization of image samples in the stream.
    *
    * @return "PixelInterleaved", "PlaneInterleaved", "LineInterleaved" or 
    *          "TileInterleaved".
    */
   public String getPlanarConfiguration()
   {
      Node data = getDataNode();
      Node planarConfiguration = getNode(data, "PlanarConfiguration");
      return getAttribute(planarConfiguration, "value");
   }

   /**
    * The numeric format of image samples.
    *
    * @return "SignedIntegral", "UnsignedIntegral", "Real" or "Index".
    */
   public String getSampleFormat()
   {
      Node data = getDataNode();
      Node sampleFormat = getNode(data, "SampleFormat");
      return getAttribute(sampleFormat, "value");
   }

   /**
    * The number of bits per sample.
    *
    * @return bits per sample.
    */
   public String getBitsPerSample()
   {
      Node data = getDataNode();
      Node bitsPerSample = getNode(data, "BitsPerSample");
      return getAttribute(bitsPerSample, "value");
   }

   /**
    * The number of significant bits per sample.
    *
    * @return significant bits per sample.
    */
   public String getSignificantBitsPerSample()
   {
      Node data = getDataNode();
      Node significantBitsPerSample = getNode(data, "SignificantBitsPerSample");
      return getAttribute(significantBitsPerSample, "value");
   }

   /**
    * The position of the most significant bit of each sample.
    *
    * @return sample most significant bit.
    */
   public String getSampleMSB()
   {
      Node data = getDataNode();
      Node sampleMSB = getNode(data, "SampleMSB");
      return getAttribute(sampleMSB, "value");
   }

   /**
    * The width of a pixel divided by its height.
    *
    * @return pixel aspect ratio.
    */
   public float getPixelAspectRatio()
   {
      Node dimension = getDimensionNode();
      Node pixelAspectRatio = getNode(dimension, "PixelAspectRatio");
      String value = getAttribute(pixelAspectRatio, "value");
      return Float.parseFloat(value);
   }

   /**
    * The desired orientation of the image in terms of flips and 
    * counter-clockwise rotations.
    *
    * @return image orientation.
    */
   public String getImageOrientation()
   {
      Node dimension = getDimensionNode();
      Node imageOrientation = getNode(dimension, "ImageOrientation");
      return getAttribute(imageOrientation, "value");
   }

   /**
    * The width of a pixel, in millimeters, as it should be rendered on media.  
    *
    * @return horizontal pixel size.
    */
   public float getHorizontalPixelSize()
   {
      Node dimension = getDimensionNode();
      Node horizontalPixelSize = getNode(dimension, "HorizontalPixelSize");
      String value = getAttribute(horizontalPixelSize, "value");
      return Float.parseFloat(value);
   }

   /**
    * The height of a pixel, in millimeters, as it should be rendered on media.  
    *
    * @return vertical pixel size.
    */
   public float getVerticalPixelSize()
   {
      Node dimension = getDimensionNode();
      Node verticalPixelSize = getNode(dimension, "VerticalPixelSize");
      String value = getAttribute(verticalPixelSize, "value");
      return Float.parseFloat(value);
   }

   /**
    * The horizontal distance in the subject of the image, in millimeters, 
    * represented by one pixel at the center of the image.  
    *
    * @return horizontal physical pixel spacing.
    */
   public float getHorizontalPhysicalPixelSpacing()
   {
      Node dimension = getDimensionNode();
      Node horizontalPhysicalPixelSpacing =
         getNode(dimension, "HorizontalPhysicalPixelSpacing");
      String value = getAttribute(horizontalPhysicalPixelSpacing, "value");
      return value == null ? 0 : Float.parseFloat(value);
   }

   /**
    * The vertical distance in the subject of the image, in millimeters, 
    * represented by one pixel at the center of the image.
    *
    * @return vertical physical pixel spacing.
    */
   public float getVerticalPhysicalPixelSpacing()
   {
      Node dimension = getDimensionNode();
      Node verticalPhysicalPixelSpacing =
         getNode(dimension, "VerticalPhysicalPixelSpacing");
      String value = getAttribute(verticalPhysicalPixelSpacing, "value");
      return value == null ? 0 : Float.parseFloat(value);
   }

   /**
    * The horizontal position, in millimeters, where the image should be 
    * rendered on media.
    *
    * @return horizontal position.
    */
   public float getHorizontalPosition()
   {
      Node dimension = getDimensionNode();
      Node horizontalPosition = getNode(dimension, "HorizontalPosition");
      String value = getAttribute(horizontalPosition, "value");
      return value == null ? 0 : Float.parseFloat(value);
   }

   /**
    * The vertical position, in millimeters, where the image should be 
    * rendered on media.
    *
    * @return vertical position.
    */
   public float getVerticalPosition()
   {
      Node dimension = getDimensionNode();
      Node verticalPosition = getNode(dimension, "VerticalPosition");
      String value = getAttribute(verticalPosition, "value");
      return value == null ? 0 : Float.parseFloat(value);
   }

   /**
    * The horizonal position, in pixels, where the image should be rendered 
    * onto a raster display.
    *
    * @return horizontal pixel offset.
    */
   public int getHorizontalPixelOffset()
   {
      Node dimension = getDimensionNode();
      Node horizontalPixelOffset = getNode(dimension, "HorizontalPixelOffset");
      String value = getAttribute(horizontalPixelOffset, "value");
      return value == null ? 0 : Integer.parseInt(value);
   }

   /**
    * The vertical position, in pixels, where the image should be rendered 
    * onto a raster display.
    *
    * @return vertical pixel offset.
    */
   public int getVerticalPixelOffset()
   {
      Node dimension = getDimensionNode();
      Node verticalPixelOffset = getNode(dimension, "VerticalPixelOffset");
      String value = getAttribute(verticalPixelOffset, "value");
      return value == null ? 0 : Integer.parseInt(value);
   }

   /**
    * The width, in pixels, of the raster display into which the image should 
    * be rendered.
    *
    * @return horizontal screen size.
    */
   public int getHorizontalScreenSize()
   {
      Node dimension = getDimensionNode();
      Node horizontalScreenSize = getNode(dimension, "HorizontalScreenSize");
      String value = getAttribute(horizontalScreenSize, "value");
      return value == null ? 0 : Integer.parseInt(value);
   }

   /**
    * The height, in pixels, of the raster display into which the image should 
    * be rendered.
    *
    * @return vertical screen size.
    */
   public int getVerticalScreenSize()
   {
      Node dimension = getDimensionNode();
      Node verticalScreenSize = getNode(dimension, "VerticalScreenSize");
      String value = getAttribute(verticalScreenSize, "value");
      return value == null ? 0 : Integer.parseInt(value);
   }

   /**
    * The version of the format used by the stream.
    *
    * @return format version.
    */
   public String getFormatVersion()
   {
      Node document = getDocumentNode();
      Node formatVersion = getNode(document, "FormatVersion");
      return getAttribute(formatVersion, "value");
   }

   /**
    * The interpretation of this image in relation to the other images stored 
    * in the same stream.
    *
    * @return "Standalone", "SinglePage", "FullResolution", "ReducedResolution" 
    *          "PyramidLayer", "Preview", "VolumeSlice", "ObjectView", 
    *          "Panorama", "AnimationFrame", "TransparencyMask", 
    *          "CompositingLayer", "SpectralSlice" or "Unknown". 
    */
   public String getSubimageInterpretation()
   {
      Node document = getDocumentNode();
      Node subimageInterpretation = getNode(document, "SubimageInterpretation");
      return getAttribute(subimageInterpretation, "value");
   }

   /**
    * The full year of image creation (e.g., 1967, not 67).
    *
    * @return image creation year.
    */
   public int getImageCreationYear()
   {
      Node document = getDocumentNode();
      Node formatVersion = getNode(document, "ImageCreationTime");
      String value = getAttribute(formatVersion, "year");
      return value == null ? 0 : Integer.parseInt(value);
   }

   //-------------------------
   private Node getChromaNode()
   {
      return getNode("Chroma");
   }

   private Node getCompressionNode()
   {
      return getNode("Compression");
   }

   private Node getDataNode()
   {
      return getNode("Data");
   }

   private Node getDimensionNode()
   {
      return getNode("Dimension");
   }

   private Node getDocumentNode()
   {
      return getNode("Document");
   }

   /*    <!ELEMENT "Document" (FormatVersion?, SubimageInterpretation?, 
         ImageCreationTime?, ImageModificationTime?)>
         <!-- Document information --> 
   
   
         <!ELEMENT "ImageCreationTime" EMPTY>
           <!-- The time of image creation --> 
           <!ATTLIST "ImageCreationTime" "year" #CDATA #REQUIRED>
             <!-- The full year (e.g., 1967, not 67) --> 
             <!-- Data type: Integer -->
           <!ATTLIST "ImageCreationTime" "month" #CDATA #REQUIRED>
             <!-- The month, with January = 1 --> 
             <!-- Data type: Integer -->
             <!-- Min value: 1 (inclusive) -->
             <!-- Max value: 12 (inclusive) -->
           <!ATTLIST "ImageCreationTime" "day" #CDATA #REQUIRED>
             <!-- The day of the month --> 
             <!-- Data type: Integer -->
             <!-- Min value: 1 (inclusive) -->
             <!-- Max value: 31 (inclusive) -->
           <!ATTLIST "ImageCreationTime" "hour" #CDATA "0">
             <!-- The hour from 0 to 23 --> 
             <!-- Data type: Integer -->
             <!-- Min value: 0 (inclusive) -->
             <!-- Max value: 23 (inclusive) -->
           <!ATTLIST "ImageCreationTime" "minute" #CDATA "0">
             <!-- The minute from 0 to 59 --> 
             <!-- Data type: Integer -->
             <!-- Min value: 0 (inclusive) -->
             <!-- Max value: 59 (inclusive) -->
           <!ATTLIST "ImageCreationTime" "second" #CDATA "0">
             <!-- The second from 0 to 60 (60 = leap second) --> 
             <!-- Data type: Integer -->
             <!-- Min value: 0 (inclusive) -->
             <!-- Max value: 60 (inclusive) -->
   
         <!ELEMENT "ImageModificationTime" EMPTY>
           <!-- The time of the last image modification --> 
           <!ATTLIST "ImageModificationTime" "year" #CDATA #REQUIRED>
             <!-- The full year (e.g., 1967, not 67) --> 
             <!-- Data type: Integer -->
           <!ATTLIST "ImageModificationTime" "month" #CDATA #REQUIRED>
             <!-- The month, with January = 1 --> 
             <!-- Data type: Integer -->
             <!-- Min value: 1 (inclusive) -->
             <!-- Max value: 12 (inclusive) -->
           <!ATTLIST "ImageModificationTime" "day" #CDATA #REQUIRED>
             <!-- The day of the month --> 
             <!-- Data type: Integer -->
             <!-- Min value: 1 (inclusive) -->
             <!-- Max value: 31 (inclusive) -->
           <!ATTLIST "ImageModificationTime" "hour" #CDATA "0">
             <!-- The hour from 0 to 23 --> 
             <!-- Data type: Integer -->
             <!-- Min value: 0 (inclusive) -->
             <!-- Max value: 23 (inclusive) -->
           <!ATTLIST "ImageModificationTime" "minute" #CDATA "0">
             <!-- The minute from 0 to 59 --> 
             <!-- Data type: Integer -->
             <!-- Min value: 0 (inclusive) -->
             <!-- Max value: 59 (inclusive) -->
           <!ATTLIST "ImageModificationTime" "second" #CDATA "0">
             <!-- The second from 0 to 60 (60 = leap second) --> 
             <!-- Data type: Integer -->
             <!-- Min value: 0 (inclusive) -->
             <!-- Max value: 60 (inclusive) -->
   */
}