#include "../const.h"
#include <math.h>
#include "ProcessExpression.h"
#include "BlockMatching.h"
#include "BMP.h"


// This function is responsible for the processing of the face expression:
// it performs block matching in order to derive the eybrow and mouth motions,
// and computes the eyes aperture with respect to the neutral expression.
bool
ProcessExpression(const Image& im_expanded, const Image& im_expression, const Image& im_expr_clust, int* face_centroid, int* face_bb,
                  const Image& im_expr_cr, const Image& eye_left, const Image& eye_right, const Image& im_cr, 
                  Block* blocks, int& eyes_status, const Init_para& parameters, int counter)
{

int* face_movement;
bool result;

#ifdef FUNC_TRACK
PRN(("Starting ProcessExpression\n"));
#endif


                                                                 // Block Matching
result = BlockMatching(blocks, im_expanded, im_expression, im_expr_clust, face_centroid, face_bb, face_movement, parameters, counter);
if (!result) {
   PRN(("Block Matching failed.\n"));
   return false;
}
 	                                                        // Eyes aperture...
result = ComputeEyesAperture(eye_left, eye_right, im_cr, im_expr_cr, face_movement, eyes_status, parameters, counter);
if (!result) {
   PRN(("Could not correctly define eye aperture.\n"));
   return false;
}

// Freeing memory...
free(face_movement);

#ifdef FUNC_TRACK
PRN(("Ending ProcessExpression\n"));
#endif

return true;

}


// This function computes the eyes aperture state, comparing the aperture state for both eyes.
bool
ComputeEyesAperture(const Image& eye_left, const Image& eye_right, const Image& im_cr, const Image& im_expr_cr,
                    int* face_movement, int& eyes_status, const Init_para& parameters, int counter)
{

int state_left, state_right;
bool result;

#ifdef FUNC_TRACK
PRN(("Starting ComputeEyesAperture\n"));
#endif

// left eye
result = ComputeOneEyeAperture(eye_left, im_cr, im_expr_cr, face_movement, state_left, parameters, counter);
if (!result)
   return false;

// right eye
result = ComputeOneEyeAperture(eye_right, im_cr, im_expr_cr, face_movement, state_right, parameters, counter);
if (!result)
   return false;

// eyes aperture decision
if (state_left == state_right)
   eyes_status = state_left;
else
   eyes_status = NO_EYE;


#ifdef FUNC_TRACK
PRN(("Ending ComputeEyesAperture\n"));
#endif

return true;

}

// This function computes the eye aperture state, comparing the aperture state in 
// the neutral image and in the expression image.
bool
ComputeOneEyeAperture(const Image& eye, const Image& im_cr, const Image& im_expr_cr, 
                      int* face_movement, int& status, const Init_para& parameters, int counter)
{

bool result;
int area_neutral, area_expr, th = 0;
int* bb;
Image cropped, cropped_exp, th_neutral, th_expr;

#ifdef FUNC_TRACK
PRN(("Starting ComputeOneEyeAperture\n"));
#endif

// Getting eye bounding box
result = BoundingBox(eye, 0, bb);
if (!result)
   return false;
bb[0] += eye.offsetX; 
bb[1] += eye.offsetX;
bb[2] += eye.offsetY;
bb[3] += eye.offsetY;


// Enlarging bounding box in order not lo lose details...
bb[0] -= (int) (parameters.add_eye * im_cr.width);
if (bb[0] < 0)
   bb[0] = 0;
bb[1] += (int) (parameters.add_eye * im_cr.width);
if (bb[1] >= im_cr.height)
   bb[1] = im_cr.height - 1;
bb[2] -= (int) (parameters.add_eye * im_cr.height);
if (bb[2] < 0)
   bb[2] = 0;
bb[3] += (int) (parameters.add_eye * im_cr.height);
if (bb[3] >= im_cr.height)
   bb[3] = im_cr.height - 1;


// Cropping eye image on the cr image (neutral expression)
result = CropImage(bb, im_cr, cropped, NO_BORDER);
if (!result)
   return false;

// Cropping eye image on the cr image (expression image)
// Face movement is taken into account
bb[0] += (face_movement[0]/4);
bb[1] += (face_movement[0]/4);
bb[2] += (face_movement[1]/4);
bb[3] += (face_movement[1]/4);
result = CropImage(bb, im_expr_cr, cropped_exp, NO_BORDER);
if (!result)
   return false;

// Thresholding the cr-eye images
result = ThresholdPerc(cropped, th_neutral, parameters.perc_eye_th, BLACK, WHITE, th);
if (!result)
   return false;
result = Threshold(cropped_exp, BLACK, th, th_expr);
if (!result)
   return false;

// Computing eye aperture...
area_neutral = Area(th_neutral);
area_expr = Area(th_expr);

// if the two areas differ little, we infer the eye has been neutral in our frames...
if (abs(area_neutral - area_expr) < (area_neutral * parameters.eye_status_thres))
   status = NEUTRAL_EYE;
else if (area_neutral > area_expr)
   status = CLOSING_EYE;
else if (area_neutral < area_expr)
   status = OPENING_EYE;


// Debug
if (parameters.debug_eyesap) {
    BMP bmp;
    char name[MAX_LENGTH_FILE];

    sprintf(name, "%s%s_neu%d.bmp", DATA_FOLDER, parameters.file_debug_eyesap, counter);
    bmp.Write2File(name, th_neutral);
    sprintf(name, "%s%s_exp%d.bmp", DATA_FOLDER, parameters.file_debug_eyesap, counter);
    bmp.Write2File(name, th_expr);

    PRN(("Eye status: %d. %d -> %d\n", status, area_neutral, area_expr));
    PRN(("Threshold: %d\n", th));
}


// Freeing memory
free(bb);
FreeImg(cropped);
FreeImg(cropped_exp);
FreeImg(th_expr);
FreeImg(th_neutral);

#ifdef FUNC_TRACK
PRN(("Ending ComputeOneEyeAperture\n"));
#endif

return true;

}




