/*  
    Copyright (C) 2003 Johan Borg

    This file is part of xmerge.

    xmerge 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.
                
    xmerge 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 xmerge; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/






//TODO - list

//verify that the new features, load scaling, gain change and offset, works

//preseve the crop rectangle when solving, when possible

//some way of setting the crop rectangle from command line (-s not very usefull without this)

//make it possible to move the source images individually (is this neccecary, or even usefull?)

//more tests on the constraints, disabling parts of the function

//make it possible to select an individual link are be used as constraints or parts of the goal function

//some way of indicating current position within the source/target (a small win with an rectangle representing currently visible area)

//some more sofisticated form of gain adjust, gradients perhaps..

//other image mappings, especially something more suitable for working with photographs

//use analytical derivatives for the optimization, or use a better hessian update (the current hessian update used isn't suitable for nummerical derivatives..)

//do something with widgets (something with preferences for currently manipulated link,perhaps)

//some way of indicating which image is currently on top, and some method for writing the individual
//images stretched but not merged, for use in time lapse sequences etc

//interpolate edges against background color? (must keep track if it's an outer edge, of if there is another image covering that pixel

#include "xmerge.h"

int Ox,Oy,Ot;		//number of images horizontally and vertically

IMG **simg;		//source images 
struct linkp rlink[MAXLINKS]; 

int csl,cdl;	
int BC_r=255,BC_g=0,BC_b=0;
IMG *csi,*cdi;

int Ml,Mt,Mr,Mb;	//margins of the mapped image
extern double ewa_W[4096];
extern double merge_L[4096];


char * opt_Wfile="list.txt";
char * opt_wfile="test.ppm";
double opt_scale=2.0;
double opt_lscale=1.0;

extern int RCOL_r,RCOL_g,RCOL_b;
int OFS_r=0,OFS_g=0,OFS_b=0;
double LCOL_r=1,LCOL_g=1,LCOL_b=1;

int writing=0,write_abort=0,writing_list=0;


void chld_handler(int i) {
 wait(&i);
}

void int_handler(int i) {
 i=0;	//to avoid warning about unused parameters
 if (writing) write_abort=1; else {
  if (!writing_list) write_list("xmerge_killed.txt"); 
  exit(0);
 } 
}


void hup_handler(int i) {
 i=0;
 if (!writing_list) write_list("xmerge_killed.txt"); 
 if (writing) write_abort=2; else exit(0);
 return;
}



int main(int argc, char **argv) {
 int o;

 int opt_solve=0;
 int opt_write=0;
 int opt_Write=0;
 char * opt_load=0;


 if (argc<2) goto help;

//additional options include filtering parameter, various maximums, post scaling, post rotation, gain/offset (brightnes/contrast)
  
 while((o=getopt(argc,argv,"hwWsl:o:O:m:b:r:R:B:M:"))>=0) {
  switch(o) {
   case 'h': 
help:   
    printf("usage:\n"); 
    printf("  -h 		this message\n");
    printf("  -o		set output file for final image, if written (default test.ppm)\n");
    printf("  -O		set output file for mapping data, if written\n");
    printf("  -l		load saved mapping data, mutually exclusive to specifying ppm files\n");
    printf("  -m		magnification applied when solution is calculated (default 1.0)\n");
    printf("  -M		magnification applied if mapping data are loaded\n");
    printf("  -b		background color (default: %d,%d,%d  (red))\n",BC_r,BC_g,BC_b);
    printf("  -r		reference-color for gain calculation (gui: b) (default %d,%d,%d)\n",RCOL_r,RCOL_g,RCOL_b);
    printf("  -R		color gain applied if mapping data are loaded (default 0,0,0)\n");
    printf("  -B		black level used when final image is created (default: 0,0,0)\n");
    printf("			(color gain or reference level must be adjusted accordingly)\n");
    printf("\n");
    printf(" options implying non interactive operation: (in order of execution)\n");
    printf("  -s		solve loaded problem\n");
    printf("  -W		write current mapping data\n");
    printf("  -w		write final image\n");
    printf("\n");
    printf(" Input file(s) can be either -l <filename> OR a list of ppm(P6) files.\n");
    printf(" When image files are specifiled, the images are placed on rows from left to right.\n"); 
    printf(" The special file name / causes remaining images to be placed on a new row one position down.\n");
    printf(" Empty arguments (\"\" in most shells) can be used to create empty locations\n");    
    printf("\n");   
    exit(0);
   case 'w':
    opt_write=1;
    break;
   case 'W':
    opt_Write=1;
    break;
   case 's':
    opt_solve=1;
    break;
   case 'l':
    opt_load=optarg;
    break;
   case 'o':
    opt_wfile=optarg;
    break;
   case 'O':
    opt_Wfile=optarg;
    break;
   case 'm':
    opt_scale=strtod(optarg,0);
    if (opt_scale<=0) {
     printf("invalid scaling requested!\n");
     exit(-1);
    }
    opt_scale=2.0*opt_scale;
    break; 

   case 'M':
    opt_lscale=strtod(optarg,0);
    if (opt_scale<=0) {
     printf("invalid scaling requested!\n");
     exit(-1);
    }
    break; 
    
   case 'b':
    if ((sscanf(optarg,"%d,%d,%d",&BC_r,&BC_g,&BC_b)!=3) || (BC_r<0) || (BC_r>255) || (BC_g<0) || (BC_g>255) || (BC_b<0) || (BC_b>255)) {
     printf("invalid argument, usage: -b <0-255>,<0-255>,<0-255>\n");
     exit(-1);
    }
    break;   
   case 'r':
    if ((sscanf(optarg,"%d,%d,%d",&RCOL_r,&RCOL_g,&RCOL_b)!=3) || (RCOL_r<0)/* || (RCOL_r>255) || (RCOL_g<0) || (RCOL_g>255) || (RCOL_b<0) || (RCOL_b>255)*/) {
//     printf("invalid argument for -r, format: -r <0-255>,<0-255>,<0-255>\n");
     printf("invalid argument, usage: -r <r_ref>0>,<g_ref>0>,<b_ref>0>\n");
     exit(-1);
    }
    
   case 'R':
    if (sscanf(optarg,"%lf,%lf,%lf",&LCOL_r,&LCOL_g,&LCOL_b)!=3) {
     printf("invalid argument, usage: -R <r_gain>,<g_gain>,<b_gain>\n");
     exit(-1);
    }
    break;   
    
   case 'B':
    if (sscanf(optarg,"%d,%d,%d",&OFS_r,&OFS_g,&OFS_b)!=3) {
     printf("invalid argument, usage: -B <r_ofs>,<g_ofs>,<b_ofs>\n");
     exit(-1);
    }
    break;   
    
  }
 }
 
 
 if (optind<argc) {
  if (opt_load) {
   printf(" can't use additional files with -l <filename>, aborting\n");
   exit(-1);
  }
 
  printf("argv[optind: %s %d %d\n",argv[optind],optind,argc);
  read_files(argv+optind,argc-optind); 
 
 } else {
  if (!opt_load) {
   printf("must have either filenames or -l <filename>, aborting		(-h for help)\n");
   exit(-1);
  }
   
  read_list(opt_load);
 }

 
 
 signal(SIGCHLD,&chld_handler);
 signal(SIGINT,&int_handler);
 signal(SIGHUP,&hup_handler);
 signal(SIGTERM,&hup_handler);
// signal(SIGSEGV,&hup_handler);
// signal(SIGBUS,&hup_handler);
 
 
 for(o=0;o<pE;o++) ewa_W[o]=exp(-o/pE*pT*pH*pG);	//gaussian weights for ewa
 for(o=0;o<4096;o++) merge_L[o]=(1.0-cos(o*3.1415926535/4096.0))/2.0;
 
 
 if (!opt_solve && !opt_write && !opt_Write) run_gui(); else {
  if (opt_solve) solve();
  if (opt_Write) write_list(opt_Wfile); 
  if (opt_write) {
   o=open(opt_wfile,O_WRONLY|O_CREAT|O_TRUNC,0777);
   imap_ewa_merge(Ml,Mt,Mr,Mb,o);
  } 
 }
 return 0;
}
