/* Library to make operations available in C */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <unistd.h>
#include <time.h>

#include "ApnCamera.h"
#include "libapogeedrv.h"


/* Local storage */

int exp_width = 0;
int exp_height = 0;

/* Master object */

static CApnCamera *alta;

/* Function prototype */

static void apogee_check_alta();

/* Connect to the camera and perform any one-time setup */
/* Return 0 if ok else -1                              */

int apogee_open(unsigned int id)
{
  alta = (CApnCamera *)new CApnCamera();
  if (!alta->InitDriver(id,80,0) || !alta->ResetSystem())
  {
    return (-1);
  }
  
  alta->write_LedState (0, Apn_LedState_Expose);
  alta->write_LedState (1, Apn_LedState_AtTemp);

  return (0);
}

/* Return the camera operating parameters */

void apogee_get_values(int *roiw, int *roih, int *osw, int *osh, 
  int *binw, int *binh, double *mintemp)
{
  apogee_check_alta();

  *roiw = alta->m_ApnSensorInfo->m_ImagingColumns;
  *roih = alta->m_ApnSensorInfo->m_ImagingRows;
  *osw =  alta->m_ApnSensorInfo->m_OverscanColumns;
  *osh =  alta->m_ApnSensorInfo->m_OverscanRows;
  *binw = alta->read_MaxBinningH();
  *binh = alta->read_MaxBinningV();
  *mintemp = alta->m_ApnSensorInfo->m_CoolingSupported ? -30 : 0; /*TODO*/
}


/* Start an exposure without error checking */

int apogee_expose(double exposure, int x, int y, int height, int width, 
  int shutter_flag)
{
  int status;
  
  exp_width = width;
  exp_height = height;
  alta->write_RoiStartX(x);
  alta->write_RoiStartY(y);
  alta->write_RoiPixelsH(width);
  alta->write_RoiPixelsV(height);
  
  /* No overscan */
  alta->write_DigitizeOverscan(0);
  
  /* Single image per download */
  alta->write_ImageCount(1);

  /* Start an exposure */
  status = alta->Expose(exposure,shutter_flag);
  
  if (!status)
  {
    return(0);
  }
    
  return(1);
}


/* Stop an exposure without reading out */

int apogee_stop_exposure(void)
{
  apogee_check_alta();
  alta->StopExposure(0);
  return(1);
}

/* Check camera status */
/* Return 2 if the current exposure is complete */
/* Return 1 if exposure is integrating */
/* Return 0 otherwise */

int apogee_get_status(void)
{
  apogee_check_alta();
  if  (alta->read_ImagingStatus() == Apn_Status_ImageReady)
  {
    return(2);
  }
  return(0);  
}

/* Return the image based on data size from exposure request */

int apogee_get_image(unsigned short int *image)
{  

  long status;
  unsigned long count;
  unsigned short width;
  unsigned short height;
  
  width = exp_width;
  height = exp_height;
  count = width*height;
  status = alta->GetImageData (image, width, height, count);
  if (status != CAPNCAMERA_SUCCESS)
  {
    return(0);
  }       

  return(1);
}


/* Set cooler target temperature */

void apogee_set_cooler_temperature(double newtemp)
{    
  apogee_check_alta();
  alta->write_CoolerSetPoint(newtemp);
}


/* Set cooler state */

void apogee_set_cooler_state(int state)
{
  apogee_check_alta();
  
  if (state == 0) 
  {
    alta->write_CoolerEnable( (bool) 0 );
  } 
  else 
  {
    alta->write_CoolerEnable( (bool) 1 );
  }
}


/* Report urgent cooler tempperature status */
/*   0 = off                                */
/*   1 = ramping to set point               */              
/*   2 = at set point                       */                     

int apogee_get_cooler_temperature(double *apogeetemp)
{
  int status;

  apogee_check_alta();

  *apogeetemp = alta->read_TempCCD();
  status = alta->read_CoolerStatus();
  if (status > 2)
  {
    status = 2;
  }
  return (status);
}

/* Set fan speed from  0 to 3 */

void apogee_set_fan(int speed)
{
  alta->write_FanMode(0);   
  alta->write_FanMode(speed&3);
}

/* Actuate a guider relay */

int apogee_guide(int relay, double ontime)
{
  return(0);
}

/* Actuate the adaptive optics tip-tilt */

int apogee_tiptilt(int ao_x, int ao_y)
{
  return(0);
}


/* Return pointers to sensor and camera name */
/* Caller should neither modify nor free these strings. */

void apogee_get_info(char **sensor, char **camera)
{
  *sensor = alta->m_ApnSensorInfo->m_Sensor;
  *camera = alta->m_ApnSensorInfo->m_CameraModel;
}



/* Check that the alta object has been created */ 

static void apogee_check_alta()
{
  if (!alta) 
  {
    fprintf (stderr, "Bug! Alta used before open\n");
    exit(1);
  }
}

