/*****************************************************************************
 "This software module was originally developed by:

	Noboru Yamaguchi (TOSHIBA CORPORATION), 
	Takashi Ida (TOSHIBA CORPORATION) 

	and edited by:

 	Toshiaki Watanabe (TOSHIBA CORPORATION), 
	Yoshihiro Kikuchi (TOSHIBA CORPORATION), 
	Noel Brady (TELTEC IRELAND)

	in the course of development of the <MPEG-4 Video(ISO/IEC 14496-2)>. This
  software module is an implementation of a part of one or more <MPEG-4 Video
  (ISO/IEC 14496-2)> tools as specified by the <MPEG-4 Video(ISO/IEC 14496-2)
  >. ISO/IEC gives users of the <MPEG-4 Video(ISO/IEC 14496-2)> free license
  to this software module or modifications thereof for use in hardware or
  software products claiming conformance to the <MPEG-4 Video(ISO/IEC 14496-2
  )>. Those intending to use this software module in hardware or software
  products are advised that its use may infringe existing patents. The
  original developer of this software module and his/her company, the
  subsequent editors and their companies, and ISO/IEC have no liability for
  use of this software module or modifications thereof in an implementation.
  Copyright is not released for non <MPEG-4 Video(ISO/IEC 14496-2)>
  conforming products. TOSHIBA CORPORATION retains full right to use the code
  for his/her own purpose, assign or donate the code to a third party and to
  inhibit third parties from using the code for non <MPEG-4 Video(ISO/IEC
  14496-2)> conforming products. This copyright notice must be included in
  all copies or derivative works. Copyright (c)1996".
 *****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "io_generic.h"
#include "momusys.h"
#include "mom_structs.h"
#include "mot_comp.h"
#include "mot_est.h"
#include "mot_padding.h"
#include "mot_util.h"
#include "vm_common_defs.h"
#include "vm_enc_defs.h"
#include "vm_config.h"
#include "vm_stats.h"
#include "vm_vop_bound.h"
#include "alp_common_def.h"
#include "alp_code_mc.h"
#include "alp_mv_tables.h"
#include "alp_common_mc.h"
#include "alp_common_util.h"

#define _ENCODE_DEBUG_MC
#define MVDs_RANGE 8

Int
FindPredAlphaAndMVmei (Vop *curr,
		       Int x,
		       Int y,
		       Int ox,
		       Int oy,
		       Image *mot_x,
		       Image *mot_y,
		       Image *motA_x,
		       Image *motA_y,
		       Image *MB_decisions, 
		       Image *alpha_decisions,
		       Image *modeA,
		       SInt* prev,
		       SInt* pred,
		       SInt* org,
		       Int width,
		       UInt width_prev, 
		       UInt height_prev, 
		       SInt mb_size,
		       Int thresh,
		       Int *DmotA_x,
		       Int *DmotA_y,
		       Int *mvda,
		       UChar *shape_stream)
{
  Int mvbits=0;
  Int i, j, ix, iy, m, n, ip, jp;
  Int sum_dis;
  Int min_mv_x, min_mv_y, min_dist;
  Int mvp_x, mvp_y, mvs_x, mvs_y;
  Int mv_bits, min_mv_bits;
  Int total=0, max_stream=32;
  SInt tmp_pred[16][16];
  Char tmp_stream[32];
	SInt binary_shape_only;
	Int error_res_disable;

	if (GetVopShape(curr) == BINARY_SHAPE_ONLY)   /* BSO_NOEL */
		binary_shape_only = 1;
	else
		binary_shape_only = 0;

	error_res_disable = GetVopErrorResDisable(curr);

  strcpy(tmp_stream, "");
#ifdef ENCODE_DEBUG_MC
  fprintf(stdout, "ENCODE:alphaMV (i,j)=(%2d,%2d)\n",(x/mb_size),(y/mb_size));
#endif

 if (GetVopPredictionType(curr)==B_VOP) 
     FindMVB (x,y,mot_x,mot_y,motA_x,motA_y,MB_decisions,modeA,
	     &mvp_x,&mvp_y,width,mb_size);
      else  
    FindMVP (x,y,mot_x,mot_y,motA_x,motA_y,MB_decisions,modeA,
	     	&mvp_x,&mvp_y,width,mb_size,MBM_TRANSPARENT,
				alpha_decisions,binary_shape_only,error_res_disable);    /* BSO_NOEL */
   /* changed by Minhua Zhou 24.07.1997 */

#ifdef ENCODE_DEBUG_MC
  fprintf(stdout, "MVP=(%3d,%3d) mode=%d\n",mvp_x,mvp_y,
	  ModeMB(MB_decisions,(x/mb_size),(y/mb_size)));
#endif

  /* DmotA = ( 0, 0 ) */
  min_mv_x = DmotA_x[0] = DmotA_x[1] = DmotA_x[2] = DmotA_x[3] = 0;
  min_mv_y = DmotA_y[0] = DmotA_y[1] = DmotA_y[2] = DmotA_y[3] = 0;
  FindPredAlpha4MC (x+ox,y+oy,mvp_x,mvp_y,prev,&tmp_pred[0][0],0,
		    width_prev,height_prev,mb_size);
  FindPredAlpha4MC (x+ox,y+oy,mvp_x,mvp_y,prev,&tmp_pred[0][8],1,
		    width_prev,height_prev,mb_size);
  FindPredAlpha4MC (x+ox,y+oy,mvp_x,mvp_y,prev,&tmp_pred[8][0],2,
		    width_prev,height_prev,mb_size);
  FindPredAlpha4MC (x+ox,y+oy,mvp_x,mvp_y,prev,&tmp_pred[8][8],3,
		    width_prev,height_prev,mb_size);
  for( i=0; i<4; i++ ) for( j=0; j<4; j++ ) {
    sum_dis = 0; 
    for( m=0; m<4; m++ ) for( n=0; n<4; n++ ) {
      ip = 4*i+m; jp = 4*j+n;
/*      sum_dis += ABS(*(org+ip*mb_size+jp) - tmp_pred[ip][jp]); */
				sum_dis += (*(org+ip*mb_size+jp) != tmp_pred[ip][jp]);
    }
		sum_dis*=255;
    if( sum_dis > (16*thresh) ) goto EXIT1;
  }
  *mvda = 1;
  SetAlphaMV (x,y,motA_x,motA_y,mvp_x,mvp_y,width,mb_size);
  goto EXIT2;

 EXIT1:
  min_dist = 65535;
  min_mv_bits = 100;
  for( iy=-MVDs_RANGE; iy<=MVDs_RANGE; iy++ ) 
		for( ix=-MVDs_RANGE; ix<=MVDs_RANGE; ix++ ) {
		sum_dis = 0;
    FindAdress (mvp_x,mvp_y,ix,iy,&mvs_x,&mvs_y);

    FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[0][0],0,
		      width_prev,height_prev,mb_size);
		for (i=0; i<8; i++)
			for (j=0; j<8; j++)
				if (org[i*mb_size+j] != tmp_pred[i][j])
					if ((sum_dis += 255) > min_dist)
						goto nextplease;

    FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[0][8],1,
		      width_prev,height_prev,mb_size);
		for (i=0; i<8; i++)
			for (j=8; j<mb_size; j++)
				if (org[i*mb_size+j] != tmp_pred[i][j])
					if ((sum_dis += 255) > min_dist)
						goto nextplease;

    FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[8][0],2,
		      width_prev,height_prev,mb_size);
		for (i=8; i<mb_size; i++)
			for (j=0; j<8; j++)
				if (org[i*mb_size+j] != tmp_pred[i][j])
					if ((sum_dis += 255) > min_dist)
						goto nextplease;

    FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[8][8],3,
		      width_prev,height_prev,mb_size);
		for (i=8; i<mb_size; i++)
			for (j=8; j<mb_size; j++)
				if (org[i*mb_size+j] != tmp_pred[i][j])
					if ((sum_dis += 255) > min_dist)
						goto nextplease;

		if( ix==0 && iy==0 ) 
			{
      	mv_bits = 1;
    	} 
		else if( ix == 0 ) mv_bits = 2*abs(ix)+2*abs(iy)+1;
    else mv_bits = 2*abs(ix)+2*abs(iy)+2;
    
		if( sum_dis < min_dist ) 
			{
				min_mv_x = ix; min_mv_y = iy;
				min_dist = sum_dis;
				min_mv_bits = mv_bits;
    	} 
		else if( sum_dis == min_dist ) 
			{
				if( mv_bits < min_mv_bits ) 
					{
						min_mv_x = ix; min_mv_y = iy;
						min_dist = sum_dis;
						min_mv_bits = mv_bits;
      		} 
				else 
					if( mv_bits == min_mv_bits ) 
						{
							if( abs(iy) < abs(min_mv_y) ) 
								{
									min_mv_x = ix; min_mv_y = iy;
									min_dist = sum_dis;
									min_mv_bits = mv_bits;
								} 
								else 
									if( abs(iy) == abs(min_mv_y) ) 
										{
											if( abs(ix) < abs(min_mv_x) ) 
												{
	    										min_mv_x = ix; min_mv_y = iy;
													min_dist = sum_dis;
													min_mv_bits = mv_bits;
	  										}
										}
      			}
    	}

		nextplease:
			;
  }

  if(min_mv_x==0 && min_mv_y == 0) {
    *mvda = 1;
    goto EXIT3;
  }
  *mvda = 0;
  strcat(tmp_stream, Cmvds[ABS(min_mv_x)]);
  mvbits += strlen(Cmvds[ABS(min_mv_x)]);
#ifdef ENCODE_DEBUG_MC
  fprintf(stdout, "MVDs        %s      (%d)[H]\n",Cmvds[ABS(min_mv_x)],
	  strlen(Cmvds[ABS(min_mv_x)]));
#endif
  if( min_mv_x < 0 ) {
    strcat(tmp_stream, "0");
    mvbits++;
#ifdef ENCODE_DEBUG_MC
    fprintf(stdout, "MVDs        %s      (%d)[S]\n","0",1);
#endif
  } else if( min_mv_x > 0 ) {
    strcat(tmp_stream, "1");
    mvbits++;
#ifdef ENCODE_DEBUG_MC
    fprintf(stdout, "MVDs        %s      (%d)[S]\n","1",1);
#endif
  }
  if( min_mv_x == 0 ) {
    strcat(tmp_stream, Cmvds[ABS(min_mv_y)-1]);
    mvbits += strlen(Cmvds[ABS(min_mv_y)-1]);
#ifdef ENCODE_DEBUG_MC
    fprintf(stdout, "MVDs        %s      (%d)[V2]\n",Cmvds[ABS(min_mv_y)-1],
	    strlen(Cmvds[ABS(min_mv_y)-1]));
#endif
  } else {
    strcat(tmp_stream, Cmvds[ABS(min_mv_y)]);
    mvbits += strlen(Cmvds[ABS(min_mv_y)]);
#ifdef ENCODE_DEBUG_MC
    fprintf(stdout, "MVDs        %s      (%d)[V1]\n",Cmvds[ABS(min_mv_y)],
	    strlen(Cmvds[ABS(min_mv_y)]));
#endif
  }
  if( min_mv_y < 0 ) {
    strcat(tmp_stream, "0");
    mvbits++;
#ifdef ENCODE_DEBUG_MC
    fprintf(stdout, "MVDs        %s      (%d)[S]\n","0",1);
#endif
  } else if( min_mv_y > 0 ) {
    strcat(tmp_stream, "1");
    mvbits++;
#ifdef ENCODE_DEBUG_MC
    fprintf(stdout, "MVDs        %s      (%d)[S]\n","1",1);
#endif
  }

 EXIT3:
#ifdef ENCODE_DEBUG_MC
  fprintf(stdout, "MVDs=(%3d,%3d)\n",min_mv_x,min_mv_y);
#endif
  FindAdress (mvp_x,mvp_y,min_mv_x,min_mv_y,&mvs_x,&mvs_y);
  FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[0][0],0,
		    width_prev,height_prev,mb_size);
  FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[0][8],1,
		    width_prev,height_prev,mb_size);
  FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[8][0],2,
		    width_prev,height_prev,mb_size);
  FindPredAlpha4MC (x+ox,y+oy,mvs_x,mvs_y,prev,&tmp_pred[8][8],3,
		    width_prev,height_prev,mb_size);
  DmotA_x[0] = DmotA_x[1] = DmotA_x[2] = DmotA_x[3] = min_mv_x;
  DmotA_y[0] = DmotA_y[1] = DmotA_y[2] = DmotA_y[3] = min_mv_y;

  SetAlphaMV (x,y,motA_x,motA_y,mvs_x,mvs_y,width,mb_size);    

 EXIT2:
  StreamOut(shape_stream, &total, &max_stream, tmp_stream);

  for( i=0; i<mb_size*mb_size; i++ ) *(pred+i) = *(&tmp_pred[0][0]+i);

  return(mvbits);
}

Int NewSad(SInt *org, SInt tmp_pred[16][16], Int mb_size)
{
	Int i,j,sum_dis;

    sum_dis = 0;
    for( i=0; i<mb_size; i++) for( j=0; j<mb_size; j++ ) {
			if (ContPel(org,j,i)) {
      	sum_dis += ABS(*(org+i*mb_size+j) - tmp_pred[i][j]);
			}
    }
		return sum_dis;
}


Int ContPel(SInt *org, Int x0, Int y0)
{
	Int i,j;
	Int black, white;

	if (x0 == 0 || y0 == 0 || x0 == 15 || y0 == 15) return 1;
	else 
		{
			white = black = 0;
			for (i=-1;i<=1;i++)
				for (j=-1;j<=1;j++)
					{
						if (org[16*(y0+i)+(x0+j)] == 0) white = 1;
						else black = 1;
					}
			if (black & white) return 1;
		}

	return 0;
}

