/*
 * Run.java
 * Encode and decode a block of 64 DCT coefficients using
 * 3D run-level codewoards.
 */
import java.io.*;

class Run {
  /*
    Input: 64 quantized DCT coefficients in Y[][].
    Output: 3D run-level codewords in runs[].
  */
  void run_block ( short [][] Y, Run3D [] runs )
  {
    byte run_length = 0, k = 0;
    for ( int i = 0; i < 8; i++ ) {
      for ( int j = 0; j < 8; j++ ) {
        if ( Y[i][j] == 0  ) {
          run_length++;
          continue;
        }
        runs[k].run = run_length;
        runs[k].level = Y[i][j];
        runs[k].last = 0;
        run_length = 0;
        k++;
      }
    } 
    if ( k > 0 )
      runs[k-1].last = 1;       //last nonzero element
    else {                      //whole block 0
      runs[0].run = 64;
      runs[0].level = 0;
      runs[0].last = 1;         //this needs to be 1 to terminate
    }
  }

  /*
   *   Input: 3D run-level codewords of a macroblock in runs[].
   *   Output: 64 DCT coefficients in Y[][].
   */
  void run_decode ( Run3D [] runs, short [][] Y )
  {
    int i, j, r, k = 0, n = 0;
   
    while ( n < 64 ) {
      for ( r = 0;  r < runs[k].run; r++ ){
        i = n / 8;
        j = n % 8;
        Y[i][j] = 0;
        n++;
      }
      if ( n < 64 ){
        i = n / 8;
        j = n % 8;
        Y[i][j] = runs[k].level;
        n++;
      }
      if ( runs[k].last != 0 ) break;
      k++;
    }

    //run of 0s to end
    while ( n < 64 ) {
      i = n / 8;
      j = n % 8;
      Y[i][j] = 0;
      n++;
    }
  }

  //Get 64 sample values from in and put them in Y[][]
  int get64 ( short Y[][], DataInputStream in )
  {
    short n = 0;

    for ( int i = 0; i < 8; ++i )
      for ( int j = 0; j < 8; ++j )
         try {
           Y[i][j] = in.readShort();
           n++;
         } catch (IOException e) {
           return 0;
         }

    return n;
  }

  //Save the 64 sample values of Y[][] to out
  int put64 ( short Y[][], DataOutputStream out )
  {
    short n = 0;

    for ( int i = 0; i < 8; ++i )
      for ( int j = 0; j < 8; ++j )
         try {
           out.writeShort( Y[i][j] );
           n++;
         } catch (IOException e) {
           return 0;
         }

    return n;
  }

  //print one 8x8 sample block
  void print_block( short [][] X )
  {
    for ( int i = 0; i < 8; ++i ){
      System.out.printf("\n");
      for ( int j = 0; j < 8; ++j ) {
        System.out.printf("%6d, ", X[i][j] );
      }
    }
  }

  //print the run-level codewords of one block
  void print_run( Run3D runs[] )
  {
    short k = 0, len = 0, count = 0;

    while ( len < 64 ) {
      if ( count % 4 == 0 ) System.out.printf("\n");
      System.out.printf( "(%2d, %3d, %1d)    ", runs[k].run, runs[k].level, runs[k].last );
      len += (short) runs[k].run;
      ++len;
      if ( runs[k].last != 0  ) break;
        count++;
      k++;
    }
    System.out.printf("\n");
  }
}
