#!/usr/bin/env jython

import os.path
import sys
import glob
import time
import stilts
import re 

from java.lang import *
from java.sql import *

from java.lang import Math
from org.apache.commons.math.special import Erf

from xml.etree.ElementTree import ElementTree, Element, tostring

from batch import Batch
from gpc1db import Gpc1Db
from ipptopspsdb import IppToPspsDb
from scratchdb import ScratchDb
from dvoforcedgalaxy import DvoForcedGalaxy # need one specific for cpy.
from sqlUtility import sqlUtility

import logging.config

'''
ForcedGalaxyBatch class

This class, a sub-class of Batch, processes full force summary products.

'''
class ForcedGalaxyBatch(Batch):

    '''
    Constructor
    '''
    def __init__(self,
                 logger,
                 config,
                 skychunk,
                 gpc1Db,
                 ippToPspsDb,
                 scratchDb,
                 dvoID,
                 batchID):

        super(ForcedGalaxyBatch, self).__init__(
            logger,
            config,
            skychunk,
            gpc1Db,
            ippToPspsDb,
            scratchDb,
            dvoID,
            batchID,
            "FG",
            None)

        try:
            self.dvoForcedGalaxy = DvoForcedGalaxy(self.logger, self.config, self.skychunk, self.ippToPspsDb, self.scratchDb, self.gpc1Db)
        except:
            self.logger.errorPair("Unable to create instance of", "DvoForcedGalaxy")
            raise

        # create an output filename
        self.outputFitsFile = "%08d.FITS" % self.id
        self.outputFitsPath = "%s/%s" % (self.localOutPath, self.outputFitsFile)

        # dump stuff to log
        self.logger.infoPair("DVO INDEX", "%d" % self.id)

    '''
    Generate ippObjID and make it an index 
    '''
    def addIppObjID (self, tableName):
        sql = "ALTER TABLE " + tableName + " ADD COLUMN ippObjID BIGINT"
        self.scratchDb.execute(sql)
        
        sql = "CREATE INDEX ippObjID_index ON " + tableName + " ( ippObjID ) ";
        self.scratchDb.execute(sql)

        sql = "UPDATE " + tableName + " set ippObjID = (OBJ_ID + (CAT_ID << 32))"
        self.scratchDb.execute(sql)

    '''
    Overriden from batch base class to import directly from DVO for forced galaxy shape parameters
    '''
    def importIppTables(self, columns="*", filter=""):
        self.region = self.scratchDb.getRegionNameFromThisDvoIndex(self.id)
#        self.ippToPspsDb.insertForcedSummaryMeta(self.batchID, self.region)
        self.dvoForcedGalaxy.nativeIngestRegion(self.region)

        cptTableName = self.scratchDb.getDbFriendlyTableName(self.region + ".cpt")

        if not self.scratchDb.tableExists(cptTableName):
            self.logger.infoPair("can't find in scratch db:", "cpt table")
            return False

        cpqTableName = self.scratchDb.getDbFriendlyTableName(self.region + ".cpq")
        
        if not self.scratchDb.tableExists(cpqTableName):
            self.logger.infoPair("can't find in scratch db:", "cpq table")
            return False
            
        self.logger.infoPair("checking if we have anything in"," cpq/cpt")
        rowcountcpt = self.scratchDb.getRowCount(cptTableName);
        rowcountcpq = self.scratchDb.getRowCount(cpqTableName);
        
        if (rowcountcpt == 0):
            self.logger.infoPair("0 rows for ","cpt table")
            return False
        if (rowcountcpq == 0):
            self.logger.infoPair("0 rows for ","cpq table")
            return False

        # add ippObjID columns and index them:
        self.addIppObjID (cptTableName)
        self.addIppObjID (cpqTableName)

        return True

    '''
    Applies indexes to the PSPS tables
    '''
    def alterPspsTables(self):
        return True

    '''
    Applies indexes to the IPP Tables
    '''
    def indexIppTables(self):
        return True

    '''
    Updates table and generates pspsuniqueids
    '''
    def updatePspsUniqueIDs(self):
        sql = "UPDATE ForcedGalaxyShape set uniquePspsFGid = (("+str(self.batchID)+"*1000000000 ) + row)"
        self.scratchDb.execute(sql)

    '''
    Actually inserts the science data
    '''
    def updateForcedGalaxyShapeFromCpq(self, cpqTable):

        # Get filter information as in forcedobjectbatch.py
        interestedFilters = ['g','r','i','z','y']
        filters = self.scratchDb.getOrderedListOfFiltersFromPhotcodesTable(interestedFilters)
        filterCount = self.scratchDb.getCountOfFiltersFromPhotcodesTable()

        self.logger.infoPair("Available filters in Photcodes", filters)

        self.logger.infoPair("Adding measurements from", "cpq table")

        for filter in filters:
            filterID = self.scratchDb.getFilterID(filter[1])
            
            photcodeName = "NONE"
            if self.config.camera == "gpc1":
                photcodeName = "GPC1." + filter[1] + ".ForcedWarp"
            if self.config.camera == "simtest":
                photcodeName = "SIMTEST." + filter[1] + ".ForcedWarp"
            
            photcode = self.scratchDb.getPhotcodeByName(photcodeName)
            
            # XXX hard-wired platescale : 0.25
            pltscale = 0.25

            # This is going to need to join elsewhere to get all the fields?
            # XforcedSummaryID, Ra, Dec, RaErr, DecErr
            # Should GalChiSq fold in Npix somehow? 
            
            sqlLine = sqlUtility("UPDATE ForcedGalaxyShape AS a, " + cpqTable + " AS b SET")
            sqlLine.group("a." + filter[1] + "ippDetectID",     "b.DET_ID")
            sqlLine.group("a." + filter[1] + "stackImageID",    "b.IMAGE_ID")
            sqlLine.group("a." + filter[1] + "GalMajor",        "b.MAJOR_AXIS     * " + str(pltscale))
            sqlLine.group("a." + filter[1] + "GalMajorErr",     "b.MAJOR_AXIS_ERR * " + str(pltscale))
            sqlLine.group("a." + filter[1] + "GalMinor",        "b.MINOR_AXIS     * " + str(pltscale))
            sqlLine.group("a." + filter[1] + "GalMinorErr",     "b.MINOR_AXIS_ERR * " + str(pltscale))
            sqlLine.group("a." + filter[1] + "GalMag",          "b.MAG")
            sqlLine.group("a." + filter[1] + "GalMagErr",       "b.MAG_ERR")
            sqlLine.group("a." + filter[1] + "GalPhi",          "b.THETA")
            sqlLine.group("a." + filter[1] + "GalIndex",        "b.SERSIC_INDEX")
            sqlLine.group("a." + filter[1] + "GalFlags",        "b.FLAGS")
            sqlLine.group("a." + filter[1] + "GalChisq",        "b.CHISQ")

            # we insert data for each of the possible model types, counting the number of filter/model values
            # selected for each type.  later we will delete rows for which nFilter is 0
            sqlLine.group("a.nFilter", "a.nFilter + 1")
            
            # These fields don't exist.
            # sqlLine.group("a." + filter[1] + "GalRa",           "b.RA")
            # sqlLine.group("a." + filter[1] + "GalDec",          "b.DEC")
            # sqlLine.group("a." + filter[1] + "GalRaErr",        "b.RA_ERR")
            # sqlLine.group("a." + filter[1] + "GalDecErr",       "b.DEC_ERR")
            
            sql = sqlLine.makeEquals("WHERE a.ippObjID = b.ippObjID AND a.galModelType = b.MODEL_TYPE AND b.Photcode = " + str(photcode))
            
            self.logger.debugPair("cpq sql: ", sql)
            
            self.scratchDb.execute(sql)

            ## # check on the status as we go:
            ## sql = "select count(*) as N, galModelType, nFilter, count(*)*nFilter as S from ForcedGalaxyShape group by galModelType, nFilter"
            ## rs = self.scratchDb.executeQuery(sql)  
            ## 
            ## while rs.next():
            ##     N = rs.getInt(1)
            ##     M = rs.getInt(2)
            ##     F = rs.getInt(3)
            ##     S = rs.getInt(4)
            ##     
            ##     print "N: %d, TYPE: %d, nFilter: %d, Sum: %d" % (N, M, F, S)

    '''
    Populate ForcedGalaxyShape table with basic IDs
    '''
    def populateForcedGalaxyShapeTable(self):

        cptTableName = self.scratchDb.getDbFriendlyTableName(self.region + ".cpt")
        cpqTableName = self.scratchDb.getDbFriendlyTableName(self.region + ".cpq")
        
        self.logger.info("Populating ForcedGalaxyShape")

        # the cpt file has the basic object data (IDs).  insert a row for each of the
        # model types of interest, listed in the array below
        self.logger.info("Inserting from cpt file")
        for modelName in ["PS_MODEL_EXP", "PS_MODEL_DEV", "PS_MODEL_SERSIC"]:
            modelID = self.scratchDb.getFitModelID(modelName)
            ## assert on modelID > 0

            sqlLine = sqlUtility("INSERT INTO ForcedGalaxyShape (")

            # uniquePspsFGid is set elsewhere
            # batchID isn't in the schema, should it be?

            sqlLine.group("objID",             "EXT_ID")
            sqlLine.group("ippObjID",          "ippObjID")
            sqlLine.group("surveyID",          str(self.surveyID))
            sqlLine.group("randomForcedGalID", "RAND("+str(self.batchID)+")")
            sqlLine.group("nFilter",           "0")
            sqlLine.group("galModelType",      str(modelID))

            sql = sqlLine.makeRaw(") SELECT ", " FROM " + cptTableName)

            # print "--- sql: " + sql

            self.scratchDb.execute(sql)

        # add in the actual galaxy photometry & shape measurements
        self.logger.infoPair("update ForcedGalaxyShape from ","cpq table")
        self.updateForcedGalaxyShapeFromCpq(cpqTableName)

        # drop the rows with no galaxy photometry
        self.logger.infoPair("dropping rows with no data", "ForcedGalaxyShape")
        sql = "DELETE FROM ForcedGalaxyShape WHERE nFilter = 0"
        self.scratchDb.execute(sql)

        # now we need to generate a unique psps ID:
        self.logger.infoPair("Adding 'row' columns to", "ForcedGalaxyShape table")
        self.scratchDb.addRowCountColumn("ForcedGalaxyShape", "row")

        self.logger.infoPair("generating unique ids for ","ForcedGalaxyShape")
        self.updatePspsUniqueIDs()

        self.logger.infoPair("Dropping row column from ", "ForcedGalaxyShape table")
        self.scratchDb.dropColumn("ForcedGalaxyShape", "row")

        self.logger.infoPair("setting minmaxobjid for ", "ForcedGalaxyShape table")
        self.setMinMaxObjID(["ForcedGalaxyShape"])

        self.logger.infoPair("checking if we have detections", "ForcedGalaxyShape table")
        rowcount = self.scratchDb.getRowCount("ForcedGalaxyShape")

        if rowcount == 0:
            self.logger.infoPair("skipping this one", "ForcedGalaxyShape")
            self.skipBatch = False
            return True
        else:
            return True

    '''
    Populate psps tables
    '''
    def populatePspsTables(self):
        
        if not self.populateForcedGalaxyShapeTable(): 
            return False
            
        return True
