#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <stdio.h>
#include <dirent.h>

#define FALSE 0
#define TRUE !FALSE
#define DEBUG 0

#include "CamImage.h"
#include "FW/labImage.h"
#include <iostream>
#include "ImprovMain.h"
#include "Camera.h"

extern char img_path[];
extern char seq_path[];
extern int subscale;
extern int factor;
extern char seqfilenames[][MAXSEQNAMELEN];
extern int  seqfile_len;
extern char seqfile_info;
extern char seqfile_source[];

#ifndef MAX
#define MAX(a,b) ((a)>=(b)?(a):(b))
#endif
#ifndef MIN
#define MIN(a,b) ((a)>=(b)?(b):(a))
#endif

int restart=0; 
int cameraon_off=1;
int seq_cam=0;
int which_cam=0;
extern int nr_cameras;
extern Camera *cameras[];

int alphasort(const struct dirent **a, const struct dirent **b);
struct dirent **seqdirs;
struct dirent **seqfiles;

#define MENU_ITEM_SEQ  15     /* max no. of sequences */
Improv_Menu_Item menu_items[MENU_ITEM_SEQ+1] = 
{ {"Camera On Off",E_CameraOn_Off, 0},
    
  {"Sequences/S1 ",E_S1, 0},
  {"Sequences/S2 ",E_S2, 0},
  {"Sequences/S3 ",E_S3, 0},
  {"Sequences/S4 ",E_S4, 0},
  {"Sequences/S5 ",E_S5, 0},
  {"Sequences/S6 ",E_S6, 0},
  {"Sequences/S7 ",E_S7, 0},
  {"Sequences/S8 ",E_S8, 0},
  {"Sequences/S9 ",E_S9, 0},
  {"Sequences/S10",E_S10, 0},
  {"Sequences/S11",E_S11, 0},
  {"Sequences/S12",E_S12, 0},
  {"Sequences/S13",E_S13, 0},
  {"Sequences/S14",E_S14, 0},
  {"Sequences/S15",E_S15, 0}
};

// IMPROV configuration structure
IPL_CONFIG ipl_config;

CamImage::CamImage(int x,int y,int w,int h,const char *label)
            : Fl_Group(x,y,w,h)
{
  //Title
  menu = new Fl_Menu_Button(x+65, y, 105, 20, "Original");
  menu->box(FL_THIN_UP_BOX);
  menu->labelsize(12);
  menu->textsize(12);
  init_menu();

  //Display Area
  box = new Fl_Box(x, y+20,w,h-45, label);
  
  //DisplayImage Offset
  ipl_config.display_xOffset=3;
  ipl_config.display_yOffset=23;

  //Final display Size
  ipl_config.displayWidth=w-2*ipl_config.display_xOffset;
  ipl_config.displayHeight=h-5-2*ipl_config.display_yOffset;
  
  box->box(FL_ENGRAVED_BOX);
  box->labelsize(12);
  box->align(FL_ALIGN_TOP_LEFT);
  
  initialised = false;
  stopped = true;
  
  enlarge=true;
 
  camera = NULL;
}



void CamImage::initialize(Picture *p_out, bool *colour)
{ int i;
  
  if (NULL != camera) camera->close();
  
  camera = NULL;
  //Try cameras after each other
  for (i=0; i<nr_cameras; i++)
  { if (cameras[i] != NULL && (cameras[i])->open(&ipl_config) )
    { camera = cameras[i];
      fprintf(stderr,"Found camera %d\n", i);
      if (i==nr_cameras-1) seq_cam = 1;  /* image sequence */
      break;
     }
  }
  if (i==nr_cameras)
  { fprintf(stderr,"No camera found, no sequences found.  Exiting!\n"); exit(1);
  }

  cam_colour = camera->iscolor();
  *colour = cam_colour;
  
  //Initiate camera output image
  setImageType(p_out,ipl_config.imageType);
  resizeImage(p_out,ipl_config.imageWidth,ipl_config.imageHeight);
  
  //Set global variables for improc.c
  ipl_config.colorBlack=0;
  ipl_config.colorWhite=255;
  IPL_init(&ipl_config);
  
  p_output_img=p_out;
  initialised = true;
}


CamImage::~CamImage()
{
  if (NULL != camera)
    camera->close();
  
  delete menu;
  delete box;
}

void CamImage::camera_stopped(bool state)
{
  stopped = state;
}

void CamImage::enable_enlarge()
{
  enlarge = false;
  subscale = 0;
}

void CamImage::set_params(double p[])
{
  camera->params(p);  
}

void CamImage::disable_enlarge()
{
    enlarge = true;
    subscale = 1;
}


void CamImage::save_image(char *fname)
{
  saveImage(fname,p_output_img);
}

void CamImage::get_cam_info(CamInfo *info)
{
  camera->get_info(info);
}

void CamImage::get_IPL_info()
{
  Camera **camp;
  
  if (NULL != camera)
    camera->close();
  
  camera = NULL;
  
  for (camp = cameras; NULL != camp; camp++)
    {
      if ((*camp)->get_IPL(&ipl_config))
	{
	  (*camp)->close();
	  break;
	}
    }
}

void CamImage::draw()
{

  if (initialised) 
    camera->read(p_output_img);
  
  Fl_Group::draw();
  
  if(cameraon_off==1)
    {
      if (p_output_img->format==pix_rgb24) 
	{
	  if(( p_output_img->width  > ipl_config.displayWidth ||
	       p_output_img->height > ipl_config.displayHeight ) && 
	     enlarge==true )
	    {
	      Picture *tmp;
	      
	      tmp=cropImage(p_output_img,0,0, 
			    MIN(ipl_config.displayWidth,p_output_img->width), 
			    MIN(ipl_config.displayHeight,p_output_img->height));
	      
	      fl_draw_image(tmp->data,
			    x()+ipl_config.display_xOffset,
			    y()+ipl_config.display_yOffset,
			    tmp->width,
			    tmp->height, 3, 0);
	      
	      freeImage(tmp);
	      
	    }
	    else
	      fl_draw_image(p_output_img->data,
			    x()+ipl_config.display_xOffset,
			    y()+ipl_config.display_yOffset,
			    p_output_img->width,
			    p_output_img->height,3,0);
	}
      else 
	{ 
	  fl_draw_image_mono(p_output_img->data,
			     x()+ipl_config.display_xOffset,
			     y()+ipl_config.display_yOffset,
			     p_output_img->width,
			     p_output_img->height,1,0);
	}
    }
}


/* ****************************************************************************** */

int file_select(const struct dirent *entry)
{if ( (strcmp(entry->d_name, ".") == 0)  ||
      (strcmp(entry->d_name, "..") == 0) ||
      (strcmp(entry->d_name, "README") == 0))
   return (FALSE);
  else return (TRUE);
}



void GetSFiles(char *dirpath, char namelist[][MAXSEQNAMELEN],
               int *num, char *ssource, char *sinfo)
/* read individual files of a sequence, copy images to filelist                      */
/* read README file for seq_source (string) and seq-info (char): L=loop or R=reverse */
/* Thomas Bräunl, Jan. 2001                                                          */
{ int i,j;
  char full_path[300];
  char ch;
  FILE * readme;

  strcpy (full_path, img_path);
  strcat (full_path, dirpath);
  strcat (full_path, "/");

  strcpy (seq_path, dirpath); /*  copy for later file retrieval */

  if (DEBUG) fprintf(stderr,"GetSFiles: load path >%s<\n", full_path);
  *num = scandir(full_path, &seqfiles, file_select, alphasort);

  // defaults
  strcpy(ssource, "\n");  /* only newline in source string */
  *sinfo = 'L';           /* loop by default */
           
  if (*num > 0) 
  { if (DEBUG) fprintf(stderr,"Number of files: %d\n", *num);
    for (i=0; i< MIN(MAXSEQLEN, *num); i++)
    { strncpy(namelist[i], seqfiles[i]->d_name, MAXSEQNAMELEN);
      if (DEBUG) fprintf(stderr,"%3d) >%s<\n", i, namelist[i]);
    }
    // Get info from README file
    strcpy (full_path, img_path);
    strcat (full_path, dirpath);
    strcat (full_path, "/README");
    if ((readme = fopen(full_path, "r")) != NULL)
    { j = 0;  ch = ' ';
      while (j<MAXSOURCE && ch != '\n')
      { fscanf(readme, "%c", &ch);
        ssource[j++] = ch;
      }
      ssource[j] = (char) 0;       /* string terminator */
      fscanf(readme, "%c", &ch); /* read info */
      *sinfo = ch;
      fclose(readme);
    }
  }
}


//Camera menu
#ifndef _ARRAY_SIZE
#define ARRAY_SIZE(a) (int)(sizeof(a)/sizeof((a)[0]))
#endif
void CamImage::menu_cb(Fl_Widget *w,void *param)
{ if (DEBUG) fprintf(stderr, "menu_cb\n");

  Improv_Menu_Item *item=(Improv_Menu_Item *) param;
  IPLOP op;

  op.operation = item->operation;
  
  if (op.operation == E_CameraOn_Off)
  { if(seq_cam)
    { Camera *tmp;
      tmp=cameras[0];  
      cameras[0]=cameras[nr_cameras-2];
      cameras[nr_cameras-2]=tmp;
      seq_cam=0;
      cameraon_off=1;
      restart=1;
    }
    else cameraon_off = !cameraon_off;
  }

  else if (E_S1 <= op.operation && op.operation <= E_S1+MENU_ITEM_SEQ-1)      
  { if(!seq_cam)
    { Camera *tmp;
      cameras[0]->close();
      tmp=cameras[0];  
      cameras[0]=cameras[nr_cameras-2];
      cameras[nr_cameras-2]=tmp;
      seq_cam=1;
    }
	
    factor=2;
    /* read individual files */
     GetSFiles(seqdirs[op.operation-E_S1]->d_name, seqfilenames,
               &seqfile_len, seqfile_source, &seqfile_info);
     if (seqfile_len>0)
     { if (DEBUG) fprintf(stderr,"menu_cb:  seq name >%s< len: %d info: %c\n",
                          seqdirs[op.operation-E_S1]->d_name,
                          seqfile_len, seqfile_info);
       printf(seqfile_source);

       // Indicate that Improv has to be re-initialised
       restart=1;
     }
  }
  op.num_param = item->num_param;
}


void CamImage::init_menu()
{ int seq_count, i;
  char nametmp[50];

  if (DEBUG) fprintf(stderr,"Current working directory = %s\n", img_path);
  seq_count = scandir(img_path, &seqdirs, file_select, alphasort);
  seq_count = MIN(MENU_ITEM_SEQ, seq_count);
           
  if (seq_count <= 0) 
  { fprintf(stderr,"No files in sequence directory\n");
     seq_count = 0;
  }
  else
  { if (DEBUG) fprintf(stderr,"Number of sequences: %d\n",seq_count);
    for (i=0; i<seq_count; i++)
    { strcpy (nametmp, "Sequences/");
      strncat(nametmp, seqdirs[i]->d_name, 20);
      if (DEBUG) fprintf(stderr,"%3d) >%s<\n", i, nametmp);
      strcpy (menu_items[i+1].text, nametmp);
    }
  }

  for (i=0; i<seq_count+1; i++) 
    menu->add(menu_items[i].text, 0, (CamImage::menu_cb), &(menu_items[i]), 0);

  if (seq_count>0) strncpy(seq_path, seqdirs[0]->d_name, 20);  /* default is first sequence */
}

