/******************************************************************************
 * Copyright 1990-2014 MBARI
 * MBARI Proprietary Information. All rights reserved.
 ******************************************************************************
 * Summary  : Example: implements interface to ACM 2-D Current Meter
 * Filename : 
 * Author   : 
 * Project  : Example: Benthic Rover
 * Version  : 
 * Created  : Example: Nov 08
 * Modified : 
 *****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "ImageFile.h"

ImageFile::ImageFile(const char* img_filename, bool debug)
{
   _debug = debug;
   _filename = strdup(img_filename);
}

ImageFile::~ImageFile()
{
   if (_filename) delete _filename;
}

float ImageFile::calc_coverage(ImageFile *reference, ImageFile *mask) 
{
	return calc_coverage(reference, 0);
}


float ImageFile::calc_coverage(ImageFile *reference, ImageFile *mask, unsigned int threshold) 
{
   // Define function calc_coverge
   float coverage_counter;
   unsigned int pixs = 0;

   for (unsigned int i = 0; i < IMGSIZE; i++) 
   {
      // Skip only if there's a masking image and the masking data at this pixel equals 0
      //
      if (mask && (mask->_data[i] == 0))
	     continue;
      else
	     pixs++;

      // darker pixels have lower values
      if ( (_data[i] + threshold) < reference->_data[i] )
      {
	      //printf("samp data[%d] = %u      ref data[%d] = %u\n", i, _data[i], i, reference->_data[i]);
         coverage_counter += 1.0;

         //if (_debug) printf("Image %4u + %3d < Ref %4u by %4u\n", _data[i], threshold, reference->_data[i],
         //   reference->_data[i] - (_data[i] + threshold));
	  }
	}
		
	_coverage = (coverage_counter / pixs) * 100;
   if (_debug) printf("%f/%ld = %f\n", coverage_counter, pixs, _coverage);

	
	return _coverage;
}

float ImageFile::calc_intensity(ImageFile *reference, ImageFile *mask) 
{
   // Define function calc_intensity
   float intensity_counter = 0.;
   float intensity_sum = 0.;
   unsigned int pixs = 0;
   
   for (unsigned int i = 0; i < IMGSIZE; i++) 
   {
      // Skip only if there's a masking image and the masking data at this pixel equals 0
      //
      if (mask && (mask->_data[i] == 0))
      	continue;
      else
      	pixs++;


      if (_data[i] < reference->_data[i] )
	   {
	      intensity_sum += reference->_data[i] - _data[i];
			intensity_counter++;
	   }
	}
	
   if (_debug) printf("Using %ld pixels in intensity image\n", pixs);
	if (intensity_counter > 0) _intensity = (intensity_sum / intensity_counter) / 40.96;

	return _intensity;
}

unsigned int ImageFile::load()
{
   // Check for access first and exit if we don't
   if (0 != access(_filename, R_OK))
   {
      if (_debug) printf("ImageFile::load - cannot access %s\n", _filename);
      return 1;
   }
   
   // Open file and read header
   int fd = open (_filename, O_RDONLY);

   int nbytes = read (fd, _header, sizeof(_header));
   
   // Report debug 
   if (_debug) printf("ImageFile::load - read %d bytes in header\n",
					nbytes);
   
   // Check to see if right amount of bytes were read
   if (nbytes < sizeof(_header))
   {
	   printf("ImageFile::load - error: header size too small\n");
	   return 1;
   }
   
   if (_debug)
   {
	   for (int i = 0; i < HDRSIZE; i++)
	   {
		  if (_debug) 
			if (_header[i] != 0) printf("Header [%d] = %d\n", i, _header[i]);
	   }
      printf("Is this a time stamp: %ld\n", _header[0]);
      printf("Is this a time stamp: %ld\n", _header[8]);
      printf("Is this a time stamp: %ld\n", _header[54]);
   }
      
   // Location of image dimensions within header
   _cols = _header[38];
   _rows = _header[40];
   
   // Verify image dimensions 
   if ((_cols * _rows) != IMGSIZE)
   {
	   printf("ImageFile::load - error bad dimensions: %d x %d\n", 
				_cols, _rows);
	   return 2;
   }
   
   // Read in image data
   nbytes = read (fd, _data, sizeof(_data));
   if (_debug) printf("ImageFile::load - read %d bytes of data\n",
					nbytes);
   
   // Check to see if right amount of bytes were read
   if (nbytes < sizeof(_data))
   {
	   printf("ImageFile::load - error: file size too small\n");
	   return 1;
   }

   extract_timestamp();

   return 0;
}


// Use the file name to extract the timestamp of the image,
// trying to match known file naming methods.
// Return 0 if successful.
//
unsigned int ImageFile::extract_timestamp()
{
   unsigned int ret_val = 0;
   _year = _month = _day = _hour = _min = _sec = 0;

   // Attempt to extract the date and time from the filename.
   // Assuming filename format something like:
   // some_image_description_YYMMDD-HHMMSS.b16
   //
   // First, find the extension .b16
   // strstr(haystack, needle) finds and returns a pointer to a substring
   // within a string, or returns NULL if not found.
   // Don't bother unless the extension is found and the
   // length of the filename is long enough
   //
   char *extension = NULL;
   if (strlen(_filename) >= strlen("YYMMDD-HHMMSS.b16")) extension = strstr(_filename, ".b16");

   if (NULL != extension)
   {
      // Look for naming method file_name_yymmdd-hhmmss.b16
      //
      char *datetime = extension - strlen("YYMMDD-HHMMSS");   // Back up to the start of the date and time
      int n = sscanf(datetime, "%2d%2d%2d-%2d%2d%2d",
         &_year, &_month, &_day, &_hour, &_min, &_sec);
      _year += 2000; // This century

      if (_debug) printf("%d items => %04d/%02d/%02d %02d:%02d:%02d\n",
         n, _year, _month, _day, _hour, _min, _sec);

      // If the date and time was scanned correctly, n will equal 6
      // and the date/time components will contain the values.
      //
      // If the date and time was not parsed correctly, reset the values
      // and return a non-zero value.
      //
      if (n != 6)
      {
         _year = _month = _day = _hour = _min = _sec = 0;
         ret_val = 2;   // Not a recognized naming method
      }
   }
   else
   {
      ret_val = 1;      // File name too short or not a .b16 file
   }

   return ret_val;
}


// Write the data to a file, possibly with mods
//
unsigned int ImageFile::dump(const char* new_filename)
{
   if (0 == strcmp(_filename, new_filename))
   {
      printf("Not going to overwrite image file: Use a name other than %s\n", _filename);
      return 1;
   }
   int fd = open (new_filename, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
   if (_debug) perror("");

   int nbytes = write(fd, _header, sizeof(_header));
   printf("Wrote %d bytes to %s\n", nbytes, new_filename);

   // Write a rectangle into the image
   //
   float mask_level = 0.23;
   unsigned long counter = 0;
   unsigned int level = mask_level * 4096;
   for (int i = 0; i < IMGSIZE; i++)
   {
      if (_data[i] <= level)
         _data[i] = 0;
      else
      {
         _data[i] = 4090;
         counter++;
      }

   } 
   nbytes = write(fd, _data, sizeof(_data));
   printf("Wrote %d bytes to %s, %ld non-zero values\n", nbytes, new_filename, counter);

   close(fd);
   printf("Wrote modified version to %s\n", new_filename);

   return 0;
}
