/*

	clip_lbs.c

	clbs1.bat = cl /AL clip_lbs.c

Reads an 8, 16 or 32 bit image and

 clips and/or samples it 

clip [infile] [outfile] [rw1] [cl1] [orw] [ocl] [sample]

where:
   infile --- input file name without extension
   outfile -- output file name without extension
   rw1 ------ first row in input image to use in output image
   cl1 ------ first column in input image to use in output image
   orws ----- number of rows in output image
   ocls ----- number of columns in output image
   sample --- sample rate  ( 1 for full data )

*/
#include <stdio.h>
#include <string.h>

char *Path[10];
int NumPath=0;
char Type[9][50]=
{
	"error",
	"unsigned char",
	"char",
	"unsigned short",
	"short",
	"unsigned long",
	"long",
	"float",
	"double"
};
union Data
{
	unsigned char uc[40000];
	char c[5000];
	unsigned short us[20000];
	short s[20000];
	unsigned long ul[10000];
	long l[10000];
	float f[10000];
	double d[5000];
}D;
struct grid_stat
{
	double maxlat,minlat,maxlon,minlon;
	double maxz,minz;
	double dellat,dellon;			/* array size */
	double latspace,lonspace;	/* line spacing */
	double scale;
	int numlat,numlon;
	char datafile[100];
	char sourcefile[100];
	double flex;
   double msng_val;
	char msng;
	int type,size;	/* type -- 1 = unsigned char (1 byte) */
                  /* type -- 2 = char (1 byte) */
                  /* type -- 3 = unsigned short (2 bytes) */
                  /* type -- 4 = short (2 bytes) */
                  /* type -- 5 = unsigned long (4 bytes) */
                  /* type -- 6 = long (4 bytes) */
                  /* type -- 7 = float (4 bytes) */
                  /* type -- 8 = double (8 bytes) */
}Fs;
int Ppd=0;

FILE *fopen_path(char *filename,char *type);

main(int argc,char *argv[])

{
	long i,j,k,l,m,n,r,g,b;
	long irow,icol,orow,ocol,row1,col1;
	int row,col;
	char infile[100],inname[100],outname[100],string[100],cr=0xd;
	FILE *fpin,*fplbs,*fppal,*fpdat;
	long offset,sample=1;
	char iop;
	long bytes,lsample;

	for(i=7;i<argc;i++)
		if(argv[i][1]==':'||argv[i][0]==92)	
			Path[NumPath++]=argv[i];
	if(argc<8)
		print_format();
	strcpy(inname,argv[1]);
	if(sscanf(argv[3],"%ld",&row1)<1)
		not_read("row1");
	if(sscanf(argv[4],"%ld",&col1)<1)
		not_read("col1");
	if(sscanf(argv[5],"%ld",&orow)<1)
		not_read("orow");
	if(sscanf(argv[6],"%ld",&ocol)<1)
		not_read("ocol");
	if(sscanf(argv[7],"%ld",&sample)<1)
		not_read("sample");
	strcpy(outname,argv[2]);
   read_lbs(inname,&Fs);
	if(row1+orow>(long)Fs.numlat)
	{
		printf("You asked for too many rows.\n\n");
		exit(0);
	}
	if(col1+ocol>(long)Fs.numlon)
	{
		printf("You asked for too many columns.\n\n");
		exit(0);
	}
	irow=Fs.numlat;
	icol=Fs.numlon;
	sprintf(string,"%s.lbs",outname);
	fplbs=fopen_path(string,"wt");
	if(!fplbs)
	{
		printf("Could not open '%s' to write 'LBS' file.\n\n",string);
		exit(0);
	}
	fprintf(fplbs,"FILE_TYPE          = ELEVATION_ARRAY\n");
	fprintf(fplbs,"IMAGE_LINES        = %6d\n",(orow+sample-1)/sample);
	fprintf(fplbs,"LINE_SAMPLES       = %6d\n",(ocol+sample-1)/sample);
	fprintf(fplbs,"UPPER_LEFT_LAT     = %11.6lf\n",
		Fs.maxlat-(double)row1*Fs.latspace);
	fprintf(fplbs,"UPPER_LEFT_LON     = %11.6lf\n",
		Fs.minlon+(double)col1*Fs.lonspace);
	fprintf(fplbs,"LOWER_RIGHT_LAT    = %11.6lf (optional)\n",
		Fs.maxlat-(double)(row1+orow-1)*Fs.latspace);
	fprintf(fplbs,"LOWER_RIGHT_LON    = %11.6lf (optional)\n",
		Fs.minlon+(double)(col1+ocol-1)*Fs.lonspace);
	if(Ppd<2)
	{	
		fprintf(fplbs,"DELTA_LAT          = %15.8le\n",Fs.latspace*sample);
		fprintf(fplbs,"DELTA_LON          = %15.8le\n",Fs.lonspace*sample);
	}
	else
	{	
		fprintf(fplbs,"DELTA_LAT          = %6.0lf points/degree\n",
			1.0/(Fs.latspace*sample));
		fprintf(fplbs,"DELTA_LON          = %6.0lf points/degree\n",
			1.0/(Fs.lonspace*sample));
	}
	fprintf(fplbs,"NUMBER_OF_LAT      = %6d\n",(orow+sample-1)/sample);
	fprintf(fplbs,"NUMBER_OF_LON      = %6d\n",(ocol+sample-1)/sample);
	fprintf(fplbs,"SAMPLE_RATE        = %d\n",sample);
	fprintf(fplbs,"DATA_TYPE          = %s\n",Type[Fs.type]);
	fprintf(fplbs,"DATA_SIZE          = %d bytes\n",Fs.size);
	bytes=Fs.size;
	if(Fs.msng>0)
		fprintf(fplbs,"MISSING_DATA_VALUE = %lf\n");
	fprintf(fplbs,"DATA_FILE_POINTER  = '%s.D%02d'\n",outname,Fs.size*8);
	fprintf(fplbs,"SOURCE_FILE        = '%s'\n",Fs.datafile);
	fclose(fplbs);
	if(ocol*(long)Fs.size>40000)
	{
		printf("Requested too many columns.\n\n");
		exit(0);
	}
	fpin=fopen_path(Fs.datafile,"rb");
	if(!fpin)
	{
		printf("Could not open '%s' to read data.\n\n",Fs.datafile);
		exit(0);
	}
	sprintf(string,"%s.D%02d",outname,Fs.size*8);
	fpdat=fopen_path(string,"wb");
	if(!fpdat)
	{
		printf("Could not open '%s' to write data.\n\n",string);
		exit(0);
	}
	row=(orow+sample-1)/sample;
	col=(ocol+sample-1)/sample;
	lsample=sample;
	for(i=0;i<orow/sample;i++)
	{
		printf("%c%6ld of %d",cr,i+1,orow/sample);
		offset=((i*lsample+row1)*icol+col1)*bytes;/* 1st pixel of output line */
		fseek(fpin,offset,SEEK_SET);
		if(Fs.type==1)
		{
			if(fread((char *)D.uc,sizeof(char),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.uc[j]=D.s[j*sample];
			fwrite((char *)D.uc,sizeof(char),col,fpdat);
		}
		else if(Fs.type==2)
		{
			if(fread((char *)D.c,sizeof(char),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.c[j]=D.s[j*sample];
			fwrite((char *)D.c,sizeof(char),col,fpdat);
		}
		else if(Fs.type==3)
		{
			if(fread((char *)D.us,sizeof(short),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.s[j]=D.us[j*sample];
			fwrite((char *)D.us,sizeof(short),col,fpdat);
		}
		else if(Fs.type==4)
		{
			if(fread((char *)D.s,sizeof(short),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.s[j]=D.s[j*sample];
			fwrite((char *)D.s,sizeof(short),col,fpdat);
		}
		else if(Fs.type==5)
		{
			if(fread((char *)D.ul,sizeof(long),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.ul[j]=D.s[j*sample];
			fwrite((char *)D.ul,sizeof(long),col,fpdat);
		}
		else if(Fs.type==6)
		{
			if(fread((char *)D.l,sizeof(long),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.l[j]=D.s[j*sample];
			fwrite((char *)D.l,sizeof(long),col,fpdat);
		}
		else if(Fs.type==7)
		{
			if(fread((char *)D.f,sizeof(float),(int)ocol,fpin)<(int)ocol)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.f[j]=D.f[j*sample];
			fwrite((char *)D.f,sizeof(float),col,fpdat);
		}
		else if(Fs.type==8)
		{
			if(fread((char *)D.d,sizeof(double),(int)ocol,fpin)<col)
			{
				printf("EOF hit in '%s'\n\n",Fs.datafile);
				exit(0);
			}
			for(j=0;j<col;j++)
				D.d[j]=D.s[j*sample];
			fwrite((char *)D.d,sizeof(double),col,fpdat);
		}
		else
		{
			printf("\n\nInvalid data type = %d\n",Fs.type);
			exit(0);
		}
	}
}

/**********************************************************************
**
**
**
**********************************************************************/

int read_lbs(char *name,struct grid_stat *fs)

{
	int i,j,k;
	FILE *fp;
	char string[100],str1[50],str2[50],str3[50],str4[50];
	char *type;

	sprintf(string,"%s.lbs",name);
	fp=fopen_path(string,"rt");
	if(!fp)
	{
		printf("Could not open '%s' to read label information.\n\n",string);
		exit(0);
	}
	fs->maxlat=-360.0;
	fs->maxlon=-360.0;
	fs->minlat=360.0;
	fs->minlon=360.0;
	fs->dellat=0.0;
	fs->dellon=0.0;
	fs->latspace=0.0;
	fs->lonspace=0.0;
	fs->scale=0.0;
	fs->numlat=0;
	fs->numlon=0;
	fs->size=0;
	fs->type=0;
	fs->flex=-1.0;
	while(fgets(string,100,fp))
	{
		sscanf(string,"%s%s%s%s",str1,str2,str3,str4);
		if(strcmpi(str1,"MISSING_DATA_VALUE")==0)
		{
			if(sscanf(str3,"%lf",&fs->msng_val)<1)
			{
				printf("Invalid MISSING_DATA_VALUE '%s'\n\n",str3);
				exit(0);
			}
			fs->msng=1;
			printf("MISSING_DATA_VALUE = %lf\n",fs->msng_val);
		}
		if(strcmpi(str1,"IMAGE_LINES")==0)
		{
			if(sscanf(str3,"%d",&fs->numlat)<1)
			{
				printf("Invalid IMAGE_LINES '%s'\n\n",str3);
				exit(0);
			}
			printf("IMAGE_LINES = %d\n",fs->numlat);
		}
		if(fs->numlat==0&&strcmpi(str1,"NUMBER_OF_LAT")==0)
		{
			if(sscanf(str3,"%d",&fs->numlat)<1)
			{
				printf("Invalid NUMBER_OF_LAT'%s'\n\n",str3);
				exit(0);
			}
			printf("NUMBER_OF_LAT = %d\n",fs->numlat);
		}
		if(strcmpi(str1,"LINE_SAMPLES")==0)
		{
			if(sscanf(str3,"%d",&fs->numlon)<1)
			{
				printf("Invalid LINE_SAMPLES '%s'\n\n",str3);
				exit(0);
			}
			printf("LINE_SAMPLES = %d\n",fs->numlon);
		}
		if(fs->numlon==0&&strcmpi(str1,"NUMBER_OF_LON")==0)
		{
			if(sscanf(str3,"%d",&fs->numlon)<1)
			{
				printf("Invalid NUMBER_OF_LON'%s'\n\n",str3);
				exit(0);
			}
			printf("NUMBER_OF_LON = %d\n",fs->numlon);
		}
		if(strcmpi(str1,"UPPER_LEFT_LAT")==0)
		{
			if(sscanf(str3,"%lf",&fs->maxlat)<1)
			{
				printf("Invalid UPPER_LEFT_LAT '%s'\n\n",str3);
				exit(0);
			}
			printf("UPPER_LEFT_LAT = %lf\n",fs->maxlat);
		}
		if(strcmpi(str1,"UPPER_LEFT_LON")==0)
		{
			if(sscanf(str3,"%lf",&fs->minlon)<1)
			{
				printf("Invalid UPPER_LEFT_LON '%s'\n\n",str3);
				exit(0);
			}
			printf("UPPER_LEFT_LON = %lf\n",fs->minlon);
		}
		if(strcmpi(str1,"LOWER_RIGHT_LAT")==0)
		{
			if(sscanf(str3,"%lf",&fs->minlat)<1)
			{
				printf("Invalid LOWER_RIGHT_LAT '%s'\n\n",str3);
				exit(0);
			}
			printf("LOWER_RIGHT_LAT = %lf\n",fs->minlat);
		}
		if(strcmpi(str1,"LOWER_RIGHT_LON")==0)
		{
			if(sscanf(str3,"%lf",&fs->maxlon)<1)
			{
				printf("Invalid LOWER_RIGHT_LON '%s'\n\n",str3);
				exit(0);
			}
			printf("LOWER_RIGHT_LON = %lf\n",fs->maxlon);
		}
		if(strcmpi(str1,"DELTA_LAT")==0)
		{
			if(sscanf(str3,"%lf",&fs->latspace)<1||fs->latspace<=0.0)
			{
				printf("Invalid DELTA_LAT '%s'\n\n",str3);
				exit(0);
			}
			if(strcmpi(str4,"points/degree")==0)
			{
				Ppd=+1;
				fs->latspace=1.0/fs->latspace;
				printf("DELTA_LAT = %6.0lf points/degree\n",1.0/fs->latspace);
			}
			else
				printf("DELTA_LAT = %lf\n",fs->latspace);
		}
		if(strcmpi(str1,"DELTA_LON")==0)
		{
			if(sscanf(str3,"%lf",&fs->lonspace)<1||fs->lonspace<=0.0)
			{
				printf("Invalid DELTA_LON '%s'\n\n",str3);
				exit(0);
			}
			if(strcmpi(str4,"points/degree")==0)
			{
				Ppd+=1;
				fs->lonspace=1.0/fs->lonspace;
				printf("DELTA_LON = %6.0lf points/degree\n",1.0/fs->lonspace);
			}
			else
				printf("DELTA_LON = %lf\n",fs->lonspace);
		}
		if(strcmpi(str1,"MAXIMUM_Z")==0)
		{
			if(sscanf(str3,"%lf",&fs->maxz)<1)
			{
				printf("Invalid MAXIMUM_Z '%s'\n\n",str3);
				exit(0);
			}
			printf("MAXIMUM_Z = %lf\n",fs->maxz);
		}
		if(strcmpi(str1,"MINIMUM_Z")==0)
		{
			if(sscanf(str3,"%lf",&fs->minz)<1)
			{
				printf("Invalid MINIMUM_Z '%s'\n\n",str3);
				exit(0);
			}
			printf("MINIMUM_Z = %lf\n",fs->minz);
		}
		if(strcmpi(str1,"DATA_FILE_POINTER")==0)
		{
			k=0;
			for(i=0;i<strlen(str3);i++)
				if(str3[i]!=39)		/* single quote */
					fs->datafile[k++]=str3[i];
			fs->datafile[k]='\0';
			printf("DATA_FILE_POINTER = '%s'\n",fs->datafile);
		}
		if(strcmpi(str1,"DATA_TYPE")==0)
		{
			strcpy(type,str3);
			printf("DATA_TYPE = '%s'\n",type);
		}
		if(strcmpi(str1,"DATA_SIZE")==0)
		{
			if(sscanf(str3,"%d",&fs->size)<1)
			{
				printf("Invalid DATA_SIZE '%s'\n\n",str3);
				exit(0);
			}
			printf("DATA_SIZE = %d\n",fs->size);
		}
		if(strcmpi(str1,"SPLINE_FLEXIBILITY")==0)
		{
			sscanf(str3,"%lf",&fs->flex);
			printf("SPLINE_FLEXIBILITY = %lf\n",fs->flex);
		}
		if(strcmpi(str1,"INPUT_DATA_NAME")==0)
		{
			strcpy(fs->sourcefile,str3);
			printf("INPUT_DATA_NAME = %s\n",fs->sourcefile);
		}
	}
	fclose(fp);
	if(strcmpi(type,"unsigned")==0&&fs->size==1)
	{
		fs->type=1;
		printf("TYPE = 'unsigned char'\n");
	}
	if(strcmpi(type,"char")==0&&fs->size==1)
	{
		fs->type=2;
		printf("TYPE = 'char'\n");
	}
	if(strcmpi(type,"unsigned")==0&&fs->size==2)
	{
		fs->type=3;
		printf("TYPE = 'unsigned short'\n");
	}
	if(strcmpi(type,"short")==0&&fs->size==2)
	{
		fs->type=4;
		printf("TYPE = 'short'\n");
	}
	if(strcmpi(type,"unsigned long")==0&&fs->size==4)
	{
		fs->type=5;
		printf("TYPE = 'unsigned long'\n");
	}
	if(strcmpi(type,"long")==0&&fs->size==1)
	{
		fs->type=6;
		printf("TYPE = 'long'\n");
	}
	if(strcmpi(type,"float")==0&&fs->size==4)
	{
		fs->type=7;
		printf("TYPE = 'float'\n");
	}
	if(strcmpi(type,"double")==0&&fs->size==8)
	{
		fs->type=8;
		printf("TYPE = 'double'\n");
	}
	if(fs->type==0)
	{
		printf("Invalid DATA_TYPE '%s' + %d bytes\n\n",type,fs->size);
		exit(0);
	}
	if(fs->minlat==360.0)
	{
		fs->minlat=fs->maxlat-(double)(fs->numlat-1)*fs->latspace;
		printf("LOWER_RIGHT_LAT = %lf\n",fs->minlat);
	}
	if(fs->maxlon==-360.0)
	{
		fs->maxlon=fs->minlon+(double)(fs->numlon-1)*fs->lonspace;
		printf("LOWER_RIGHT_LON = %lf\n",fs->maxlon);
	}
	fs->dellat=fs->maxlat-fs->minlat;
	fs->dellon=fs->maxlon-fs->minlon;
	printf("LAT_RANGE = %lf\n",fs->dellat);
	printf("LON_RANGE = %lf\n",fs->dellon);
	if(fs->numlat==0&&fs->dellat>0.0)
	{
		fs->numlat=(fs->dellat+fs->latspace/1000.0)/fs->latspace;
		printf("NUMBER_OF_LAT = %d\n",fs->numlat);
	}
	if(fs->numlon==0&&fs->dellon>0.0)
	{
		fs->numlon=(fs->dellon+fs->lonspace/1000.0)/fs->lonspace;
		printf("NUMBER_OF_LON = %d\n",fs->numlon);
	}
	if(fs->numlon==0)
	{
		printf("Could not find or calculate NUMBER_OF_LON\n");
		exit(0);
	}
	if(fs->numlat==0)
	{
		printf("Could not find or calculate NUMBER_OF_LAT\n");
		exit(0);
	}
	if(fs->minlon>=360.0)
	{
		printf("Could not find or calculate UPPER_LEFT_LON\n");
		exit(0);
	}
	if(fs->maxlat<=-360.0)
	{
		printf("Could not find or calculate UPPER_LEFT_LAT\n");
		exit(0);
	}
	if(fs->numlon==0)
	{
		printf("Could not find or calculate DELTA_LON\n");
		exit(0);
	}
	if(fs->numlat==0)
	{
		printf("Could not find or calculate DELTA_LAT\n");
		exit(0);
	}
}




/**********************************************************************
**
**
**
**********************************************************************/

int not_read(char *what)

{
	printf("# Could not read '%s'\n",what);
	print_format();
}



/**********************************************************************
**
**
**
**********************************************************************/

int not_open(char *filename,char *action)

{
	printf("? Could not open '%s' to %s.\n\n",filename,action);
	exit(0);
}



/**********************************************************************
**
**
**
**********************************************************************/

int print_format()

{
	printf("\n");
	printf("\n");
	printf("Command Line:\n");
	printf("\n");
	printf(
"clip_lbs [infil] [outfil] [rw1] [cl1] [orw] [ocl] [sample]]\n");
	printf("\nwhere:\n");
	printf("   infil --- input file name without extension\n");
	printf("   outfil -- output file name without extension\n");
	printf("   rw1 ----- first row in input image to use in output image\n");
	printf("   cl1 ----- first column in input image to use in output image\n");
	printf("   orw ----- number of rows to use from input image\n");
	printf("   ocl ----- number of columns to use from input image\n");
	printf("   sample -- OPTIONAL sample rate ( 2 will give orow/2 x ocol/2\n");
	printf("\n");
	printf("Example:\n");
	printf("\n");
	printf("clip_lbs test1 test2 1500 3500 500 500 2\n");
	printf("\n");
	printf(
		"Will clip a 500x500 pixel piece out of the bottom right corner of\n");
	printf(
		"'test1.dat' (which is 2000 rows by 4000 columns), put it in \n");
	printf(
		"'test2.dat and reduce it to 250x250 pixels by sampling every\n");
	printf(
		"2nd pixel and every 2nd row.  It will also make 'test2.lbs'.\n");
	exit(0);
}


/**********************************************************************
**
**
**
**********************************************************************/

FILE *fopen_path(char *filename,char *type)

{
	int i,j,k;
	FILE *fp;
	char string[100];

	fp=fopen(filename,type);
	if(fp)
		return(fp);
	for(i=0;i<NumPath;i++)
	{
		sprintf(string,"%s%s",Path[i],filename);
		fp=fopen(string,type);
		if(fp)
			return(fp);
	}
	return(NULL);
}

                      