/*
 * Written 1997,2003 Jens Ch. Restemeier <jrestemeier@currantbun.com>
 * 
 * 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 "uf_file.h"

#define MAGIC "Filter Factory"
#define MAGIC_A 0x06e30
#define MAGIC_B 0x06c30
#define MAGIC_C 0x05220
#define MAGIC_D 0x0cc5a

#define VERSION_A 0
#define VERSION_B 1
#define VERSION_C 2
#define VERSION_D 3

/*
 * This is based on the research and development by 
 *  Michael Johannhanwahr <mjohannh@mail.hb.provi.de>
 * It loads "compiled" Files from FF for Windows.
 */
int load_bin_file(FILE *f, s_filter_data *data, int ver)
{
	int i;
/*	fpos_t ofs;
*/	long ofs;	
	unsigned char buf[32];
	
	switch (ver) {
		case VERSION_A: ofs=0x7a7c; break;
		case VERSION_B: ofs=0x7a4c; break;
		case VERSION_C: ofs=0x5e7c; break;
		case VERSION_D: ofs=0x783c; break;
		default: ofs=0; return 0;
	}

        fseek(f, ofs, SEEK_SET);
        fread(data->category, 256, 1, f);
        
        fseek(f, ofs+0x100, SEEK_SET);
        fread(data->title, 256, 1, f);
        
        fseek(f, ofs+0x200, SEEK_SET);
        fread(data->copyright, 256, 1, f);
        
        fseek(f, ofs+0x300, SEEK_SET);
        fread(data->author, 256, 1, f);

	fseek(f, ofs+0x400, SEEK_SET);
        for (i=0; i<4; i++) {
	        fread(data->map_label[i], 256, 1, f);
	}

	fseek(f, ofs+0x800, SEEK_SET);
	for (i=0; i<8; i++) {
	        fread(data->control_label[i], 256, 1, f);
	}

	fseek(f, ofs+0x1000, SEEK_SET);
	for (i=0; i<4; i++) {
	        fread(data->source[i], 1024, 1, f);
	}

	switch (ver) {
		case VERSION_A: 
			fseek(f, 0x7a5c, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_enable[i]=buf[0]!=0;
			}
			fseek(f, 0x7a1c, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_value[i] = buf[0];
			}
			break;
		case VERSION_B:
			fseek(f, 0x7a10, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_enable[i]=buf[0]!=0;
			}
			fseek(f, 0x79ec, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_value[i] = buf[0];
			}
			break;
		case VERSION_C:
			fseek(f, 0x5e5c, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_enable[i]=buf[0]!=0;
			}
			fseek(f, 0x5e1c, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_value[i] = buf[0];
			}
			break;
		case VERSION_D: 
			fseek(f, 0x781C, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_enable[i]=buf[0]!=0;
			}
			fseek(f, 0x77DC, SEEK_SET);
			for (i=0; i<8; i++) {
				fread(buf, 4, 1, f);
				data->control_value[i] = buf[0];
			}
			break;
	}
	return 1;
}

/*
 * This loads source-files from Harry's PiCo.
 */
int load_plain_source_txt(FILE *f, s_filter_data *data)
{	
	char buffer[8192], tok[8192], arg[8192];
	int i;
	fseek(f, 0, SEEK_SET);
	for (i=0; i<8; i++) {
		data->control_enable[i]=0;
	}
	/* read sliders */
	while (!feof(f)) {
		int c; 
		c=0; while (((i=fgetc(f))!='\r') && (i!='\n') && (!feof(f))) { buffer[c++]=i;  if (feof(f)) return 0; } buffer[c]=0;
		do {
			i=fgetc(f);
		} while (((i=='\r') || (i=='\n')) && (!feof(f)));
		if (!feof(f))
			fseek(f, -1, SEEK_CUR);
		i=strspn(buffer, "\t\r\n ");
		strcpy(tok, &(buffer[i]));
		i=strcspn(tok, " :");
		strcpy(buffer, &(tok[i]));
		tok[i]=0;
		i=strspn(buffer, " :");
		strcpy(arg, &(buffer[i]));
		i=strcspn(arg, "\n\r");
		if (i>0) arg[i]=0;
		if (strcmp(tok, "Category")==0) 
			strcpy(data->category, arg);
		if (strcmp(tok, "Title")==0) 
			strcpy(data->title, arg);
		if (strcmp(tok, "Copyright")==0) 
			strcpy(data->copyright, arg);
		if (strcmp(tok, "Author")==0) 
			strcpy(data->author, arg);
		if (strcmp(tok, "R")==0) 
			strcpy(data->source[0], arg);
		if (strcmp(tok, "G")==0) 
			strcpy(data->source[1], arg);
		if (strcmp(tok, "B")==0) 
			strcpy(data->source[2], arg);
		if (strcmp(tok, "A")==0) 
			strcpy(data->source[3], arg);
		if (strncmp(tok, "ctl", 3)==0) {
			i=strcspn(tok, "[");
			i+=strspn(&(tok[i]), " [");
			strcpy(buffer, &(tok[i]));
			i=strcspn(buffer, "]");
			buffer[i]=0;
			i=atoi(buffer);
			strcpy(data->control_label[i], arg);
			data->control_enable[i]=1;
		}
		if (strncmp(tok, "val", 3)==0) {
			i=strcspn(tok, "[");
			i+=strspn(&(tok[i]), " [");
			strcpy(buffer, &(tok[i]));
			i=strcspn(buffer, "]");
			buffer[i]=0;
			i=atoi(buffer);
			data->control_value[i] = atoi(arg);
			data->control_enable[i]=1;
		}
	}
	return 1;
}

/*
 * This loads original FF-sourcecode.
 */
int load_plain_source_afs(FILE *f, s_filter_data *data)
{
        char buffer[8192];
        int i,c,n;

        fseek(f, 0, SEEK_SET);
        /* skip header */
        c=0; while ((i=fgetc(f))!='\r') { buffer[c++]=i; if (feof(f)) return 0; } buffer[c]=0;
        /* read sliders */
        for (n=0; n<8; n++) {
                c=0; while ((i=fgetc(f))!='\r') { buffer[c++]=i;  if (feof(f)) return 0; } buffer[c]=0;
                data->control_value[n]=atoi(buffer);
        }
        /* read channels */
        for (n=0; n<4; n++) {
                c=0;
                do {
                        i=fgetc(f);
                        /* one \r -> skip, two \r -> end of line */
                        if (i=='\r') i=fgetc(f);
                        if (i!='\r') buffer[c++]=i;
                        if (feof(f)) return 0;
                } while (i!='\r');
                buffer[c]=0;

                strcpy(data->source[n], buffer);
        }
        return 1;
}

/*
 * Autodetect filetype and load the filter. 
 */
int load_filter(char *s, s_filter_data *data)
{
	FILE *f;
	char buffer[32];
	int retval;
	retval=0;
	
	if ((f=fopen(s, "r"))==NULL) {
		fprintf(stderr, "unable to open %s !\n", s);
		return 0;
	}
	
	fread(buffer, 16, 1, f);
	if (strncmp(buffer, "%RGB", 4)==0) {
		char *x;
		retval=load_plain_source_afs(f, data);
		/*
		 * set information to default
		 */
		strcpy(data->category, "AFS");
		x=strrchr(s, '/');
		if (x!=NULL) {
			strcpy(data->title, x+1);
		} else {
			strcpy(data->title, s);
		}
		x=strrchr(data->title, '.');
		if (x!=NULL) {
			*x=0;
		}
		strcpy(data->author, "unknown");
		strcpy(data->copyright, "unknown");
	} else {
		if (strncmp(buffer, "Category", 8)==0) {
			retval=load_plain_source_txt(f, data);
		} else {
			if (strncmp(buffer, "MZ", 2)==0) {
				fseek (f, MAGIC_A, SEEK_SET);
				fread (buffer, 14, 1, f); buffer[14]=0;
				if (strcmp (buffer, MAGIC)==0) {
					fseek(f, MAGIC_D, SEEK_SET);
					fread(buffer, 8, 1, f); buffer[8]=0;	
					if (strcmp(buffer, "ESPRESSO")==0) {
						retval=load_bin_file(f, data, VERSION_A);
					} else {
						retval=load_bin_file(f, data, VERSION_B);
					}
				} else {
					fseek (f, MAGIC_B, SEEK_SET);
					fread (buffer, 14, 1, f); buffer[14]=0;
					if (strcmp (buffer, MAGIC)==0) {
						retval=load_bin_file(f, data, VERSION_D);
					} else {
						fseek (f, MAGIC_C, SEEK_SET);
						fread (buffer, 14, 1, f); buffer[14]=0;
						if (strcmp (buffer, MAGIC)==0) {
							retval=load_bin_file(f, data, VERSION_C);
						} else {
							fprintf(stderr, "%s is Win95 binary, not a FF-filter\n", s);
							retval=0;
						}
					}
				}
			}
		} 
	}
	fclose(f);
	return retval;
}

/*
 * Save a FF-compatible sourcefile
 */
void save_filter_afs(char *s, s_filter_data *data)
{
	FILE *f;
	int i;
	if ((f=fopen(s, "w"))==NULL) 
		return;
	/*
	 * write header 
	 */
	fprintf(f, "%%RGB-1.0\r");
	/*
	 * write sliders 
	 */
	for (i=0; i<8; i++) {
		fprintf(f,"%i\r", data->control_value[i]);
	}
	/*
	 * write channels 
	 */
	for (i=0; i<4; i++) {
		fprintf(f, "%s\r\r", data->source[i]);
	}
	fclose(f);
}

/*
 * Save a filter, that can be read into PiCo.
 */
void save_filter_txt(char *s, s_filter_data *data)
{
	FILE *f;
	int i;
	if ((f=fopen(s, "w"))==NULL) 
		return;
	fprintf(f, "Category: %s\n", data->category);
	fprintf(f, "Title: %s\n", data->title);
	fprintf(f, "Copyright: %s\n", data->copyright);
	fprintf(f, "Author: %s\n", data->author);
	fprintf(f, "Filename: %s\n", s);

	fprintf(f, "\nR: %s\n", data->source[0]);
	fprintf(f, "\nG: %s\n", data->source[1]);
	fprintf(f, "\nB: %s\n", data->source[2]);
	fprintf(f, "\nA: %s\n", data->source[3]);
	fprintf(f, "\n");
	for (i=0; i<8; i++) {
		fprintf(f, "ctl[%i]: %s\n", i, data->control_label[i]);
	}
	fprintf(f, "\n");
	for (i=0; i<8; i++) {
		fprintf(f, "val[%i]: %i\n", i, data->control_value[i]);
	}
	fclose(f);
} 

/*
 * Decide format depending on extension, default is "txt"
 */
void save_filter(char *s, s_filter_data *data)
{
	char *x;
	x=strrchr(s, '.');
	if (x==NULL) {
		save_filter_txt(s, data);
	} else {
		if (strcasecmp(x, ".afs")==0) {
			save_filter_afs(s, data);
		} else {
			if (strcasecmp(x, ".txt")==0) {
				save_filter_txt(s, data);
			} else {
				save_filter_txt(s, data);
			}
		}
	}
}

void default_filter(s_filter_data *data)
{
	static char *def_src[4] = {"r", "g", "b", "a"};
	int c;	
	strcpy(data->title, "User Filter");
	strcpy(data->category, "User Filter");
	strcpy(data->copyright, "- none defined -");
	strcpy(data->author, "- none defined -");

	for (c=0; c<4; c++) {
		strcpy(data->source[c], def_src[c]);
		data->map_enable[c]=1;
		sprintf(data->map_label[c], "Map %i:", c);
	}

	for (c=0; c<8; c++) {
		data->control_value[c]=0;
		data->control_enable[c]=1;
		sprintf(data->control_label[c], "Control %i:", c);
	}
}
