
import adcptool.adcpimport     #@UnusedImport (actually used in the eval() parts)
import adcptool.outliers    #@UnusedImport

class DataClass():
    '''
    a class to store and manage all the ADCP data in this tool.
    automatic retrieval and updating included.
    '''
    
    def __init__(self, parent=0):
        
        # method register (pretty unpythonic)
        self.methreg = dict(
                        rawprofile='adcptool.adcpimport.RawProfileObj(self.cfg["rawprofile"])',
                        cellmatrix='adcptool.outliers.get_cell_matrix(self.rawprofile)',
                        valuematrix='adcptool.outliers.get_valuematrix_from_cellmatrix(self.cellmatrix, self.cfg["valuematrix"], 1)',
                        goodvaluematrix='adcptool.outliers.get_valuematrix_from_cellmatrix(self.cellmatrix, self.cfg["valuematrix"], 2)',
                        relatdev='adcptool.outliers.get_relative_deviation_simple(self.valuematrix, self.goodvaluematrix, self.cfg["relatdev"])',
                        outliermatrix='adcptool.outliers.get_outliers(self.relatdev, self.goodvaluematrix, self.cfg["outliermatrix"])'
                        )

        self.depencies = {
                        'rawprofile':[],
                        'cellmatrix':['rawprofile'],
                        'valuematrix':['cellmatrix'],
                        'goodvaluematrix':['cellmatrix'],
                        'relatdev':['valuematrix', 'goodvaluematrix'],
                        'outliermatrix':['relatdev']
                        }
        #
        # populate dicts from methreg
        
        self.data = dict(list(zip(list(self.methreg.keys()), [None] * len(self.methreg))))        # hold the actual data
        self.cfg  = dict(list(zip(list(self.methreg.keys()), [None] * len(self.methreg))))        # stores the public cfg
        self.cfg_saved = dict(list(zip(list(self.methreg.keys()), [None] * len(self.methreg))))        # store private cfg (the one that has been used for creating data)

        self.testa = dict(list(zip(list(self.methreg.keys()), [None] * len(self.methreg))))        # store private cfg (the one that has been used for creating data)
        self.testb = dict(list(zip(list(self.methreg.keys()), [None] * len(self.methreg))))        # store private cfg (the one that has been used for creating data)
        
    def __getattr__(self, m):
        '''
        this is called to retrieve an arbitrary attribute. 
        they have to be named like in the self.methreg in order to work
        '''
        
#        print '-----------------------------------'
#        print('a:{}, b:{}'.format(self.testa['rawprofile'], self.testb['rawprofile']))
#        self.testa['rawprofile'] = 'foobar'
#        print '-----------------------------------'
#        print('a:{}, b:{}'.format(self.testa['rawprofile'], self.testb['rawprofile']))
        
        
        
        
#        print('DBG: DataClass(): {} * requested.'.format(m))
#        print('DBG: DataClass(): OLD config:')
#        self.print_cfg( self.cfg_saved[m])
#        print('DBG: DataClass(): NEW config:')
#        self.print_cfg( self.cfg[m])
#        print '-----------------------------------'
        
        
        
        
        if self.data[m] == None or self.cfg[m] != self.cfg_saved[m] or self.depcheck(m):
            # if needed: create the data (again)
#            print('DBG: DataClass(): {} + updating.'.format(m))
            if type(self.cfg[m]) == type(dict()):
                self.cfg_saved[m] = self.cfg[m].copy()
            else:
                self.cfg_saved[m] = self.cfg[m]
            self.data[m] = eval(self.methreg[m])
#            print m, type(self.data[m]), type(self.cfg[m]), type(self.cfg_saved[m])
            
        return self.data[m]

    def print_cfg(self, x):
        ''' 
        a debug function that prints out the config dictionary nicely
        '''
        
        print(x)
        

    def depcheck(self, m):
        '''
        somehow make the dependency chekcing
        '''
        for dep in self.depencies[m]:
#            print('depcheck: {}:{}'.format(m, dep))
            if self.cfg[dep] != self.cfg_saved[dep]:
#                print('depcheck: {}:{}: cfg has changed'.format(m, dep))
                return True
            else:
                return self.depcheck(dep)
        

def get_guicfg(tk):
    ''' 
    return an empty dictionary that contains the structure
    that hold the Tk/Variables. unfortunately this is not the 
    same structure as the "real data structure" which is based
    on the method names in DataClass() 
    '''
    
    guicfg = dict(
                inputfile     = tk.StringVar(),
                outliers    = dict(
                                enabled=tk.BooleanVar(),
                                radius_h=tk.IntVar(),
                                radius_v=tk.IntVar(),
                                limit=tk.StringVar()
                                )
                ) 
    
    return guicfg


def gui2cfg(guicfg, cfg, module=False):
    '''
    read field variables from the GUI and write it into cfg. depending on module,
    it either writes all or only the specified module 
    '''
    
    
#    if module:
#        for key in guicfg[module].keys():
#            if not hasattr(guicfg[module][key], 'get'):
#                cfg[key] = guicfg[module][key]
#            else:
#                cfg[key] = guicfg[module][key].get()
    

    cfg['rawprofile'] = guicfg['inputfile'].get()
    cfg['relatdev']['radius_h'] = int(guicfg['outliers']['radius_h'].get())
    cfg['relatdev']['radius_v'] = int(guicfg['outliers']['radius_v'].get())
    cfg['relatdev']['enabled'] = bool(guicfg['outliers']['enabled'].get())
    cfg['outliermatrix']['limit'] = float(guicfg['outliers']['limit'].get())
    cfg['outliermatrix']['enabled'] = bool(guicfg['outliers']['enabled'].get())
            
    
    return cfg


def cfg2gui(guicfg, cfg, module=False):
    '''
    write the data from the cfg dictionary to the GUI variables.
    '''
    
#    if module:
#        for key in guicfg:
#            print('module: {}, key: {}, value:{}'.format(module, key, cfg[module][key]))
#            guicfg[module][key].set(cfg[module][key])
    
    #ugly but works
    guicfg['inputfile'].set(cfg['rawprofile'])
    guicfg['outliers']['radius_h'].set(cfg['relatdev']['radius_h'])
    guicfg['outliers']['radius_v'].set(cfg['relatdev']['radius_v'])
    guicfg['outliers']['enabled'].set(cfg['relatdev']['enabled'])
    guicfg['outliers']['limit'].set(cfg['outliermatrix']['limit'])
    guicfg['outliers']['enabled'].set(cfg['outliermatrix']['enabled'])

    return guicfg

    

def get_default_cfg():
    ''' 
    return a default config that can be used as suggestion to the user 
    and also provides settings that cannot be changed in the GUI
    
    '''
    
    cfg = dict(
        rawprofile = '../testfiles/demodata.txt',
        valuematrix = '.velocity_comp.v',
        relatdev = dict(radius_h=5, radius_v=0, enabled=1),
        outliermatrix = dict(limit=2.5, enabled=1),
        
        
        goodvaluematrix = None,
        cellmatrix = None,
        outfolder = '../testfiles/'
            )
    
    return cfg
    
    

# -----------------------------------------------------------------------------
if __name__ == '__main__':
    dc = DataClass()
    
    
    dc.cfg = get_default_cfg()
    
    print(dc.cfg)
    
    rd = dc.relatdev
    ol = dc.outliermatrix
    
    print(dc.cfg_saved, '\n', dc.cfg)
    print('#### updating #######################################################')
    
    dc.cfg['relatdev']['radius_h'] = 7
    print(dc.cfg_saved, '\n', dc.cfg)
    
    
    ol = dc.relatdev
    
    
    
    
    