from collections import defaultdict
from collections import defaultdict
from datetime import datetime
import re
import chgseq
from ....util import key_as_str

__all__ = ['post_cycle', 'pre_cycle']


def post_cycle(region, aobvs={}, arrest_records=None, cobvs={}, sentence_records=None):
    if region == 'ar':
        oldcycles = defaultdict(list)
        oldcycle_chgs = defaultdict(dict)
        for row in cobvs.itervalues(): 
            for teststring in ["revocation of prev", "revocation of a prev", "revo prev", "revo of prev"]:
                if key_as_str(row['crtcmtx']).find(teststring) != -1:
                    #sentence_records[row['id']]['delflag'] = 1
                    sentence_records[row['id']]['delflag'] = 'ar'
            oldcycles[row['cycnum']].append(row)
            if row['cchglitx'] not in oldcycle_chgs[row['cycnum']].keys(): oldcycle_chgs[row['cycnum']][row['cchglitx']] = 1
            else: oldcycle_chgs[row['cycnum']][row['cchglitx']] += 1
        
        if len(oldcycles.keys()) > 1: #Step 2 Condition 1 met
            for row in cobvs.itervalues():
                if 'delflag' in sentence_records[row['id']].keys() and sentence_records[row['id']]['delflag'] == 'ar':
                    nonblank = True
                    match = True
                    for othercyc in [cycnum for cycnum in oldcycles.keys() if cycnum != row['cycnum']]:
                        for cchglit in oldcycle_chgs[row['cycnum']].keys():
                            if cchglit not in oldcycle_chgs[othercyc] or oldcycle_chgs[othercyc][cchglit] < oldcycle_chgs[row['cycnum']][cchglit]: match = False #Step 2 Condition 2 met
                        nonblank_test = False
                        for othercycrow in oldcycles[othercyc]: 
                            if othercycrow['snttextx'] != "": nonblank_test = True
                        if nonblank_test == False: nonblank = False #Step 2 Condition 3 met
                    if nonblank and match: 
                        for obv in oldcycles[row['cycnum']]:
                            sentence_records[obv['id']]['delflag'] = 'ar'
                        for obv in aobvs.itervalues():
                            if obv['cycnum'] == row['cycnum']:
                                #arrest_records[obv['id']]['delflag'] = 1
                                arrest_records[obv['id']]['delflag'] = 'ar'                            
     
    if region == "de":
        segments = [(aobvs,'achglit'),(cobvs,'cchglitx')]
        for segment in segments:
            test_rows = []
            for row in segment[0].itervalues():
                for teststr in ["violation of probation-", "civil contempt of court-"]:
                    if key_as_str(str(row[segment[1]]).lower()).find(teststr) != -1:
                        test_rows.append(row)
            if len(test_rows) > 1 and segment[1] == 'achglit':
                for row in test_rows:
                    if row['arryr'] != 9999 and row['offyr'] != 9999:
                        if datetime(row['arryr'],row['arrmo'],row['arrda']) < datetime(row['offyr'],row['offmo'],row['offda']):
                            #arrest_records[row['id']]['delflag'] = 1
                            arrest_records[row['id']]['delflag'] = 'de'
                            
            elif len(test_rows) > 1 and segment[1] == 'cchglitx':
                try:
                    min_dt = min([datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) 
                              for row in test_rows if row['cdispyr'] != 9999])
                except ValueError:
                    min_dt = None
                    
                for row in test_rows:
                    if min_dt and min_dt != datetime(row['cdispyr'], row['cdispmo'], row['cdispda']): 
                        #sentence_records[row['id']]['delflag'] = 1
                        sentence_records[row['id']]['delflag'] = 'de'
                        
    if region == "ia":
        parole = [row for row in cobvs.itervalues() if row['cchg'] in [490, 495, 500]]
        no_parole = len([row for row in cobvs.itervalues() if row['cchg'] not in [490, 495, 500]])
        if no_parole > 0 and len(parole) > 0:
            try:
                max_dt = max([datetime(row['sntyr'], row['sntmo'], row['sntda']) for row in cobvs.itervalues() if row['sntyr'] != 9999 and row['cchg'] not in [490, 495, 500]])
            except ValueError:
                max_dt = None
            if len([row for row in aobvs.itervalues() if row['achg'] in [490, 495, 500]]) == 0:
                for row in parole:
                    #TODO: verify that 9999 is the universal code for missing dates; if not, log
                    #if row['sntyr'] == 9999:
                     if row['sntyr'] == 9999 or (max_dt and datetime(row['sntyr'], row['sntmo'], row['sntda']) > max_dt):
                         #sentence_records[row['id']]['delflag'] = 1
                         sentence_records[row['id']]['delflag'] = 'ia'
                                                                
    if region == "mo":
        sentences = defaultdict(list)
        for row in cobvs.itervalues():
            if key_as_str(row['cdisptextx']).find("guilty") != -1 or key_as_str(row['cdisptextx']).find("guilty -sis") != -1:
                sentences[row['cchg']].append(row)
        for cchg in sentences.keys():
            if len(sentences[cchg]) > 1:
                try:
                    min_sntdt = min([datetime(row['sntyr'], row['sntmo'], row['sntda']) for row in sentences[cchg] if row['sntyr'] != 9999])
                except ValueError:
                    min_sntdt = None
                    
                missing = []
                for row in sentences[cchg]:
                    if row['sntyr'] == 9999:
                        missing.append(row)
                    elif min_sntdt and datetime(row['sntyr'], row['sntmo'], row['sntda']) > min_sntdt:
                        #sentence_records[row['id']]['delflag'] = 1
                        sentence_records[row['id']]['delflag'] = 'mo'
                if len(missing) > 0:
                    if len(missing) == len(sentences[cchg]): 
                        #all missing sentdates; use dispdate for all
                        try:
                            min_dspdt = min([datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) for row in missing if row['cdispyr'] != 9999])
                        except ValueError:
                            min_dspdt = None
                        for row in missing:
                            if min_dspdt and row['cdispyr'] != 9999 and datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) > min_dspdt:
                                #sentence_records[row['id']]['delflag'] = 1
                                sentence_records[row['id']]['delflag'] = 'mo'
                    else:
                        #some missing sentdates; use dispdate as substitute
                        for row in missing:
                            if row['cdispyr'] != 9999 and datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) > min_sntdt:
                                #sentence_records[row['id']]['delflag'] = 1
                                sentence_records[row['id']]['delflag'] = 'mo'
        hits = defaultdict(list)
        misses = defaultdict(list)
        for row in cobvs.itervalues():
            if key_as_str(row['cdisptextx']).find("change of venue") != -1: hits[row['cchglitx']].append(row)
            else: misses[row['cchglitx']].append(row)
        for cchg in hits.keys():
            if len(hits[cchg]) > 0 and len(misses[cchg]) > 0:
                for row in hits[cchg]:
                    #sentence_records[row['id']]['delflag'] = 1
                    sentence_records[row['id']]['delflag'] = 'mo'
    
    if region == "nb":
        #rule update via email: delete all PVs not at the first sentence date
        try:
            #compare_dt = max([datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) for row in cobvs.itervalues() if row['cdispyr'] != 9999 and row['cchg'] not in [490, 495, 500]])
            compare_dt = min([datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) for row in cobvs.itervalues() if row['cdispyr'] != 9999])
        except ValueError: compare_dt = None
        for row in cobvs.itervalues():
            try: row_dt = datetime(row['cdispyr'], row['cdispmo'], row['cdispda'])
            except ValueError: row_dt = None
            if row['cchg'] in [490, 495, 500] and compare_dt and row_dt and row_dt > compare_dt:
                #sentence_records[row['id']]['delflag'] = 1
                sentence_records[row['id']]['delflag'] = 'nb'

    

    
    if region == "nc":
        if len([row for row in aobvs.itervalues() if row['achg'] in [490, 495, 500]]) == 0: 
            try:
                compare_dt = min([datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) for row in cobvs.itervalues() if row['cchg'] not in [490, 495, 500] and row['cdispyr'] != 9999])
            except ValueError:
                compare_dt = None
                
            for row in cobvs.itervalues():
                if row['cchg'] in [490, 495, 500] and compare_dt and datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) > compare_dt:
#                    sentence_records[row['id']]['delflag'] = 1
                    sentence_records[row['id']]['delflag'] = 'nc'
    
    if region == "sc":
    
        for row in cobvs.itervalues():
            if row['cdsp'] == 81: 
                #sentence_records[row['id']]['delflag'] = 1 #rule 1
                sentence_records[row['id']]['delflag'] = 'sc' #rule 1
        
        '''Rule 2: For entries that say "MULTIPLE CHARGE ONE DISPOSITION;" in cdisptextx, 
        but have a blank snttextx field or snttextx says "COURT PROVISION: SAME AS ABOVE", 
        code the sentence variables (cnf,incmax, incmin, suspmax, suspmin, prb) to match a "MULTIPLE..." event 
        in the same cycle without a blank sntextx field.     
        
        If no "MULTIPLE.." event has a sentence entry, but anther charge is coded cdisp 35 and has a sentence, 
        code "MULTIPLES... to that sentence.

        '''
        multiples = []
        replacer = None
        backup = None
        for row in cobvs.itervalues():
            if key_as_str(row['cdisptextx']).find("multiple charge one disposition") != -1:
                if (key_as_str(row['snttextx']).find("court provision: same as above") != -1 or not row['snttextx']):
                    multiples.append(row)
                elif replacer == None:
                    replacer = row
            elif backup == None and row['cdsp'] == 35:
                backup = row
        if replacer == None and backup != None: replacer = backup
        if replacer != None:
            for multiple in multiples:
                #if multiple['id'] in [147824,147826,582117,582118]:
                    #print str(multiple['id']) + " replaced by " + str(replacer['id'])
                for var in ['cnf','incmax','incmin','suspmax','suspmin','prb','cdsp','pjp','pjp2', 'jpmx']:
                    sentence_records[multiple['id']][var] = replacer[var] #rule 2
                    
        if len(set([row['eventdate1x'] for row in cobvs.itervalues()])) == 1:
            pvs = []
            non_pvs = []
            for row in cobvs.itervalues():
                if key_as_str(row['cchglitx']).find("probation revocation") != -1 or key_as_str(row['cchglitx']).find("probation violation") != -1:
                    pvs.append(row)
                else: non_pvs.append(row)
            if len(non_pvs) > 0:
                compare_dt = min([datetime(row['cdispyr'], 
                                           row['cdispmo'] if row['cdispmo'] != 99 else 12, 
                                           row['cdispda'] if row['cdispda'] != 99 else 31) for row in non_pvs])
                for row in pvs:
                    if row['cdispyr'] != 9999 and datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) > compare_dt:
                        #sentence_records[row['id']]['delflag'] = 1 #rule 3
                        sentence_records[row['id']]['delflag'] = 'sc' #rule 3

    if region == "wi":
        sentences = defaultdict(list)
        for row in cobvs.itervalues():
            sentences[row['cchglitx']].append(row)
        for cchglit in sentences.keys():
            if len(sentences[cchglit]) > 1:
                try:
                    compare_dt = min([datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) for row in sentences[cchglit] if row['cdispyr'] != 9999])
                except ValueError:
                    compare_dt = None
                for row in sentences[cchglit]:
                    if compare_dt and datetime(row['cdispyr'], row['cdispmo'], row['cdispda']) > compare_dt:
                        #sentence_records[row['id']]['delflag'] = 1
                        sentence_records[row['id']]['delflag'] = 'wi'

    if region == "vt":
        prb_re = re.compile(r'violation of probation \d{2}\/\d{2}\/\d{2}')
        for row in cobvs.itervalues():
            if prb_re.match(key_as_str(str(row['cchglitx']).lower())):
                #sentence_records[row['id']]['delflag'] = 1
                sentence_records[row['id']]['delflag'] = 'vt'                

    if region == "ma":
        chgs = defaultdict(list)
        for row in aobvs.itervalues():
            chgs[row['achg']].append(row)
        for chg in chgs.keys():
            pd, sd = [], []
            if len(chgs[chg]) > 1:
                for row in chgs[chg]:
                    if row['arrname'].lower().find("pd") != -1: pd.append(row)
                    elif row['arrname'].lower().find("sd") != -1: sd.append(row)
                if len(pd) > 0 and len(sd) > 0:
                    for row in sd:
                        #arrest_records[row['id']]['delflag'] = 1
                        arrest_records[row['id']]['delflag'] = 'ma'

    if region == 'ny':
        sentences = defaultdict(list)
        for row in cobvs.itervalues():
            sentences['%s|%s|%s|%s' % (key_as_str(row['casenum']), key_as_str(row['cycnum']), key_as_str(row['cstatnumx']), key_as_str(row['cchglitx']))].append(row)
        cdisptextxes = set(['convicted upon plea of guilty',
                            'convicted upon verdict after bench trial',
                            'convicted upon verdict after jury trial',
                            'convicted upon verdict after trial',
                        ])
        for rows in sentences.itervalues():
            if len(rows) == 2:
                row1 = rows[0]
                row2 = rows[1]
                if any([key_as_str(row['cdisptextx']) in cdisptextxes and row['snttextx'] in {None, ''} for row in [row1, row2]]):
                    if any([row['snttextx'] not in {None, ''} and row['cdsp'] != 35 for row in [row1, row2]]):
                        cdsp1 = row1['cdsp']
                        cdsp2 = row2['cdsp']
                        sentence_records[row1['id']]['cdsp'] = cdsp2
                        sentence_records[row2['id']]['cdsp'] = cdsp1

    if region == 'nj':
        sentences = defaultdict(list)
        for row in cobvs.itervalues():
            sentences[row['%s|%s' % (key_as_str(row['cycnum']), key_as_str(row['cchglitx']))]].append(row)

        for rows in sentences.itervalues():
            if len(rows) > 1 and all([row['cdsp'] == 35 for row in rows]) and any([row['sntdatex'] not in {None, ''} for row in rows]):
                sentence_records[sorted(rows, key=lambda x: x['sntdatex'])[-1]['id']]['delflag'] = 'nj'




def pre_cycle(region, aobvs={}, arrest_records=None, cobvs={}, sentence_records=None, ma_set=set()):
    if region == "ct":
        flag_chgs = []
        for row in aobvs.itervalues(): 
            for chg in [490, 495, 500]:
                #TODO: add validation for dates; log all invalid dates
                if row['arryr'] != 9999 and row['offyr'] != 9999:
                    if row['achg'] == chg and datetime(row['offyr'],row['offmo'],row['offda']) > datetime(row['arryr'],row['arrmo'],row['arrda']):
                        #arrest_records[row['id']]['delflag'] = 1
                        arrest_records[row['id']]['delflag'] = 'ct'
                        flag_chgs.append(chg)
        chglits = defaultdict(list)
        for key, row in cobvs.iteritems():
            if row['cchg'] in flag_chgs:
                #sentence_records[row['id']]['delflag'] = 1
                sentence_records[row['id']]['delflag'] = 'ct'
            else:
                chglits[row['cchglitx']].append(row)
        for key in chglits.keys():
            if len(chglits[key]) > 1:
                try:
                    min_dt = min([datetime(row['sntyr'],row['sntmo'],row['sntda']) for row in chglits[key] if row['sntyr'] != 9999])
                except ValueError:
                    min_dt = None 
                for row in chglits[key]:
                    try:
                        if min_dt and min_dt != datetime(row['sntyr'], row['sntmo'], row['sntda']): 
                            #sentence_records[row['id']]['delflag'] = 1
                            sentence_records[row['id']]['delflag'] = 'ct'
                    except ValueError:
                        sentence_records[row['id']]['delflag'] = 'ct'
                        
    if region == "ky": #this is pre-cycle as per the implication in Candy's 11/28 email
        #"this rule should be applied before new cycles numbers are generated and combined"
        ori_test = [row for row in aobvs.itervalues() if len(row['aori'])>=9 and row['aori'][8].lower() == "g"]
        if len(ori_test) > 1:
            pvs = []
            non_pvs = []
            for row in aobvs.itervalues():
                if row['achg'] in [490, 495, 500]:
                    pvs.append(row)
                else: non_pvs.append(row)
                
            if len(pvs) > 0 and len(non_pvs) > 0:
                for row in non_pvs:
                    arrest_records[row['id']]['delflag'] = 1
                    arrest_records[row['id']]['delflag'] = 'ky'  
                
    
    if region == "md":
        for id in [row['id'] for row in cobvs.itervalues() if row['cchg'] in [490, 495, 500]]:
            cobvs[id]['delflag'] = 1
            cobvs[id]['delflag'] = 'md'
        arrests = [row['id'] for row in aobvs.itervalues() if row['achg'] == 999 and not row['achglit']]
        if len(arrests) > 0:
            min_score, charge = 99999, -9
            for cchg in [row['cchg'] for row in cobvs.itervalues() if row['cchg'] not in [490, 495, 500]]:
                score = chgseq.chg_score(cchg)
                if score < min_score: 
                    min_score, charge = score, cchg
                    #print "score: " + str(min_score) + ", charge: " + str(charge)
            if charge != -9:
                for id in arrests:
                    arrest_records[id]['achg'] = charge

    if region == "ma":
        for row in aobvs.itervalues():
            ma_tuple = (key_as_str(row['casenum']), key_as_str(row['achglit']), key_as_str(row['arrdatex']), key_as_str(row['arrnamex']))
            if ma_tuple in ma_set:
                arrest_records[row['id']]['delflag'] = 'ma pre-cycle'
            else:
                ma_set.add(ma_tuple)
    
                         
"""                                                
def transform(aobvs, cobvs, region):
#obvs = dictionary of id/row pairs e.g. {ID1: {row vars}, ID2: {row vars}}   
                    
    if region == "ia":
        parole = 0
        non_parole = 0
        match = 0
        flag_rows = []
        for key, row in cobvs.iteritems(): 
            if row['cchg'] in [500, 495, 490]: 
                parole += 1
                flag_rows.append(row)
                #check arrest segment for match, if so, match+=1 
            else: non_parole += 1
        for row in flag_rows:
            if parole > 0 and non_parole > 0 and match == 0 and #date condition
    
    if region == "md":
        for key, row in cobvs.iteritems():
            if row['cchg'] in [490, 495, 500]:
                sentence_records[row['id']]['delflag'] = 1
                
    if region == "nb":
        flag_date = []
        cchgs = [(row['cchg'],datetime(row['sntyr'],row['sntmo'],row['sntda']),row['id']) for row in cobvs.values()]
        maxdate = max([datetime(row['sntyr'],row['sntmo'],row['sntda']) for row in cobvs.values() if row['cchg'] not in [490, 495, 500]])
        for cchg in cchgs: 
            if cchg[0] in [490, 495, 500] and cchg[1] > maxdate: 
                cobvs[cchg[2]]['delflag'] = 1

    if region == "nc":
        flag_date = []
        cchgs = [(row['cchg'],datetime(row['sntyr'],row['sntmo'],row['sntda']),row['id']) for row in cobvs.values()]
        maxdate = max([datetime(row['sntyr'],row['sntmo'],row['sntda']) for row in cobvs.values() if row['cchg'] not in [490, 495, 500]])
        check_arr = [row for row in aobvs.values() if row['cchg'] in [490, 495, 500]]
        for cchg in cchgs: 
            if cchg[0] in [490, 495, 500] and cchg[1] > maxdate and len(check_arr) == 0: 
                cobvs[cchg[2]]['delflag'] = 1
 """                                   