/*
 * Test_encode_ppm.java
 * Code testing the encoding and decoding of an RGB frame to and
 * from YCbCr format. The original RGB data are saved in a PPM
 * file.  The restored RGB data are saved in another PPM file.
*/
import java.io.*;
import java.awt.Frame;
import java.awt.image.*;
import javax.media.jai.JAI;
import javax.media.jai.RenderedOp;
import com.sun.media.jai.codec.FileSeekableStream;
import javax.media.jai.widget.ScrollingImagePanel;
import com.sun.media.jai.codec.PNMEncodeParam;

public class Test_encode_ppm {
  private static byte [] header = {'Y','C','b','C','r','4','2','0'};
   
  public static void write_ycc_header(int width, int height, 
                                               DataOutputStream out)
  {
    try {
       out.write ( header );
       out.writeInt ( width );
       out.writeInt ( height );
    } catch (IOException e) {
       e.printStackTrace();
       System.exit(0);
    }
  }

  public static int read_ycc_header( RGBImage rgbimage,  DataInputStream in)
  {
    byte [] bytes = new byte[header.length];
    try {
      in.read ( bytes );
      rgbimage.width  = in.readInt ();
      rgbimage.height = in.readInt ();
    } catch (IOException e) {
       e.printStackTrace();
       System.exit(0);
    }
    for ( int i = 0; i < header.length; ++i )
      if ( bytes[i] != header[i] )
	return -1;      //wrong header
   
    return 1;
  } 

  public static void main(String[] args) throws InterruptedException {
    if (args.length < 3) {
      System.out.println("Usage: java " + "Test_encode_ppm" +
        " input_ppm_filename output_ycc_filename recoverd_ppm_filename\n" +
        "e.g. java Test_encode_ppm ../data/beach.ppm t.ycc t.ppm");
      System.exit(-1);
    }

    /*
     * Create an input stream from the specified file name
     * to be used with the file decoding operator.
     */
     FileSeekableStream stream = null;
     try {
       stream = new FileSeekableStream(args[0]);
     } catch (IOException e) {
       e.printStackTrace();
       System.exit(0);
     }
  
    /* Create an operator to decode the image file. */
    RenderedOp image = JAI.create("stream", stream);

    /* Get the width and height of image. */
    int width = image.getWidth();
    int height = image.getHeight();

    if ( width % 16 != 0 || height % 16 != 0 ) {
      System.out.println("Program only works for image dimensions divisible");
      System.out.println("by 16. Use 'convert' to change image dimension.");
      System.exit(1);
    }
    int [] samples = new int[3*width*height];         
 
    Raster ras = image.getData();
    //save pixel RGB data in samples[]
    ras.getPixels( 0, 0, width, height, samples ); 
    RGBImage rgbimage = new RGBImage( width, height );
    //copy image data to RGBImage object buffer
    int isize = width * height;
    for ( int i = 0, k = 0; i < isize; ++i, k+=3 ) {
      rgbimage.ibuf[i].R =  samples[k];
      rgbimage.ibuf[i].G = samples[k+1];
      rgbimage.ibuf[i].B = samples[k+2];    
    }

    try {
      File f = new File ( args[1] );
      OutputStream o = new FileOutputStream( f );
      DataOutputStream out = new DataOutputStream ( o );
      write_ycc_header ( width, height, out );
      Encode enc = new Encode ();
      
      //save encoded data ( YCbCr ) in file specified by args[1]
      enc.encode ( rgbimage, out );
      out.close();
    } catch (IOException e) {
       e.printStackTrace();
       System.exit(0);
    }

    System.out.printf("\nEncoding done, YCbCr data saved in %s\n",args[1]);
    
    //read the YCbCr data back from file args[1] and convert to RGB 
    DataInputStream in;
    Decode ycc_decoder = new Decode ();
    try {
      File f = new File ( args[1] );
      InputStream ins = new FileInputStream( f );
      in = new DataInputStream ( ins );
      if ( read_ycc_header ( rgbimage,  in ) == -1 ){
        System.out.println("Not YCC File");
        return;
      }
      /*
        Decode data: convert YCbCr data from file args[1] to RGB.
        Restored RGB data returned via parameter rgbimage.
      */
      ycc_decoder.decode_yccFrame (rgbimage, in);
    } catch (IOException e) {
       e.printStackTrace();
       System.exit(0);
    }
    
    /*
      Now save RGB data in PPM format in the file specified by args[2].
    */
    isize = rgbimage.width * rgbimage.height;
    byte [] P6 = { 'P', '6', '\n' };
    byte [] colorLevels = { '2', '5', '5', '\n' };
    String sw = Integer.toString ( rgbimage.width ) + " ";
    String sh = Integer.toString ( rgbimage.height ) + "\n";
    byte [] bytes = new byte[3*isize];
    for ( int i = 0, k = 0; i < isize; i++, k+=3 ){
        bytes[k] = (byte) (rgbimage.ibuf[i].R); 
        bytes[k+1] = (byte) (rgbimage.ibuf[i].G); 
        bytes[k+2] = (byte) (rgbimage.ibuf[i].B);
     }
     try {
        File f = new File ( args[2] );
        OutputStream o = new FileOutputStream( f );
	DataOutputStream out = new DataOutputStream ( o );
        out.write ( P6 );
        out.writeBytes ( sw ); 
        out.writeBytes ( sh ); 
        out.write ( colorLevels );
        out.write ( bytes );   //save 8-bit RGB data
        out.close();
    } catch (IOException e) {
       e.printStackTrace();
       System.exit(0);
    }
    System.out.printf("Decoded data saved in %s \n", args[2] );
  }
}
