from collections import defaultdict
from datetime import datetime
import re

__all__ = ['transform']

#dsp values to check against for each step
_dsp_values = {
    1: [23,41,44],
    2: [11, 12,13,14,22,31,33,34,35,36,38,40,42,43,48,49],
    3: [90],
    4: [81],
    5: [32],
    6: [46],
    7: [45],
    8: [47],
    9: [43],
    10: [48],
    11: [52],
    12: [51],
    13: [97],
    14: [82],
    15: [12],
    16: [83],
    17: [84],
    18: [21],
    19: [88],
    20: [89],
    21: [19],
    22: [98],
    23: [99],
}

#QUESTION does entries in "Precode ... for all entries without these cdisps" refer to all cycle entries or all entries where the chglit is the same 
def transform(observations, region):
    '''covers caseflowchart. observations should be a dictionary where key = observation id and value = observation data'''
    #TODO this needs to be reworked completely
    cycle_data = defaultdict(list)
    nb_35_delflags = defaultdict(list)
    nj_35_delflags = defaultdict(list)
    nb_35_dsps = defaultdict(list)
    
    chg_var = 'cchg' if region in ('ut', 'md') else 'cchglitx'
    _revoked_re = re.compile('sentence revoked', flags=re.I)
    
    if region in ('ok', 'ut'):
        _dsp_values[2].append(37)
        
    for key, row in observations.iteritems(): 
        if region == 'nb' and row['cdsp'] == 35:
            if row['cdispyr'] != 9999:
                nb_35_delflags[(row['cycnum'], row[chg_var])].append((datetime(row['cdispyr'], row['cdispmo'], row['cdispda']), row))
        elif region == 'nj' and row['cdsp'] == 35:
            if row['sntyr'] != 9999:
                nj_35_delflags[(row['cycnum'], row[chg_var])].append((datetime(row['sntyr'], row['sntmo'], row['sntda']), row))
        cycle_data[(row['cycnum'], row[chg_var])].append(row)
            
    for key, cycle_info in cycle_data.iteritems():
        _break = False
        if len(cycle_info) > 1:
            dsps = [r['cdsp'] for r in cycle_info]
            #iterate over the steps
            for step in xrange(1,19):
                #check each dsp value in the step
                for dsp in _dsp_values[step]:
                    #if the dsp value is in the dsps for the current cycle
                    if dsp in dsps:
                        #then iterate over the cycle_info applying the rule for the step
                        for _row in cycle_info:
                            if _row['cdsp'] not in _dsp_values[step]:
                                if step in (1,2):
                                    #observations[_row['id']]['delflag'] = 1
                                    observations[_row['id']]['delflag'] = 'flow-%s' % step
                                    observations[_row['id']]['step'] = step
                                    observations[_row['id']]['matchdsp'] = dsp
                                else:
                                    observations[_row['id']]['delflag'] = 'flow-%s' % step
                                    observations[_row['id']]['step'] = step
                                    observations[_row['id']]['matchdsp'] = dsp
                            
                        _break = True
                        break
                
                if step == 2: 
                    if region == 'nb':
                        min_dt = 0
                        #TODO this may need to be reworked to include all multiple entries
                        if len(nb_35_delflags[key]) > 1:
                            for dt, row in sorted(nb_35_delflags[key], key=lambda k: k[0]):
                                if min_dt == 0: #first item in list set min_dt to date and proceed to next
                                    min_dt = dt
                                    continue
                                
                                #if the dates do not match flag for deletion
                                if min_dt != dt: 
                                    #observations[row['id']]['delflag'] = 1
                                    observations[row['id']]['delflag'] = 'flow-2b'
                                    _break = True
                                    
                    elif region == 'nj':
                        min_dt = 0
                        #TODO this may need to be reworked to include all multiple entries
                        if len(nj_35_delflags[key]) > 1:
                            
                            for dt, row in sorted(nj_35_delflags[key], key=lambda k: k[0]):
                                if min_dt == 0: #first item in list set min_dt to date and proceed to next
                                    min_dt = dt
                                    continue
                                
                                #if the dates do not match flag for deletion
                                if min_dt != dt: 
                                    #observations[row['id']]['delflag'] = 1
                                    observations[row['id']]['delflag'] = 'flow-2b'
                                    _break = True
                                    
                    elif region in ('ok', 'ut'):
                        if 37 in dsps and 35 in dsps:
                            for _row in cycle_info:
                                if _row['cdsp'] == 37:
                                    #observations[_row['id']]['delflag'] = 1
                                    observations[_row['id']]['delflag'] = 'flow-2b'
                        
                        if region == 'ok':
                            if dsps.count(35) > 1:
                                _revoked = False
                                for _row in cycle_info:
                                    if _row['cdsp'] == 35 and _revoked_re.search(_row['crtcmtx'] if _row['crtcmtx'] else ''): 
                                        _revoked= True
                                
                                if _revoked:
                                    for _row in cycle_info:
                                        if _row['cdsp'] == 35 and _revoked_re.search(_row['crtcmtx'] if _row['crtcmtx'] else ''):
                                            #observations[_row['id']]['delflag'] = 1
                                            observations[_row['id']]['delflag'] = 'flow-2c'
                        
                if _break: break

#region specific dsp values
#def _apply_dsp_del_flag(step, cycnum, chglit, cycle_delflags):
#    for chg, dsp, del_flag, id in cycle_delflags[cycnum]:
#        if dsp not in _dsp_values[step] and chglit != chg:
#            del_flag = True
#    
#    return cycle_delflags    
#      cycle_chgs = defaultdict(list)
#    cycle_dsps = defaultdict(list)
#    cycle_delflags = defaultdict(list)
#    nb_35_dsps = defaultdict(list)
#    
#    chg_var = 'cchg' if region in ('ut', 'md') else 'cchglitx'
#    
#    if region in ('ok', 'ut'):
#        dsp_values['step_2'].add(37)
#        
#    for row in observations: 
#        #how to apply ut-md do we compare cchg against all observations in cycle (do cycles contain different state data)
#        cycle_chgs[row['cycnum']].append(row[cchg_var])
#        cycle_dsps[row['cycnum']].append(row)
#        if region == 'nb' and row['cdsp'] == 35:
#            nb_35_delflags[row['cycnum']].append((datetime(row['cdispyr'], row['cdispmo'], row['cdispda']), row))
#            
#        cycle_delflags[row['cycnum']].append((row[chg_var], row['cdsp'], False, row['id']))
#        cycle_seq[(row['cycnum'], row[chg_var])].append((row['cdsp'], row['id']))                      
                    
#    for row in observations:
#        '''step0 does entry in the cycle have others in the same cycle that match on the same chg_desc'''
#        if row[chg_var] not in cycle_chgs[row['cycnum']]:
#            continue
#        
#        #TODO make recursive for speedup
#        '''STEP 1: A'''
#        for cycle_obs in cycle_dsps[row['cycnum']]:
#            if row[chg_var] == cycle_obs[chg_var]: #identify matching entries
#                '''step1: do any of the matching entries have a cdsp=23,41,44'''
#                if cycle_obs['cdsp'] in _dsp_values['step_1']:
#                    cycle_delflags = _apply_dsp_del_flag('step1', row['cycnum'], row[chg_var], cycle_delflags)
#                    continue
#                
#                '''step 2:...'''
#                if cycle_obs['cdsp'] in _dsp_values['step_2']:
#                    cycle_delflags = _apply_dsp_del_flag('step2', row['cycnum'], row[chg_var], cycle_delflags)
#                    continue
#                
#                #if
#    seq_ids = []
#    
#    '''STEP B'''
#    if region == 'nb':
#        for k,v in nb_35_delflags.iteritems():
#            #if multiple dsps with 35 check date values
#            if len(v) > 1:
#                min_dt = 0
#                for chg_lit, dt, del_flag, id in sorted(v, key=lambda k: k[0]):
#                    if min_dt == 0: #first item in list set min_dt to date and proceed to next
#                        min_dt = dt
#                        continue
#                    
#                    #if the dates do not match flag for deletion
#                    if min_dt != dt: 
#                        del_flag = 1
#    
#    elif region in ('ok', 'ut'):
#        pass
#    
#    '''STEP C'''
#   if region == 'ok':
#       pass