
from shinsapp import SHINSApp
from util.shinsLogger import logger
from util import variables as uvars
from util import functions as ufun
from util import exception
import numpy as np

from SHARKNIR_gen_base import SHARKNIR_gen_base

class SHARKNIR_cal_tec_NCPA_PD_lab(SHINSApp):

    @exception.handler_for_run
    def run(self, ins_s=None, det_s=None, tel_s=None, rtc_s=None, **kwargs):
        '''Calculate NCPA with PD using fibers.
        '''

        logger.info(__name__)
        self.status = uvars.EXIT_SUCCESS
        obsController = self.obsController

        self.gen_base = SHARKNIR_gen_base();        gen_base = self.gen_base

        fitsDir = uvars.fitsDir + obsController.getCurrentDataDirectory() +'/'

        #############################################
        # START AND WAIT INSTRUMENT AND SASHA SETUP #
        #############################################

        gen_base.main(ins_s=ins_s, det_s=det_s, expose=False)

        sci_filt_w1 = ins_s["SCI_FILT_W1"]
        sci_filt_w2 = ins_s["SCI_FILT_W2"]
        self.master_array = [] # the list of images CDS-subtracted and meaned over NREADS=10

        # Apo positions are shared between focus and defocus loops
        several_apos = ["HOLE3", "Lens_PD_neg", "Lens_PD_pos"]

        ##########################
        # OPEN REAL-TIME TT LOOP #
        ##########################
        if self.paragraph("OPEN REAL-TIME TT LOOP"):
            logger.info("TT open loop")
            self.status = obsController.RTCTTOpenLoop()
            ufun.error_handler(self.status, "RTCTTOpenLoop")
            logger.debug(self.status)
            logger.info("Tip tilt loop open on TECCAM")
        
        ###################################
        # LOOP FOCUS FIBER: SETUP + IMAGE #
        ###################################

        several_drops = ["0", "96", "96"]

        logger.info("***Starting Focus fiber loop")

        for apo, drop in zip(several_apos, several_drops):

            ins_s = {
                "CAL_FIBER_DEP": "FOCUS_IN",
                "CAL_FIBER_FOCUS_LAMP": "ON",
                "CAL_FIBER_DEFOCUS_LAMP": "OFF",
                "APODIZER_W": apo,
            }

            det_s = {"NDROPS": drop}

            logger.info("****Start focus setup and image")
            self.status, self.filename, self.other = gen_base.main(ins_s=ins_s, det_s=det_s)
            logger.info("****End focus setup and image")

            if self.paragraph("Focused {}".format(apo)):

                self.master_array = ufun.ncpa_masterize(fitsDir, self.filename, self.master_array)

        #####################################
        # LOOP DEFOCUS FIBER: SETUP + IMAGE #
        #####################################

        several_drops = ["19", "138", "17"]

        logger.warning("Starting Defocus fiber loop")
        for apo, drop in zip(several_apos, several_drops):

            ins_s = {
                "CAL_FIBER_DEP": "DEFOCUS_IN",
                "CAL_FIBER_FOCUS_LAMP": "OFF",
                "CAL_FIBER_DEFOCUS_LAMP": "ON",
                "APODIZER_W": apo,
            }

            det_s = {"NDROPS": drop}

            logger.info("****Start defocus setup and image")
            self.status, self.filename, self.other = gen_base.main(ins_s=ins_s, det_s=det_s)
            logger.info("****End defocus setup and image")

            if self.paragraph("Defocused {}".format(apo)):

                self.master_array = ufun.ncpa_masterize(fitsDir, self.filename, self.master_array)

        ########################################
        # ONERA CODE in IDL, using IDL bridges #
        ########################################
        if self.paragraph("ONERA processing"):
            wvl = ufun.determine_filter_wavelength(sci1 = sci_filt_w1 , sci2=sci_filt_w2)
            zernikes = ufun.call_onera(self.master_array, wavelength=wvl, occultation=0.0)

        ###################
        # Calculate modes #
        ###################
        if self.paragraph("Calculate modes modes"):

            logger.info("Found these zernikes:")
            logger.info(str(zernikes))

            modes = ufun.zernikes_to_modes(zernikes)#, filename="221130_fibers.txt")

            logger.info("Function zernike_to_modes returns:")
            logger.info(str(modes))

        logger.info("Setup final configuration ... ")
        final_ins_s = {
            "APODIZER_W":"HOLE",
            "CAL_FIBER_DEP" : "FOCUS_IN",
            "CAL_FIBER_DEFOCUS_LAMP" : "OFF",
            "CAL_FIBER_FOCUS_LAMP" : "ON"
        }
        self.status , _, _ = gen_base.main(ins_s=final_ins_s, expose=False)
        logger.info("Setup final configuration ... DONE")

        ##################
        # PAUSE / RESUME #
        ##################
        self.paragraph("CONTINUE and APPLY or STOP and NOT APPLY")
        #self.paused = True
        logger.warning("From WEB INTERFACE: Continue if you agree to apply; Stop otherwise.")
        logger.warning("From COMMAND LINE: Resume if you agree to apply; Quit otherwise.")
        print("(R)esume, (Q)uit")
        
        import sys
        from select import select
        
        timeout = 2
               
        answer = None
        print("Enter something:"),
        self.paused = True
        
        
        while self.paused==True and self.aborted==False:

            rlist, _, _ = select([sys.stdin], [], [], timeout)
            if rlist:
                answer = sys.stdin.readline()
                print(answer)
            else:
                print("still waiting...")

            if answer:
                if answer.lower().startswith('r'):
                    self.paused = False
                    pass
                if answer.lower().startswith('q'):
                    self.paused = False
                    self.aborted = True
                    self.abort()
                    return
                else:
                    pass

            
        ###############
        # Apply Modes #
        ###############
        
        reserved = [0,0]
        zeros = [0,0,0,0] # tip tilt piston focus

        logger.info("Upload a mode vector to internal DM")
        self.status = obsController.RTCTTModeUpload(reserved+zeros+modes, absolute=False)
        logger.info("Waiting setup to apply displacement... DONE")

        ########################
        # Save and apply flat #
        ########################
        if self.paragraph("Save and apply flat"):
            
            from util import master_listener_davide
            
            thread = master_listener_davide.PLOT_THREAD()
            thread.start()
            thread.RUN = True
            print("plot thread started")
            
            flat_name = ufun.save_flat(self.obsController, thread)
            logger.info("Save DM flat file... DONE")
            logger.info(flat_name)
            
            thread.CLOSE = True
            thread.RUN = False
            print("plot thread stopped")

            logger.info("Flaten DM")
            modes = [0] * 39
            status = self.obsController.RTCTTModeUpload(modes, absolute=True)
            logger.info("Flaten DM...done")
            
            logger.info("Apply DM flat file...")
            rtc_s = {"TTDMFLATFILE": flat_name}
            status = self.obsController.RTCTTExecuteSetup(rtc_s)
            logger.info("Apply DM flat file... DONE")

