/* Join together images. 
 *
 * 	find_mosaic x y file_name <root>.0x0.v <root>.0x1.v ...
 *
 * Where the image has been take with patches named as
 *	
 *	.		.
 *	.		.
 *	<root>.0x1.v	<root>.1x1.v	..
 *	<root>.0x0.v	<root>.1x0.v	..
 *
 * Uses im__find_lroverlap and im__find_tboverlap routines to make <root>.v. 
 *
 * It stores the tie points between patches in a data_file. 
 *
 * It uses partials on all IO by including tbmerge / lrmerge programs.
 *
 *  
 * Copyright (C) Feb./1995,   Ahmed. Abbood
 * National Gallery. London
 *
 */

/*

    This file is part of VIPS.
    
    VIPS is free software; you can redistribute it and/or modify
    it under the terms of the GNU Lesser 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 Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

 */

/*

    These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk

 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include <string.h>
#include <ctype.h>
#include <math.h>
#include <fcntl.h>
#include <locale.h>

#include <vips/vips.h>

#define NUM_FILES 1000
#define MAXPOINTS 60
int xoverlap;
int yoverlap;

extern int im_lrmerge();
extern int im_merge_analysis();
extern int im__find_lroverlap();
extern int im__find_tboverlap();
static int file_ptr = 0;
static IMAGE *in[ NUM_FILES ];



/* Strategy: build a tree describing the sequence of joins we want. Walk the
 * tree assigning temporary file names, compile the tree into a linear
 * sequence of join commands.
 */



/* Decoded file name info.
 */
static char *file_root = NULL;
static char *output_file = NULL;
static int width = 0;		/* Number of frames across */
static int height = 0;		/* Number of frames down */

static int file_list[ NUM_FILES ];




/* Find the root name of a file name. Return new, shorter, string.
 */
static char *
find_root( name )
char *name;
{	char *out = strdup( name );
	char *p;

	/* Chop off '.v'.
	 */
	if( !(p = strrchr( out, '.' )) ) {
		im_error( "find_mosaic", 
			_( "bad file name format '%s'" ), name );
		free( out );
		return( NULL );
	}
	*p = '\0';

	/* Chop off nxn.
	 */
	if( !(p = strrchr( out, '.' )) ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( NULL );
	}
	*p = '\0';

	return( out );
}

/* Find the x position of a file name (extract n from <root>.nxm.v).
 */
static int
find_x( name )
char *name;
{	int n;
	char *p;
	char *out = strdup( name );

	/* Chop off '.v'.
	 */
	if( !(p = strrchr( out, '.' )) ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( -1 );
	}
	*p = '\0';

	/* Find '.nxm'.
	 */
	if( !(p = strrchr( out, '.' )) ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( -1 );
	}

	/* Read out x posn.
	 */
	if( sscanf( p, ".%dx%*d", &n ) != 1 ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( -1 );
	}

	return( n );
}

/* Find the y position of a file name (extract m from <root>.nxm.v).
 */
static int
find_y( name )
char *name;
{	int m;
	char *p;
	char *out = strdup( name );

	/* Chop off '.v'.
	 */
	if( !(p = strrchr( out, '.' )) ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( -1 );
	}
	*p = '\0';

	/* Find '.nxm'.
	 */
	if( !(p = strrchr( out, '.' )) ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( -1 );
	}

	/* Read out y posn.
	 */
	if( sscanf( p, ".%*dx%d", &m ) != 1 ) {
		im_error( "find_mosaic",
			 _( "bad file name format '%s'" ), name );
		free( out );
		return( -1 );
	}

	free( out );
	return( m );
}


 

static int
mosaic_analysis(int width, int height,IMAGE **inp, IMAGE *out, 
	int xoff, int yoff, int *vxdisp, int *vydisp,int *hxdisp, int *hydisp) {



int i, j, dx, dy, curr_im, fx, fy;
int halfcorsize, halfareasize;
int mincorsize, minareasize;
int prev_row, curr_row, curr_disp_x, curr_disp_y;
double scale1, angle1, dx1, dy1;

	
	curr_im = -1;
	curr_disp_x = -1;
	curr_disp_y = -1;
	dy = -1;
	for(i=0; i<=height; i++){
		for(j=0; j<=width; j++){
		++curr_im;
		halfcorsize = 5;
        	halfareasize = 14;
        	dx = xoff - inp[curr_im]->Xsize;
		dy = yoff - inp[curr_im]->Ysize;

		if( ( j < width ) && ( width > 0 ) ){
        		if( dx < 0 ){
                		mincorsize = (int)(inp[curr_im]->Xsize + dx - 1)/6;
                		minareasize = (int)(inp[curr_im]->Xsize + dx 
					      - 3*halfcorsize -1)/2 - mincorsize;
                		if(mincorsize > halfcorsize)
                        		mincorsize = halfcorsize;
                		if( minareasize > 0 ){
                  			if( minareasize < halfareasize ){
                    				if( minareasize > 
						    (int)(halfcorsize +(int)(halfcorsize/2 + 1))){
                        				halfareasize = minareasize;
                    				}
                    				else if(mincorsize > 2){
                         				halfcorsize=mincorsize;
                         				halfareasize=(int)(mincorsize+mincorsize/2 +1);
                    				}
                  			}
                		}
        		}

			if( ( inp[curr_im]->Xsize < xoff ) || ( inp[curr_im+1]->Xsize < xoff ) ||
			    ( inp[curr_im]->Ysize < yoff ) || ( inp[curr_im]->Ysize < yoff) ){
				++curr_disp_x;
				hxdisp[curr_disp_x] = 0;
				hydisp[curr_disp_x] = 0;
			}
			else{
        		if ( im__find_lroverlap(inp[curr_im], inp[curr_im+1],
				out, 0,
                	   	(int)(inp[curr_im]->Xsize -xoff/2), 
				(int)(inp[curr_im]->Ysize /2), 
				(int)(xoff/2), (int)(inp[curr_im+1]->Ysize /2),
                		halfcorsize, halfareasize , &fx, &fy,
				&scale1, &angle1, &dx1, &dy1 ) == -1 )
                		error_exit("Unable to im__find_lroverlap");

			++curr_disp_x;
			hxdisp[curr_disp_x] = inp[curr_im]->Xsize - xoff + fx;
			hydisp[curr_disp_x] = fy;
			}
		}
		}
		if( ( i < height ) && ( height > 0 ) ){
			curr_row = curr_im+1+(int)(width/2);
			prev_row = curr_im - width+(int)(width/2);
        		halfcorsize = 5;
        		halfareasize = 14;
 
        	      if( dy < 0){
                	mincorsize = (int)(inp[prev_row]->Ysize + dy - 1)/6;
                	minareasize = (int)(inp[prev_row]->Ysize + dy 
					- 3*halfcorsize -1)/2 - mincorsize;
                	if(mincorsize > halfcorsize)
                       		mincorsize = halfcorsize;
               		if( minareasize > 0 ){
				if( minareasize < halfareasize ){
					if( minareasize > 
				          (int)(halfcorsize +(int)(halfcorsize/2 + 1))){
						halfareasize = minareasize;
                  			}
                   			else if(mincorsize > 2){
                         			halfcorsize=mincorsize;
                         			halfareasize=(int)(mincorsize+mincorsize/2 +1);
                    			}
                  		}
                	}
        	     }
 		     if( ( inp[curr_row]->Xsize < xoff ) || ( inp[prev_row]->Xsize < xoff ) ||
			 ( inp[curr_row]->Ysize < yoff ) || ( inp[prev_row]->Ysize < yoff ) ){
				++curr_disp_y;
				vxdisp[curr_disp_y] = 0;
				vydisp[curr_disp_y] = 0;
		     }
		     else{
		     if ( im__find_tboverlap(inp[prev_row], inp[curr_row],
			     out, 0,
                	 	(int)(inp[prev_row]->Xsize/2 ), 
				(int)(inp[prev_row]->Ysize - yoff/2 ),
			 	(int)(inp[curr_row]->Xsize/2 ), (int)(yoff/2),
                	 	halfcorsize, halfareasize, &fx, &fy,
				&scale1, &angle1, &dx1, &dy1 ) == -1 )
                		error_exit("Unable to im__find_tboverlap");


		     ++curr_disp_y;
		     vxdisp[curr_disp_y] = fx;
		     vydisp[curr_disp_y] = inp[prev_row]->Ysize - yoff + fy;
		     }
		}
	}


	return ( 0 );
}



int
main( argc, argv )
int argc;
char **argv;
{
	int i, n, j, k;
	char name[ 1000 ];
	FILE *fp;
	char *r;
        IMAGE *out;
	int vxdisp[NUM_FILES + 1] ;
	int vydisp[NUM_FILES + 1] ;
	int hxdisp[NUM_FILES + 1] ;
	int hydisp[NUM_FILES + 1] ;

	if( im_init_world( argv[0] ) )
	        error_exit( "unable to start VIPS" );
	textdomain( GETTEXT_PACKAGE );
	setlocale( LC_ALL, "" );

	/* Too many?
	 */
	if( argc > NUM_FILES + 1 )
		error_exit( "Too many files to merge" );
        for(i=0; i< NUM_FILES; i++)
           file_list[i] = 0;
	/* Too few?
	 */
	if( argc == 1 )
		error_exit( "usage: xoverlap yoverlap  file_name "
			"<root>.0x0.v <root>.0x1.v ..." );
	xoverlap = atoi(argv[1]);
	yoverlap = atoi(argv[2]);
	fp = fopen( argv[3] , "w" );

	for( i = 4; i < argc; i++ ){
		/* Find/check root.
	 	*/
		if( !file_root ) {
			file_root = find_root( argv[i] );
			if( !file_root )
				error_exit( "error at file_root" );
		}
		else {
			if( !(r = find_root( argv[i] )) )
				error_exit( "Error in reading parameters" );
			if( strcmp( r, file_root ) != 0 )
				error_exit( "Not all roots identical!" );
		}

		/* Read out position.
		 */
		if( (n = find_x( argv[i] )) < 0 )
			error_exit( "Error in reading file name" );
		if( n > width - 1 )
			width = n;
		if( (n = find_y( argv[i] )) < 0 )
			error_exit( "Error in reading file name" );
		if( n > height - 1 )
			height = n;
	
       		file_list[n] +=1;
	 }	

	/* Make output name. and store them in an array.
	 */
        if( !(out = im_open( "tmp.v", "t" )) )
            error_exit("unable to open file for output");

	file_ptr =0;
        for(i=height; i>=0; i--)
            for(j=0; j<file_list[i]; j++){
                im_snprintf( name, 1024, "%s.%dx%d.v", file_root,j,i );
                output_file = strdup( name );
                if( !(in[file_ptr] = im_open( output_file, "r" )) )
                    error_exit("unable to open %s for input",output_file);
                ++file_ptr;

            }

	mosaic_analysis(width,height,in,out,xoverlap,yoverlap,vxdisp,vydisp,hxdisp,hydisp);
	k = 0;
	for( i=0; i<height; i++ ){
		for( j=0; j<width; j++ ){
			fprintf(fp,"%d %d ", hxdisp[k] , hydisp[k] );
			k++;
		}
		fprintf(fp,"\n");
	}

	for( i=0; i<height; i++ )
                fprintf(fp,"%d %d\n", vxdisp[i] , vydisp[i] );


	for(i=0; i<file_ptr; i++)
		if( im_close(in[i]) == -1)
			error_exit("unable to close partial file");  
		if( im_close(out) == -1)
			error_exit("unable to close\n ");
	fclose( fp );

	vips_shutdown();

	return( 0 );
}