/*
 * RefRefVectorMV.java
 * Reference Vector used for inter-frame Encoding and Decoding with ME and MC.
 * It extends RefVector defined in ../12/.
 */

class RefVectorMV extends RefVector {
  public RGBImage ref_frame;
  public Tss tss;
  
  //constructor
  public RefVectorMV ( CircularQueue q )
  {
    super ( q );
    ref_frame = new RGBImage ( q.width, q.height );
    tss = new Tss ( q.width, q.height );
  }

  //get the reference point
  void get_ref_point (   Point2 cp, Vec2 mvs[], Point2 ref_point )
  {
    Vec2 v = new Vec2();    //zero vector
    Point2 p = new Point2();
    p.set ( cp );
    for ( int i = 0; i < 3; i++ )
      p.plus( mvs[i] );

    ref_point.set( p );
  }

  //obtain difference between current and reference macroblock
  //  update the reference macroblock
  void current_ref_diff ( YCbCr_MACRO mp, Point2 ref_point, YCbCr_MACRO diff,
                            int nm  )
  {
    RGB_MACRO rgb_macro = new RGB_MACRO();
    YCbCr_MACRO refm = new YCbCr_MACRO();
    RgbYcc rgbYcc = new RgbYcc(); 
    tss.getRGBmacro ( ref_frame, ref_point, rgb_macro );

    rgbYcc.macroblock2ycbcr ( rgb_macro, refm );         //convert from RGB to YCbCr
    for ( int i = 0; i < 256; i++ )
      diff.Y[i] = (short) mp.Y[i] - (short) refm.Y[i];
    for ( int i = 0; i < 64; ++i ) {
      diff.Cb[i] = (short) mp.Cb[i] - (short) refm.Cb[i];
      diff.Cr[i] = (short) mp.Cr[i] - (short) refm.Cr[i];
    }
    //save the reference macroblock for reconstruction
    YCbCr_MACRO aMacro;
    aMacro = ycc_refv.get(nm);
    for ( int i = 0; i < 256; ++i ){
      aMacro.Y[i] = refm.Y[i];
      if ( i < 64 ) {
         aMacro.Cb[i] = refm.Cb[i];
         aMacro.Cr[i] = refm.Cr[i];
      }
    }
    ycc_refv.set( nm, aMacro );
  }

  //reconstruct frame from the vector of  reconstructed macros 
  void reconstruct_frame ( int number_of_macros )
  {
    int row, col, i, j, k, r;
    RGB_MACRO rgb_macro = new RGB_MACRO();
    RgbYcc rgbYcc = new RgbYcc();
    int width = ref_frame.width, height = ref_frame.height;
 
    //ycc_refv is data member of parent
    row = col = 0;
    YCbCr_MACRO ycbcr_macro;
    for ( k = 0; k < number_of_macros; ++k ){
      ycbcr_macro = ycc_refv.get ( k );                  //get k-th YCbCr macro
      rgbYcc.ycbcr2macroblock( ycbcr_macro, rgb_macro ); //converts to RGB
      
      int offset = row * width + col;                    //points to beginning of macroblock
      r = 0;
      for ( i = 0; i < 16; ++i ) {
        for ( j = 0; j < 16; ++j ) {
          ref_frame.ibuf[offset].R  = rgb_macro.rgb[r].R;
          ref_frame.ibuf[offset].G  = rgb_macro.rgb[r].G;
          ref_frame.ibuf[offset].B  = rgb_macro.rgb[r].B;
          offset++;  r++;
        }
        offset += ( width - 16 );                        //points to next row of macroblock
      }
      col += 16;
      if ( col >= width ){
        row += 16;                                       //next row of frame
        col = 0;
      }
    }  //for k;
  }

  //summing the difference and the reference to recover 'actual' values
  // mp points to the output; for decoding.
  void current_ref_sum ( YCbCr_MACRO mp, Point2 ref_point, YCbCr_MACRO diff, int nm )
  {
    RGB_MACRO rgb_macro = new RGB_MACRO();
    YCbCr_MACRO refm = new YCbCr_MACRO();
    RgbYcc rgbYcc = new RgbYcc();
    tss.getRGBmacro ( ref_frame, ref_point, rgb_macro );
    rgbYcc.macroblock2ycbcr ( rgb_macro, refm );  //convert from RGB to YCbCr

    for ( int i = 0; i < 256; ++i )
      mp.Y[i] = diff.Y[i] + (short) refm.Y[i];
    for ( int i = 0; i < 64; ++i ) {
      mp.Cb[i] = diff.Cb[i] + (short) refm.Cb[i];
      mp.Cr[i] = diff.Cr[i] + (short) refm.Cr[i];
    }
    //save the reference macroblock for reconstruction
    //  ycc_refv is data member of parent, vector of YCbCr_MACRO
    YCbCr_MACRO aMacro;
    aMacro = get ( nm );       //get() is method of parent class
    for ( int i = 0; i < 256; ++i ){
      aMacro.Y[i] = refm.Y[i];
      if ( i < 64 ) {
         aMacro.Cb[i] = refm.Cb[i];
         aMacro.Cr[i] = refm.Cr[i];
      }
    }
    ycc_refv.set( nm, aMacro );
  }
}
