/*
 * fileio.c
 * used for writing images to files in jpg,png,ppm formats
 *
 * Derived from work by:
 * Copyright (C) 1998 Rasca, Berlin
 * EMail: thron@gmx.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <time.h>
#include <errno.h>

// fixme... should be tested for in project
#define HAVE_LIBJPEG

#ifdef HAVE_LIBZ
#include <zlib.h>
#endif

#ifdef HAVE_LIBPNG
#include <png.h>
#endif

#ifdef HAVE_LIBJPEG
#include <jpeglib.h>
#endif

#include "fileio.h"
#include "callbacks.h"

char full_name[350];        // a hack!. full path/filename of last written picture

/*
 */
void put_image_jpeg(char *filename, char *image, int width, int height, int quality)
{
#ifdef HAVE_LIBJPEG
	int y, line_width;
	JSAMPROW row_ptr[1];
	struct jpeg_compress_struct cjpeg;
	struct jpeg_error_mgr jerr;
	char *line;

	FILE *fp;
    time_t      t;
    struct tm  *tm;
    int         len;
	char dir_name[350];
	
	// create the directory name as a combination of the user selected prefix + year,month,day
	sprintf(full_name,"%s%%Y%%m%%d/",image_directory);	
    time(&t);
    tm = localtime(&t);
    len = strftime(dir_name,sizeof(dir_name)-1,full_name,tm);
	
	// make the directory that user wants pictures stored in to insure it exists
	// you may want to make dir permission 0700, so other users cannot see pix
	if (-1 == mkdir(dir_name,0777))
	{
		if (errno != EEXIST )
		{
			perror("put_image_jpeg() Unable to create file save directory");
		}
	}
	
	strncpy(full_name,dir_name,sizeof(full_name)-1);
	strncat(full_name,filename,sizeof(full_name)-strlen(full_name)-1);
	
	line = malloc (width * 3);
	if (!line)
		return;
		
    if ((fp = fopen(full_name, "wb")) == NULL) 
    {
	    fprintf(stderr, "can't open %s for binary write", full_name);
		perror(" and the reason is");
	    return;
    }   
//    fprintf(stderr, "   writing image to %s\n", full_name);
    cjpeg.err = jpeg_std_error(&jerr);  // errors get written to stderr 

	jpeg_create_compress (&cjpeg);
	cjpeg.image_width = width;
	cjpeg.image_height= height;
	cjpeg.input_components = 3;
	cjpeg.in_color_space = JCS_RGB;
	jpeg_set_defaults (&cjpeg);

	jpeg_set_quality (&cjpeg, quality, TRUE);
	cjpeg.dct_method = JDCT_FASTEST;
//	jpeg_stdio_dest (&cjpeg, stdout);
    jpeg_stdio_dest (&cjpeg, fp);  	  // data written to file
	jpeg_start_compress (&cjpeg, TRUE);

	row_ptr[0] = line;
	line_width = width * 3;
	for ( y = 0; y < height; y++) 
	{
		memcpy(line,image,line_width);
		jpeg_write_scanlines (&cjpeg, row_ptr, 1);
		image += line_width;
	}
	jpeg_finish_compress (&cjpeg);
	jpeg_destroy_compress (&cjpeg);
	free (line);
	
	if (fp)
	{
		fflush(fp);
		fclose(fp);
	}
#endif
}

/*
 * write png image to stdout
 */
void put_image_png (char *image, int width, int height)
{
#ifdef HAVE_LIBPNG
	int y;
	char *p;
	png_infop info_ptr;
	png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING,
						NULL, NULL, NULL);
	if (!png_ptr)
		return;
	info_ptr = png_create_info_struct (png_ptr);
	if (!info_ptr)
		return;

	png_init_io (png_ptr, stdout);
	png_set_IHDR (png_ptr, info_ptr, width, height,
					8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
					PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
	png_set_bgr (png_ptr);
	png_write_info (png_ptr, info_ptr);
	p = image;
	for (y = 0; y < height; y++) 
	{
		png_write_row (png_ptr, p);
		p+=width*3;
	}
	png_write_end (png_ptr, info_ptr);
#endif
}

/*
 * write ppm image to stdout
 */
void put_image_ppm (char *image, int width, int height, int binary)
{
	int x, y, ls=0;
	unsigned char *p = (unsigned char *)image;
	if (!binary) 
	{
		printf ("P3\n%d %d\n%d\n", width, height, 255);
		for (x = 0; x < width; x++) 
		{
			for (y = 0; y < height; y++) 
			{
				printf ("%03d %03d %03d  ", p[2], p[1], p[0]);
				p += 3;
				if (ls++ > 4) 
				{
					printf ("\n");
					ls = 0;
				}
			}
		}
		printf ("\n");
	}
	else 
	{
		unsigned char buff[3];
		printf ("P6\n%d %d\n%d\n", width, height, 255);
		for (x = 0; x < width * height; x++) 
		{
			buff[0] = p[2];
			buff[1] = p[1];
			buff[2] = p[0];
			fwrite (buff, 1, 3, stdout);
			p += 3;
		}
	}
	fflush (stdout);
}

/* ----------------------------------------------------------------------
 * This routine extracted and modified from webcam project by Gerd Knorr
 * (c) 1998-2000 Gerd Knorr
 * Modified for colored text by L.P. Glaister July 2000
*/ 
#if 0
# define CHAR_HEIGHT  8
# define CHAR_WIDTH   8
# define CHAR_START   1
# include "font_8x8.h"
#else
# define CHAR_HEIGHT  11
# define CHAR_WIDTH   6
# define CHAR_START   4
# include "font_6x11.h"
#endif

void add_rgb_text(char *image, int width, int height, int alrm)
{
    time_t      t;
    struct tm  *tm;
    char        line[128],*ptr;
    int         i,x,y,f,len;
	
    time(&t);
    tm = localtime(&t);
    len = strftime(line,127,image_label,tm);

    for (y = 0; y < CHAR_HEIGHT; y++) 
	{
		// locate text in lower left corner of image
		ptr = image + 3 * width * (height-CHAR_HEIGHT-2+y) + 12;
					
		// loop for each character in the string
		for (x = 0; x < len; x++) 
		{
	    	// locate the character in the fontdata array
			f = fontdata[line[x] * CHAR_HEIGHT + y];
			
			// loop for each column of font data
	    	for (i = CHAR_WIDTH-1; i >= 0; i--) 
			{
				// write a black background under text
				// comment out the following block to get white letters on picture background
	    		ptr[0] = 0;
	    		ptr[1] = 0;
		    	ptr[2] = 0;
				if (f & (CHAR_START << i)) 
				{
					if (alrm)
					{
						// red text
		    			ptr[0] = 255;
		    			ptr[1] = 64;
		    			ptr[2] = 64;
					}
					else
					{
						// white text
		    			ptr[0] = 255;
		    			ptr[1] = 255;
		    			ptr[2] = 255;
					}

			
				}
				ptr += 3;
	    	}
		}
    }
}
