#!/usr/bin/env python

# 2014-02-18 tuneparam :  'while num > 500' changed to 'while num > 250'

import os
import sys
import re
import math
#import shutil
#import glob
import commands
from pyraf import iraf
from iraf import obsutil


def tuneparam(ffile, fnum, mlim):

    SCRIPTDIR = os.path.realpath(os.path.dirname(sys.argv[0])) 

    # os.system("%s/badfill %s recomtmp.fits" % (SCRIPTDIR, ffile))
    # badpixel filling is necessary so that psfmeasure does not crash.  
    # badfillw enlarges a frame from 1024x1024 to 1080x1080 in order to avoid a crash due to 
    # psfmeasure's "Pixel subscript out of bounds" error.  
    cprog = 'badfillw'
    badout = commands.getoutput("%s/%s %s recomtmp.fits" % (SCRIPTDIR, cprog, ffile)) 
    #print '%s %s' % (ffile, badout)
    med, stddev = badout.split()
    med = float(med)
    stddev = float(stddev)

    # badfillw already calculates med and stddev 
    # no need to use getstat anymore
    # med, stddev = getstat('recomtmp.fits')
    iraf.apphot.datapars.sigma = stddev
    iraf.apphot.datapars.datamin = med - 10 * stddev

    if os.access('ap.coo', os.F_OK):   #   added 2013.4.26 
        os.remove('ap.coo')            #
    if os.access('recomtmp.fits', os.R_OK):
        iraf.daofind.output = 'ap.coo'
        iraf.daofind('recomtmp.fits')
    else:
        print 'no recomtmp.fits for %s' % ffile
        return 999, 999, med, stddev, -1

    num = 0
    f = open('ap.coo')
    for line in f:
        if line[:1] != '#':
           num += 1 
    f.close()

    while num > 250:    #  2014-02-18
        os.remove('ap.coo')
        iraf.apphot.findpars.threshold += 5
        iraf.daofind('recomtmp.fits')
        num = 0
        f = open('ap.coo')
        for line in f:
            if line[:1] != '#':
                num += 1
        f.close()

    if num < 10:

        mnum = num
        mfwhm = iraf.apphot.datapars.fwhmpsf
        if os.access('map.coo', os.F_OK):   #  added 2013.4.26
            os.remove('map.coo')            #
        os.rename('ap.coo', 'map.coo')
        for tfwhm in [2, 4, 6, 8, 10]:
            iraf.apphot.datapars.fwhmpsf = tfwhm
            iraf.daofind.output = 'tap.coo'
            iraf.daofind('recomtmp.fits')
            f = open('tap.coo')
            tnum = 0
            for line in f:
                if line[:1] != '#':
                    tnum += 1 
            f.close()
       
            if tnum > mnum:
                mnum = tnum
                mfwhm = tfwhm
                os.rename('tap.coo', 'map.coo')
            else:
                os.remove('tap.coo')

        print 'ifwhm: ', mfwhm     # debug
        print '10-sigma num: ', mnum    # debug

        if mnum < 10:
            iraf.apphot.datapars.fwhmpsf = mfwhm
            iraf.apphot.findpars.threshold = 7
            iraf.daofind.output = 'map.coo'
            if os.access('map.coo', os.F_OK):   #   added 2013.4.12
                os.remove('map.coo')            #   
            iraf.daofind('recomtmp.fits')
            mnum = 0
            f = open('map.coo')
            for line in f:
                if line[:1] != '#':
                    mnum += 1 
            f.close()

            print '7-sigma num: ', mnum  # debug

            if mnum < 10:
                os.remove('map.coo')
                iraf.apphot.findpars.threshold = 5
                iraf.daofind.output = 'map.coo'
                iraf.daofind('recomtmp.fits')
                mnum = 0
                f = open('map.coo')
                for line in f:
                    if line[:1] != '#':
                        mnum += 1 
                f.close()
                
                print '5-sigma num: ', mnum # debug

            if mnum == 0:
                os.remove('recomtmp.fits')
                return 999, 999, med, stddev, 0

        num = mnum 
        iraf.apphot.datapars.fwhmpsf = mfwhm
        if os.access('ap.coo', os.F_OK):   #  added 2013.4.26
            os.remove('ap.coo')            #
        os.rename('map.coo', 'ap.coo')
            
    # end of if num < 10 

    iraf.apphot.photpars.apertures = iraf.apphot.datapars.fwhmpsf
    iraf.phot('recomtmp.fits', coords='ap.coo', output='ap.mag')

    # this will not occur, but just in case
    if not os.access('ap.mag', os.R_OK):  
        os.remove('ap.coo')
        print 'sirrecom L97 : ap.mag not found for %s' % fnum
        print 'please report to the developer of this software'
        os.remove('recomtmp.fits')
        return 999, 999, med, stddev, 0

    # merr < mlim is just for excluding merr=INDEF 
    iraf.txdump('ap.mag', fields='xc,yc,mag,merr,cier,sier,pier', expr='merr<'+str(mlim), Stdout='coo.txt') 
    os.remove('ap.mag')
    #os.rename('ap.coo', fnum+'.coo')
    os.remove('ap.coo')

    # maximum of 30 stars are enough to measure  
    # fwhm and ellipticity of a frame
    # the stars should be isolated, i.e. not contaminated by nearby stars. 
    snum = prepsf(fnum)
    os.remove('coo.txt')

    if snum == 0:
        print 'sirrecom L116 : no isolated stars in %s' % fnum
        os.remove('recomtmp.fits')
        return 999, 999, med, stddev, 0
    
    iraf.psfmeasure.radius = 2 * iraf.apphot.datapars.fwhmpsf            
    iraf.psfmeasure('recomtmp.fits', logfile='psfme.txt', Stderr=1, Stdout=1, StdoutG='/dev/null')
    #os.rename('recomtmp.fits', 'recom'+fnum+'.fits')


    fwhm, ellip = getpsf()

    if snum >= 10:
        os.remove('recomtmp.fits')
        return fwhm, ellip, med, stddev, snum

    else: 

        if os.access('ap.coo', os.F_OK):   #   added 2013.4.26 
            os.remove('ap.coo')            #
        iraf.apphot.datapars.fwhmpsf = fwhm
        iraf.daofind.output = 'ap.coo'
        iraf.daofind('recomtmp.fits')

        num = 0
        f = open('ap.coo')
        for line in f:
            if line[:1] != '#':
                num += 1 
        f.close()

        if num < 10:
            if os.access('map.coo', os.F_OK):   #   added 2013.4.26
                os.remove('map.coo')            #   
            iraf.apphot.findpars.threshold = 7
            iraf.daofind.output = 'map.coo'
            iraf.daofind('recomtmp.fits')
            mnum = 0
            f = open('map.coo')
            for line in f:
                if line[:1] != '#':
                    mnum += 1 
            f.close()

            if mnum < 3:
                os.remove('map.coo')
                iraf.apphot.findpars.threshold = 5
                iraf.daofind.output = 'map.coo'
                iraf.daofind('recomtmp.fits')
                mnum = 0
                f = open('map.coo')
                for line in f:
                    if line[:1] != '#':
                        mnum += 1 
                f.close()

                
            if mnum == 0:
                os.remove('recomtmp.fits')
                return 999, 999, med, stddev, 0

            os.rename('map.coo', 'ap.coo')

        # end of num < 10
    
        iraf.apphot.photpars.apertures = fwhm 
        iraf.phot('recomtmp.fits', coords='ap.coo', output='ap.mag')

        if not os.access('ap.mag', os.R_OK):  
            os.remove('ap.coo')
            print 'sirrecom L166 : ap.mag not found for %s' % fnum
            print 'please report to the developer of this software'
            return 999, 999, med, stddev, 0

        iraf.txdump('ap.mag', fields='xc,yc,mag,merr,cier,sier,pier', expr='merr<'+str(mlim), Stdout='coo.txt') 
        os.remove('ap.mag')
        #os.rename('ap.coo', fnum+'.coo')
        os.remove('ap.coo')

        # maximum of 30 stars are enough to measure  
        # fwhm and ellipticity of a frame
        # the stars should be isolated, i.e. not contaminated by nearby stars. 
        snum = prepsf(fnum)
        os.remove('coo.txt')

        if snum == 0:
            print 'sirrecom L193 : no isolated stars in %s' % fnum
            os.remove('recomtmp.fits')
            return 999, 999, med, stddev, 0

        
        iraf.psfmeasure.radius = 2 * iraf.apphot.datapars.fwhmpsf            
        iraf.psfmeasure('recomtmp.fits', logfile='psfme.txt', Stderr=1, Stdout=1, StdoutG='/dev/null')
        #os.rename('recomtmp.fits', 'recom'+fnum+'.fits')
        os.remove('recomtmp.fits')

        fwhm, ellip = getpsf()
        return fwhm, ellip, med, stddev, snum



def seqphot(band, itime, ifwhm, mlim, stype):

    iraf.digiphot(_doprint = 0)
    iraf.apphot(_doprint = 0)
    
    iraf.digiphot.unlearn()
    iraf.apphot.unlearn()
    iraf.daofind.unlearn()
    iraf.ptools(_doprint = 0)
    iraf.ptools.unlearn()
    iraf.txdump.unlearn()
    iraf.obsutil()
    iraf.obsutil.unlearn()
    iraf.psfmeasure.unlearn()
    
    iraf.apphot.datapars.datamax = 20000
    iraf.apphot.datapars.readnoise = 30
    iraf.apphot.datapars.epadu = 5
    iraf.apphot.datapars.itime = itime
    iraf.apphot.datapars.fwhmpsf = ifwhm
    iraf.apphot.findpars.threshold = 10
    iraf.apphot.findpars.sharphi = 0.8
    iraf.apphot.daofind.interac = 'no'
    iraf.apphot.daofind.verify = 'no'
    
    iraf.apphot.phot.interactive = 'no'
    iraf.apphot.phot.verify = 'no'
    iraf.apphot.phot.verbose = 'no'
    iraf.apphot.photpars.zmag = 21
    iraf.apphot.photpars.apertures = ifwhm

    iraf.psfmeasure.display = 'no'
    iraf.psfmeasure.imagecur = 'psfcoo.txt'
    iraf.psfmeasure.graphcur = 'q.txt'

    fo = open('q.txt', 'w')
    print >> fo, 'q'
    fo.close()

    if os.access('ap.coo', os.F_OK):
        os.remove('ap.coo')
    if os.access('ap.mag', os.F_OK):
        os.remove('ap.mag')
    if os.access('coo.txt', os.F_OK):
        os.remove('coo.txt')

    SCRIPTDIR = os.path.realpath(os.path.dirname(sys.argv[0])) 

    fo2 = open(band+'quality.txt', 'w')
    fo = open(band+'fwhm.txt', 'w')
    print 'fnum fwhm ellip star_num thresh    med    stddev'
    print >> fo2, 'fnum fwhm ellip star_num thresh    med    stddev'
    fin = open(band+stype+'recom.list')
    for line in fin:

        fdir = (line[:-1].split())[0]
        fnum = (line[:-1].split())[1]
        raoff = (line[:-1].split())[3]
        decoff = (line[:-1].split())[4]
        
        yymmdd = (fdir.split('ffiles'))[0]

        ffile = '../' + fdir + '/' + band + 'f' + fnum + '.fits'
        outmag = yymmdd + band + 'f' + fnum + '.mag'
        if os.access(ffile, os.R_OK):

            # tuning the parameters 
            fwhm, ellip, med, stddev, snum = tuneparam(ffile, fnum, mlim)
            
            if snum == -1:  #  no recomtmp.fits was found. this will not likely happen. 
                continue

            if snum == 0:
                print 'No star was detected for %s' % fnum
                continue

            iraf.apphot.datapars.fwhmpsf = fwhm


            if yymmdd == '0.':
                print '%s  %.1f  %.2f  %3d      %4.1f  %8.1f %5.1f' % (fnum, fwhm, ellip, snum, iraf.apphot.findpars.thresh, med, stddev)
                print >> fo2, '%sf%s  %.1f  %.2f  %3d      %4.1f  %8.1f %5.1f' % (band, fnum, fwhm, ellip, snum, iraf.apphot.findpars.thresh, med, stddev)
            else:
                print '%s%s  %.1f  %.2f  %3d      %4.1f  %8.1f %5.1f' % (yymmdd, fnum, fwhm, ellip, snum, iraf.apphot.findpars.thresh, med, stddev)
                print >> fo2, '%s%sf%s  %.1f  %.2f  %3d      %4.1f  %8.1f %5.1f' % (yymmdd, band, fnum, fwhm, ellip, snum, iraf.apphot.findpars.thresh, med, stddev)


            #if ellip > 0.6:
            #    print 'seqphot warning: large ellipticity'


            if fwhm < 5:
                iraf.apphot.centerpars.cbox = 5
            else:
                iraf.apphot.centerpars.cbox = fwhm
                
            iraf.apphot.fitskypars.annulus = 3 * fwhm
            iraf.apphot.fitskypars.dannulus = 2 * fwhm
            iraf.apphot.photpars.apertures = fwhm

            cprog = 'badfill'
            os.system("%s/%s %s recomtmp2.fits" % (SCRIPTDIR, cprog, ffile))
            if os.access('recomtmp2.fits', os.F_OK):

                if os.access('ap.coo', os.F_OK):   #   added 2013.4.26 
                    os.remove('ap.coo')            #
                iraf.daofind.output = 'ap.coo'
                iraf.daofind('recomtmp2.fits')
                iraf.phot(ffile, coords='ap.coo', output='ap.mag')
                iraf.phot('recomtmp2.fits', coords='ap.coo', output='apb.mag')

                if os.access('ap.mag', os.F_OK) and os.access('apb.mag', os.F_OK):
                    iraf.txdump('ap.mag', fields='xc,yc,mag,merr,cier,sier,pier', expr='merr<'+str(mlim), Stdout='ap.2.mag')
                    iraf.txdump('apb.mag', fields='xc,yc,mag,merr,cier,sier,pier', expr='merr<'+str(mlim), Stdout='apb.2.mag')

                    snum = nnd2(outmag)

                    print >> fo, '%s%sf%s %s %s %.1f %.2f %d' % (yymmdd, band, fnum, raoff, decoff, fwhm, ellip, snum)
                    
                    os.remove('ap.mag')
                    os.remove('apb.mag')
                    os.remove('ap.coo')
                    os.remove('ap.2.mag')
                    os.remove('apb.2.mag')
                    os.remove('recomtmp2.fits')

                else:
                    print 'no star was found for %s%sf%s' % (yymmdd, band, fnum)
                    os.remove('ap.coo')
                    os.remove('recomtmp2.fits')
                    if os.access('ap.mag', os.F_OK):
                        os.remove('ap.mag')
                    if os.access('apb.mag', os.F_OK):
                        os.remove('apb.mag')
                    if os.access('ap.2.mag', os.F_OK):
                        os.remove('ap.2.mag')
                    if os.access('apb.2.mag', os.F_OK):
                        os.remove('apb.2.mag')

            else:
                print 'recomtmp2.fits not found for %s%sf%s' % (yymmdd, band, fnum)

            if os.access('psfcoo.txt', os.F_OK):
                os.remove('psfcoo.txt')
                os.remove('psfme.txt')

    fin.close()
    fo.close()
    fo2.close()
    os.remove('q.txt')


def getpsf():

    fwhm = []
    ellip = []
    f = open('psfme.txt')
    for line in f:
        if re.search('\S', line[:-1]):
            values = line[:-1].split()
            if values[0] == 'Image':
                tmp = line[:-1].split('Image')
                head = len(tmp[0])+5
            elif not re.search('NOAO', line) and not re.search('maximum', line):  
                # 2011.11.25
                # changed 'Average' to 'maximum' for frames with only one star
                subline = line[head:-1]
                coos = subline.split()
                if re.search('.', coos[3]) or coos[3].isdigit():
                    fwhm.append(float(coos[3]))
                    ellip.append(float(coos[4]))
    f.close()

    # an assumption that ellip is not INDEF if fwhm is not INDEF 

    n = len(fwhm)
    fwhm.sort()
    if n%2 == 0:
        med = 0.5* (fwhm[n/2-1] + fwhm[n/2])
    else:
        med = fwhm[n/2]
        
    ellip.sort()
    if n % 2 == 0:
        med2 = 0.5* (ellip[n/2-1] + ellip[n/2])
    else:
        med2 = ellip[n/2]

    return med, med2


def prepsf(fnum):

    # to remove stars have cier!=0 or sier!=0 or pier!=0  

    txcoo = []
    tycoo = []
    tmag = []
    tmerr = []
    f = open('coo.txt')
    for line in f:
        values = line[:-1].split()
        # 4:cier 5:sier 6:pier 
        if values[4] == '0' and values[5] == '0' and values[6] == '0':
            txcoo.append(float(values[0]))
            tycoo.append(float(values[1]))
            tmag.append(float(values[2]))
            tmerr.append(float(values[3]))
    f.close()

    if len(txcoo) == 0:
        print '%s no star with cier!=0 && sier!=0 && pier!=0' % fnum
        return 0

    # pick up isolated stars 

    xcoo = []
    ycoo = []
    mag = []
    merr = []
    for i in range(len(txcoo)):
        rmin = 1000
        for j in range(len(txcoo)):
            if i != j:
                rr = math.sqrt((txcoo[j] - txcoo[i]) ** 2 + (tycoo[j] - tycoo[i]) ** 2)
                if rr < rmin:
                    rmin = rr

        if rmin > 10:
            xcoo.append(txcoo[i])
            ycoo.append(tycoo[i])
            mag.append(tmag[i])
            merr.append(tmerr[i])
    
    if len(xcoo) == 0:
        print '%s too crowded. fwhm and ellipticity may be unreliable.' % fnum
        for i in range(len(txcoo)):
            xcoo.append(txcoo[i])
            ycoo.append(tycoo[i])
            mag.append(tmag[i])
            merr.append(tmerr[i])

    #
    # use the 30 brightest stars for psfmeasure 
    #

    fo = open('psfcoo.txt', 'w')

    if len(xcoo) > 30:
        mdict = {}
        for i in range(len(merr)):
            mdict[i] = merr[i]

        psfnum = 0
        for k, v in sorted(mdict.items(), key=lambda x:x[1]):
            psfnum += 1
            if psfnum <= 30:
                print >> fo, xcoo[k], ycoo[k]
            else:
                break
        psfnum = 30
    else:
        psfnum = len(xcoo)
        for i in range(len(xcoo)):
            print >> fo, xcoo[i], ycoo[i]

    fo.close()

    return psfnum



def nnd2(outmag):

    xd = []
    yd = []
    
    f = open('apb.2.mag')
    for line in f:
        values = line[:-1].split()
        if values[2] != 'INDEF':
            xd.append(float(values[0]))
            yd.append(float(values[1]))
    f.close()


    txc = []
    tyc = []
    tmag = []
    tmerr = []
    tcier = []
    tsier = []
    tpier = []
    mflag = []
    
    f = open('ap.2.mag')
    for line in f:
        values = line[:-1].split()
        if values[2] != 'INDEF':
            txc.append(float(values[0]))
            tyc.append(float(values[1]))
            tmag.append(values[2])
            tmerr.append(values[3])
            tcier.append(values[4])
            tsier.append(values[5])
            tpier.append(values[6])
            mflag.append(0)
    f.close()

    xcnum = len(txc)

    for i in range(xcnum):
        for j in range(i+1, xcnum):
            rr = math.sqrt( (txc[j] - txc[i]) ** 2 + (tyc[j] - tyc[i]) ** 2 )
            if rr < 0.1:
                mflag[j] = 1

    xc = []
    yc = []
    mag = []
    merr = []
    cier = []
    sier = []
    pier = []

    for i in range(xcnum):
        if mflag[i] == 0:
            xc.append(txc[i])
            yc.append(tyc[i])
            mag.append(tmag[i])
            merr.append(tmerr[i])
            cier.append(tcier[i])
            sier.append(tsier[i])
            pier.append(tpier[i])


    snum = 0
    fo2 = open(outmag, 'w')
    for i in range(len(xc)):
        rmin = 1000
        sflag = 0
        for j in range(len(xd)):
            rr = math.sqrt( (xd[j] - xc[i]) ** 2 + (yd[j] - yc[i]) ** 2 )
            if rr < 1:
                sflag = 1
            elif rr < rmin:
                rmin = rr

        for j in range(len(xc)):
            if i !=j: 
                rr = math.sqrt( (xc[j] - xc[i]) ** 2 + (yc[j] - yc[i]) ** 2 )
                if rr < rmin:
                    rmin = rr

        if sflag == 1:
            print >> fo2, "%.2f %.2f %.2f %s %s %s %s %s" % (rmin, xc[i], yc[i], mag[i], merr[i], cier[i], sier[i], pier[i])
            snum += 1
        else:
            pass
            #print 'nnd2 warning : a star at (x, y) = (%.2f, %.2f) was not detected for the badfill frame.' % (xc[i], yc[i])
            #print 'you can ignore this warning.'

    fo2.close()

    return snum




if __name__ == "__main__":

    print 'sirrecom.py is a module repository.'

