#!/usr/bin/perl

#
# Properly register all 8 frames and combine into a mosaic
#
#==================================================================#
# First, grow cosmic ray masks so that we're sure there will be no #
# residual peaks which will cause ringing in the mscimage task.    #

# Insert BPM header cards

# Apply the high-order astrometry (from imacswcs) to each image,   #
# using mscimage. 

# Mosaic these images and use mscgetcat and msccmatch to solve for #
# the lower-order corrections (rotation & translation) in the 4    #
# central chips (applied to full field). 

# At all stages, be sure that the bad pixel mask is transforming   #
# in the same way.                                                 #

# Create PSF catalogues which will be used in imacscombine to do   #
# psf-matching of several frames.                                  #
#==================================================================#
#

# History
#  08June13  MM  created
#  08June17  MM  added psf measurement for psf-matching later
#  08June27  MM  added transforming of bad pixel masks
#
# Detailed help message
#

use Getopt::Long;
use Text::Wrap;


@usage = ("v1.2  MM  17June2008\n\nUsage: imacsreg (OBJECTS) \n\n");
@help = (
         "\t---------------\n ",
         "\tREQUIRED INPUTS\n ",
         "\t---------------\n ",
         "\tOBJECTS is a file containing all of the flat-fielded, \n",
	 "\tsky-subtracted pointings. For example:\n\n",
         "\tssfccd0001\n",
	 "\tssfccd0002\n",
	 "\tssfccd0003\n",
	 "\t...\n\n",
	 "\tEach of these files needs to have a corresponding msk*.fits\n",
	 "\tfile, produced by running \"imacscr\"\n",
	 "\t*NOTE* - Input files MUST be sky-subtracted before running imacsreg!\n",
         "\t------\n ",
         "\tOUTPUT\n ",
         "\t------\n ",
         "\tThe output is an IRAF CL script named 'register.cl'; run\n",
         "\tthis file at the cl> prompt with the following syntax:\n",
         "\tcl> cl < register.cl\n",
         "\tThe IRAF script returns images prepended by 'sh', \n",
	 "\t--------\n",
	 "\tSWITCHES\n",
	 "\t--------\n",
	 "\t--radius=<num> : Provide search radius for coarse alignment.\n",
	 "\t                 (default = 30.0)\n",
	 "\t--minmag=<num> : Provide minimum magnitude for stars which are\n",
	 "\t                 used to measure and match psfs.\n",
	 "\t                 (default=15 for 20min exp, scales w/ time)\n",
	 "\t--maxmag=<num> : Provide maximum magnitude for stars which are\n",
	 "\t                 used to measure and match psfs.\n",
	 "\t                 (default=19 for 20min exp, scales w/ time)\n",
	 "\t--fast         : Perform linear interpolation rather than\n",
	 "\t                 sinc17 interpolation when running mscimage.\n",
         );


if ($#ARGV lt 1) {
    if ($#ARGV eq 0) {
        if ($ARGV[0] eq "--help") {
            print @usage;
	    print @help;
            print "\n\n";
            exit;
        }
    } else {
        die "@usage\For detailed help: imacsreg --help\n\n";
    }
}

$speed = '';
$rad=30;

## Get min and max mag based on 20min exposure at 7050A ##
$minmag=999;
$maxmag=999;

GetOptions ('fast' => \$speed,
	    'radius=f' => \$rad,
	    'minmag=f' => \$minmag,
	    'maxmag=f' => \$maxmag);
if ($speed ne '') {
    $speed='linear';
} else {
    $speed='sinc17';
}

if ($minmag==999){
    $calcmags=1;
} else {
    $calcmags=0;
}

open OBJ, $ARGV[0];
@obj = <OBJ>;
close OBJ;

# Proper DETSEC keyword values for each chip.
@detsec = ("[1:2048,1:4096]",
           "[2049:4096,1:4096]",
           "[4097:6144,1:4096]",
           "[6145:8192,1:4096]",
           "[4096:2049,8192:4097]",
           "[2048:1,8192:4097]",
           "[8192:6145,8192:4097]",
           "[6144:4097,8192:4097]");


@aapply=();
@psf=();
push @aapply, "noao\n";
push @aapply, "imred\n";
push @aapply, "crutil\n";
foreach (@obj){
    @line=parse($_);
    for $i (1..8) {
	# First, grow the cosmic ray mask and insert it in the header
	push @aapply, "del temp_bpm.pl\n";
	push @aapply, "imcopy msk$line[0]c$i.fits temp_bpm.pl\n";
	push @aapply, "crgrow temp_bpm.pl msk$line[0]c$i\_bpm.pl radius=1.0 inval=1 outval=1\n";
	push @aapply, "hedit $line[0]c$i BPM \'msk$line[0]c$i\_bpm.pl\' add+ verify-\n";
	
	# Now, replace masked pixels by 0.0 (sky value) #
	# We do this so that sinc interpolation won't #
	# produce rings. We will NOT use this data later, #
	# we will reject masked regions when we stack. #

	push @aapply, "del temp.fits\n";
	push @aapply, "imcopy msk$line[0]c$i\_bpm.pl temp.fits\n";
	push @aapply, "imarith temp.fits - 1.0 temp.fits\n";
	push @aapply, "imarith temp.fits * -1.0 temp.fits\n";
	push @aapply, "imarith $line[0]c$i.fits * temp.fits cc$line[0]c$i.fits\n";
	
    }
}
push @aapply, "bye\nbye\nbye\n";

push @aapply, "mscred\n";
push @aapply, "del astrom.pos\n";
push @aapply, "del imcut.fits\n";
push @aapply, "del temp_bpm.pl\n";

open OBJ, $ARGV[0];
@obj = <OBJ>;
close OBJ;
foreach (@obj){

    @line=parse($_);

    for $i (1..8) {

	# First apply the high-order distortion corrections #
	# Interpolate bad pixel mask linearly and image using sinc #
	push @aapply, "mscimage cc$line[0]c$i a$line[0]c$i reference=\"cc$line[0]c$i.fits\" verbose+ interpolant=\"$speed\" minterpolant=\"linear\" scale=0.202 pixmask+ nxblock=2048 nyblock=4096\n";

	# Now mosaic the image #
    	push @aapply, "hedit a$line[0]c$i DETSEC $detsec[$i-1] add+ verify-\n";
	if ($i==1){
	    push @aapply, "imcopy a$line[0]c$i a$line[0]\[chip$i\]\n";
	}else{
	    push @aapply, "imcopy a$line[0]c$i a$line[0]\[chip$i,append\]\n";
	}
	push @aapply, "hedit a$line[0]\[chip$i\] IMAGEID $i add+ verify-\n";
    }

    # Flatten the image using mscimage a second time #
    # Interpolate mask using nearest value, since this should just be shifts #
    push @aapply, "mscimage a$line[0] aa$line[0] verbose+ interpolant=\"$speed\" minterpolant=\"nearest\" scale=0.202 pixmask+ nxblock=2048 nyblock=4096\n";

    # Now determine lower-order corrections  #
    # If this hangs up, use CADC:USNO-A2 #
    
    # First isolate 4-chip region
    push @aapply, "imcopy aa$line[0]\[2200:6100,1000:7500\] imcut\n";

    # Next, produce source catalogue. Get exposure time first #
    if ($calcmags==1)
    {
        open IN, "$line[0]c2.fits";
        @in = <IN>;
        close IN;
        foreach (@in) {
            if (/SIMPLE/) {
                @hline=parse($_);
                for $j (0..$#hline) {
                    if ($hline[$j] =~ /EXPTIME/) {
                        $etime=$hline[$j+2];
		    }
                }
            }
        }
	#15th mag ~= 30,000 counts  for 1200s
	#19th mag ~=  1,000 counts  for 1200s
	$minmag=-2.5*log10(10**(-0.4*15.0)*20.*60./$etime);
	$maxmag=-2.5*log10(10**(-0.4*19.0)*20.*60./$etime);
	print "$line[0]: exp time = $etime, minmag=$minmag, maxmag=$maxmag\n";
    }

    push @aapply, "mscgetcat imcut astrom.pos magmax=$maxmag magmin=$minmag catalog=\"NOAO:USNO-A2\" rmin=0.01\n";  
    
    # ..then coarse alignment #
    push @aapply, "msccmatch aa$line[0] astrom.pos usebpm- update+ verbose+ interactive- search=$rad rsearch=3 fitgeometry=\"general\" nsearch=100 csig=0.025 reject=3 cfrac=0.9\n";
    # ...and finally, fine alignment #
    push @aapply, "msccmatch aa$line[0] astrom.pos usebpm- update+ verbose+ interactive- search=0 nsearch=0 fitgeometry=\"general\" csig=0.025 reject=3 cfrac=0.9\n";

    # Now, set the BPM file WCS to match! #
    push @aapply, "imgets aa$line[0] CRVAL1\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CRVAL1 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CRVAL2\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CRVAL2 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CRPIX1\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CRPIX1 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CRPIX2\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CRPIX2 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CD1_1\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CD1_1 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CD1_2\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CD1_2 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CD2_1\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CD2_1 real(imgets.value) add+ ver-\n";
    push @aapply, "imgets aa$line[0] CD2_2\n";
    push @aapply, "hedit aa$line[0]_bpm.pl CD2_2 real(imgets.value) add+ ver-\n";

    # And clean up.. #
    push @aapply, "del imcut.fits\n";
    push @aapply, "del astrom.pos\n";
}

## Now, measure the psf of several stars in each field to 
## use later in psf-matching routing

open OBJ, $ARGV[0];
@obj = <OBJ>;
close OBJ;
foreach (@obj){

    @line=parse($_);

    # First, create sub-image #
    push @psf, "del imcut.fits\n";
    push @psf, "imcopy aa$line[0]\[2400:6000,1600:6600\] imcut\n";

    # Next, create coordinate file.  Get exposure time first #
    if ($calcmags==1)
    {
        open IN, "$line[0]c2.fits";
        @in = <IN>;
        close IN;
        foreach (@in) {
            if (/SIMPLE/) {
                @hline=parse($_);
                for $j (0..$#hline) {
                    if ($hline[$j] =~ /EXPTIME/) {
                        $etime=$hline[$j+2];
		    }
                }
            }
        }
	#15th mag ~= 30,000 counts  for 1200s
	#19th mag ~=  1,000 counts  for 1200s
	$minmag=-2.5*log10(10**(-0.4*15.0)*20.*60./$etime);
	$maxmag=-2.5*log10(10**(-0.4*19.0)*20.*60./$etime);
	print "$line[0]: exp time = $etime, minmag=$minmag, maxmag=$maxmag\n";
    }

    push @psf, "del astrom.pos\n";
    push @psf, "mscgetcat imcut.fits astrom.pos magmax=$maxmag magmin=$minmag catalog=\"NOAO:USNO-A2\" rmin=0.1\n";
    push @psf, "wcsctran astrom.pos aa$line[0].stars aa$line[0] world physical units=\"h n\"\n";
}

push @psf, "bye\n";
push @psf, "noao\n";
push @psf, "obsutil\n";

foreach (@obj){
    @line=parse($_);

    # Now, find psfs for each field #
    # Will trim these later #
    push @psf, "psfmeasure images=\"aa$line[0]\" coords=\"markall\" wcs=\"physical\" display=no size=\"MFWHM\" radius=4 iterations=4 sbuffer=10 swidth=5 logfile=\"aa$line[0].psf\" imagecur=\"aa$line[0].stars\" graphcur=\"cursor.txt\" >G \"dev\$null\"\n";
}

@cursr=();
push @cursr, "0 0 1 q\n";
unlink <cursor.txt>;  # remove old cursor.txt file
open OUT, ">cursor.txt";
print OUT @cursr;
close OUT;

unlink <register.cl>; #remove old scripts first
open OUT, ">register.cl";
print OUT @aapply;
print OUT @psf;
close OUT;

print fill("\t","",("Now enter IRAF and run 'register.cl':\n cl> cl <
register.cl\n "));
print "\n";



#######################

sub parse {
    my(@parsed);
    @parsed = split(/\s+/,$_[0]);
    chomp(@parsed);
    #remove whitespace at beginning of line, if any
    while ($parsed[0] eq "") {shift(@parsed)}
    return(@parsed);
}

##########################
# @array = PARSECOM($line)
# Parse by commas
# 08feb11  DSNR  created
##########################

sub parsecom {
    my(@parsed);
    @parsed = split(/,+/,$_[0]);
    chomp(@parsed);
    #remove whitespace at beginning of line, if any
    while ($parsed[0] eq "") {shift(@parsed)}
    return(@parsed);
}

sub log10 {
    my $n = shift;
    return log($n)/log(10);
}
