#! /usr/bin/env python

import time
import sys
import os
import os.path
import tables
import damaris.data.DataPool as DataPool
import damaris.gui.ResultReader as ResultReader
import damaris.gui.ExperimentWriter as ExperimentWriter
import damaris.gui.BackendDriver as BackendDriver
import damaris.gui.ResultHandling as ResultHandling
import damaris.gui.ExperimentHandling as ExperimentHandling

def some_listener(event):
    if event.subject=="__recentexperiment" or event.subject=="__recentresult":
        r=event.origin.get("__recentresult",-1)+1
        e=event.origin.get("__recentexperiment",-1)+1
        if e!=0:
            ratio=100.0*r/e
        else:
            ratio=100.0
        print("\r%d/%d (%.0f%%)"%(r,e,ratio), end=' ')


class ScriptInterface:

    def __init__(self, exp_script=None, res_script=None, backend_executable=None, spool_dir="spool"):
        self.exp_script=exp_script
        self.res_script=res_script
        self.backend_executable=backend_executable
        self.spool_dir=os.path.abspath(spool_dir)
        self.exp_handling=self.res_handling=None

        self.exp_writer=self.res_reader=self.back_driver=None
        if self.backend_executable is not None:
            self.back_driver=BackendDriver.BackendDriver(self.backend_executable, spool_dir)
            if self.exp_script: self.exp_writer=self.back_driver.get_exp_writer()
            if self.res_script: self.res_reader=self.back_driver.get_res_reader()
        else:
            self.back_driver=None
            if self.exp_script: self.exp_writer=ExperimentWriter.ExperimentWriter(spool_dir)
            if self.res_script: self.res_reader=ResultReader.ResultReader(spool_dir)

        self.data=DataPool()


    def runScripts(self):
        # get script engines
        if self.exp_script and self.exp_writer:
            self.exp_handling=ExperimentHandling.ExperimentHandling(self.exp_script, self.exp_writer, self.data)
        if self.res_script and self.res_reader:
            self.res_handling=ResultHandling.ResultHandling(self.res_script, self.res_reader, self.data)

        # start them
        if self.exp_handling: self.exp_handling.start()
        if self.back_driver is not None: self.back_driver.start()
        if self.res_handling: self.res_handling.start()

    def waitForScriptsEnding(self):
        # time of last dump
        dump_interval=600
        next_dump_time=time.time()+dump_interval
        # keyboard interrupts are handled in extra cleanup loop
        try:
            while [_f for _f in [self.exp_handling,self.res_handling,self.back_driver] if _f]:
                time.sleep(0.1)
                if time.time()>next_dump_time:
                    self.dump_data("pool/data_pool.h5")
                    next_dump_time+=dump_interval

                if self.exp_handling is not None:
                    if not self.exp_handling.is_alive():
                        self.exp_handling.join()
                        if self.exp_handling.raised_exception:
                            print(": experiment script failed at line %d (function %s): %s"%(self.exp_handling.location[0],
                                                                                             self.exp_handling.location[1],
                                                                                             self.exp_handling.raised_exception))
                        else:
                            print(": experiment script finished")
                        self.exp_handling = None

                if self.res_handling is not None:
                    if not self.res_handling.is_alive():
                        self.res_handling.join()
                        if self.res_handling.raised_exception:
                            print(": result script failed at line %d (function %s): %s"%(self.res_handling.location[0],
                                                                                         self.res_handling.location[1],
                                                                                         self.res_handling.raised_exception))
                        else:
                            print(": result script finished")
                        self.res_handling = None

                if self.back_driver is not None:
                    if not self.back_driver.is_alive():
                        print(": backend finished")
                        self.back_driver=None

        except KeyboardInterrupt:
            still_running=[_f for _f in [self.exp_handling,self.res_handling,self.back_driver] if _f]
            for r in still_running:
                r.quit_flag.set()

            for r in still_running:
                r.join()

    def dump_data(self, filename):
        try:
            # write data from pool
            dump_file=tables.open_file(filename,mode="w",title="DAMARIS experiment data")
            self.data.write_hdf5(dump_file, complib='zlib', complevel=6)
            # write scripts
            scriptgroup=dump_file.create_group("/","scripts","Used Scripts")
            dump_file.create_array(scriptgroup,"experiment_script", self.exp_script)
            dump_file.create_array(scriptgroup,"result_script", self.res_script)
            dump_file.create_array(scriptgroup,"backend_executable", self.backend_executable)
            dump_file.create_array(scriptgroup,"spool_directory", self.spool_dir)
            dump_file.flush()
            dump_file.close()
            dump_file=None
            # todo
        except Exception as e:
            print("dump failed", e)
       


if __name__=="__main__":

    if len(sys.argv)==1:
        print("%s: data_handling_script [spool directory]"%sys.argv[0])
        sys.exit(1)
    if len(sys.argv)==3:
        spool_dir=os.getcwd()
    else:
        spool_dir=sys.argv[3]
    
    expscriptfile=open(sys.argv[1])
    expscript=expscriptfile.read()
    resscriptfile=open(sys.argv[2])
    resscript=resscriptfile.read()

    si=ScriptInterface(expscript, resscript,"/usr/lib/damaris/backends/Mobilecore", spool_dir)

    si.data.register_listener(some_listener)

    si.runScripts()

    si.waitForScriptsEnding()

    si.dump_data("data_pool.h5")

    si=None
