#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <math.h>
#include <malloc.h>
#include <sys/io.h>
#include <forms.h>

#include "qcam.c"
#include "QuickCam.h"


QuickCam quickcam;

int QInit ( int *colCam, int *camVer, int *conVer )
{
  /* Quickcam initialisation */
  if (_QCConfig.quickcam_port != 0)
    {
      if(_QCConfig.quickcam_port != 0x278 &&
	 _QCConfig.quickcam_port != 0x378 &&
	 _QCConfig.quickcam_port != 0x3bc)
	{
	  fprintf(stderr, "Invalid port address\n");
	  return (0);
	}
      
      ioperm(_QCConfig.quickcam_port,3,1);
    }
  else
    {
      _QCConfig.quickcam_port = QC_find();
      if (_QCConfig.quickcam_port < 0)
	{
	  fprintf( stderr, "Can't get IO perms\n");
	  return (0);
	}
      else if(_QCConfig.quickcam_port == 0)
	{
	  fprintf( stderr, "Quickcam not connected\n");
	  return (0);
	}
    }
  
  /* reset camera */
  QC_reset(_QCConfig.quickcam_port);
  
  /* get camera version (colour? b/w?) */
  QC_getversion(_QCConfig.quickcam_port, colCam, camVer, conVer);
  QC_reset(_QCConfig.quickcam_port);
  
  if(_QCConfig.zoom > 2 || _QCConfig.zoom < 0)
    {
      fprintf(stderr, "Zoom values are: 0(no zoom), 1(1.5x), 2(2x)\n");
      return (0);
    }
  
  return (1);
}

bool QuickCam::open(IPL_CONFIG *ipl_config)
{
  int rc;
  int colCam, camVer, conVer;
  
  rc = QC_init();
  
  if (rc < 0)
    {
      if (rc == -1)
	fprintf(stderr, "quickcam already in use ?! (remove /tmp/quickcam and try again)\n");
      return(false);
    }
  
  if (QInit(&colCam, &camVer, &conVer) != 1)
    {
      fprintf(stderr, "No camera found, exiting...\n");
      QC_exit();
      return(false);
    }                
   
  if (colCam)
    printf("Quickcam color camera\n");
  else
    printf("Quickcam grayscale camera\n");
  
  /* Check for invalid frame modes */
  /* Set decimation mode */
  switch (_QCConfig.zoom)
    {
    case 0: /* 4:1 decimation */
      _QCConfig.xfermode = 8;
      if((_QCConfig.xsize * 4 > 320) || (_QCConfig.ysize * 4 > 240))
	{
	  fprintf(stderr, "Image %d x %d too big for camera!\n", _QCConfig.xsize, _QCConfig.ysize);
	  exit(1);
	}
      break;
    case 1: /* 2:1 decimation */
      _QCConfig.xfermode = 4;
      if((_QCConfig.xsize * 2 > 320) || (_QCConfig.ysize * 2 > 240))
	{
	  fprintf(stderr, "Image %d x %d too big for camera!\n", _QCConfig.xsize, _QCConfig.ysize);
	  exit(1);
	}
      break;
    case 2: /* No decimation */
      _QCConfig.xfermode = 0;
      if((_QCConfig.xsize > 320) || (_QCConfig.ysize > 240))
	{
	  fprintf(stderr, "Image %d x %d too big for camera!\n", _QCConfig.xsize, _QCConfig.ysize);
	  exit(1);
	}
      break;
    default: /* Unknown state */
      fprintf(stderr, "Zoom values are: 0(no zoom), 1(1.5x), 2(2x)\n");
      exit(1);
    }
  
  if(_QCConfig.colour)
    {
      /* shift bits appropriately for colour config */
      _QCConfig.xfermode = _QCConfig.xfermode >> 1;
      _QCConfig.xfermode ^= 24;
    }
  else
    {
      if (_QCConfig.bpp6)
	_QCConfig.xfermode += 2;
    }
  
  _QCConfig.xfermode += _QCConfig.biMode;
  
  ipl_config->colorBlack  = 0;
  ipl_config->colorWhite  = 255;
  ipl_config->imageWidth  = _QCConfig.xsize;
  ipl_config->imageHeight = _QCConfig.ysize;
  
  if(colCam)
    ipl_config->imageType   = pix_rgb24;
  else
    ipl_config->imageType   = pix_grey; 
  
  return(true);
}

void QuickCam::close()
{
  QC_exit();
}

extern int autobrightness;
void QuickCam::read(Picture *p_frame)
{ 
  int i;
  
  if(_QCConfig.colour)
    QC_CGet4bppImageUni(p_frame->data);
  else
    {
      QC_Get4bppImageUni(p_frame->data);
    }
    
  if (autobrightness==1)
    {
      int i;
      long sum = 0;
      double mean;
      static double tempz = 0.0;
      static double tempint = 0.0;
      
      for (i = 0; i < p_frame->datasize; i++)
	sum += p_frame->data[i];
      
      mean = (double)sum / p_frame->datasize;
      
      if (mean > 8)
	tempint = - MAX_AUTO_ADJUST * ((mean - 8) / 7);
      else if (mean < 7)
	tempint = MAX_AUTO_ADJUST * (1 - (mean / 7));
      
      if (mean > 8 || mean < 7)
        {
	  tempz =_QCConfig.brightness;
	  
	  tempz += tempint;
	  
	  if (tempz >= 255)
	    tempz = 254;
	  
	  if (tempz <= 0)
	    tempz = 1;
	  
	  _QCConfig.brightness=(int) tempz;
	  //printf("%d",(int) tempz);
	  QC_set_brightness();
        }
    }
  
  for (i = 0; i < p_frame->datasize; i++)
    p_frame->data[i]=p_frame->data[i]<<4;
  
  frame_count++;
}

void
QuickCam::get_info(CamInfo *info)
{
  info->width  = _QCConfig.xsize; 
  info->height = _QCConfig.ysize;
  
  if (iscolor() == true)
    info->bpp = 24;
  else
    info->bpp = 8; 
}

bool 
QuickCam::get_IPL(IPL_CONFIG *ipl_config)
{
  ipl_config->imageWidth  = _QCConfig.xsize;
  ipl_config->imageHeight = _QCConfig.ysize;
  
  if(_QCConfig.colour)
    ipl_config->imageType   = pix_rgb24;
  else
    ipl_config->imageType   = pix_grey;
  
  ipl_config->image_ratio = (float) ((float)ipl_config->imageHeight / 
				     (float) ipl_config->imageWidth);
}

bool
QuickCam::iscolor(void)
{
  if(_QCConfig.colour)
    return(true);
  else
    return(false);
}

void QuickCam::params(double *p)
{
  
  _QCConfig.brightness = (int) p[3];
  _QCConfig.contrast   = (int) p[4];
  _QCConfig.saturation = (int) p[5];
  
  QC_set_brightness();
  QC_set_contrast();
  QC_set_saturation();
}



