import re
from itertools import izip
from errors import *
from util import *
from cardsharp.errors import RuleError as CSRuleError

def _code_unknown(ruleset, row, unknown):
    for v in ruleset.vars:
        #do not code variables listed in skip unknown
        if v[0] not in ruleset.skip_unknown:
            #only overwrite if variable name is in overwrite rule
            if v[0] not in ruleset.overwrite and row[v[0]] is not None:
                continue
            
            if v[0] == 'cdsp':
                row['cdsp'] == 99
            else:
                row[v[0]] = unknown[v[0]]

class SentenceRules(object):
    def __init__(self, log):
        self.log = log
        self.unknown = {'cnf' : 9, 'trt' : 9, 'cmsrv' : 9999.99, 'oth' : None, 'pjp':99}
        self.na = {'cnf' : 8}
        
        for var in ('incmax', 'incmin', 'suspmax', 'suspmin', 'prb', 'fineamt', 'suspfine', 'rst', 'costs'):
            self.unknown[var] = 99999999.99
            if var in ('incmax', 'incmin', 'suspmax', 'suspmin', 'prb'):
                self.na[var] = 99899899.88
        
        
        self.missing = self.unknown
                
    def convert_sentences(self, row, ruleset, **kw):
        #TODO break this into many different functions tom improve performance?
        '''Tries to convert sentences by finding key in ruleset. If key not found then codes unknown.
        
        @param row: The row to assign values to
        @param ruleset: The ruleset which stores the key, value rule mappings to convert a given key into sentence variables    
        @param skip_unknown: A list of variables which should not be coded during unknown coding.
        @return: Returns the key that was passed in on key param. If remove_key is true will remove the key that was matched on from the string
        
        ''' 
        remove_key = ruleset.remove_key
        
        #TODO need to make this work if we have multiple key values
        #allows convert_key to be passed in 
        _row = {ruleset.metadata.key_meta[0].name:kw.get('convert_key')} if kw.get('convert_key') is not None else row
        key = ruleset.metadata.get_key(_row)
        convert_key = '|'.join([k if k else '' for k in key])

		#if null_predicate defined check to make sure all null_predicate variables are None
        if len(ruleset.null_predicate) != 0:
            for v in ruleset.null_predicate:
                if row[v] is not None:
                    if ruleset.metadata.force_unknown:
                        _code_unknown(ruleset, row, self.unknown)
                    return None
                
        
        #if overwrite not set then check to make sure at least one null value before running crosswalk
        if len(ruleset.overwrite) == 0:
            for v in ruleset.null_predicate:
                if row[v] is None:
                    break
                return None
            # else, if all the variables are already coded, return. This is needed incase a null predicate
            # is not set.
            else:
                if all([row[var[0]] is not None for var in ruleset.vars]):
                    return None
        
        try:
            #if key_predicate text is not in key code as unknown
            if ruleset.key_predicate:
                if not ruleset.key_predicate.search(convert_key): 
                    _code_unknown(ruleset, row, self.unknown)
                    return convert_key
            
            #construct the keyword arguments
            kw_args = {'remove':remove_key, 
                       'transform_results':ruleset.transform_results}
             
            #if more than one vars than we split
            if ruleset.vars > 1:
                kw_args['split'] = '|'
                
            #if transform_results is True than pass in the row and ruleset.varaible data to the convert method
            if ruleset.transform_results:
                kw_args['row'] = row

            if 'audit' in kw:
                kw_args['audit'] = kw['audit']
                kw_args['case_id'] = kw.get('case_id', 0)
            
            #try to match a rule in the ruleset to convert_key
            result = ruleset.convert(convert_key, **kw_args)
            
            if isinstance(result, tuple):
                snt_vars, key_str = result
                convert_key = key_as_str(convert_key.replace(key_str, ''))
            else:
                #make sure snt_vars is a list
                snt_vars = result if ruleset.vars > 1 else [result]
                    
            for k,v in izip(ruleset.vars, snt_vars):
                #only overwrite if overwrite is set to True
                if k[0] not in ruleset.overwrite and row[k[0]] is not None:
                    continue
                
                try:
                    row[k[0]] = v 
                except CSRuleError as e:
                    #if a rule error occurs
                    row[k[0]] = -9
                    self.log.write('snttext_errors', [row['id'], row['rapstatex'], convert_key, e])
        
        #all rules in ruleset do not find a match on convert_key, code as unknown
        except ConvertError as e:
            _code_unknown(ruleset, row, self.unknown)
                
            if ruleset.key_predicate:
                self.log.write('snttext', [row['id'], row['rapstatex'], convert_key, 
                                           "convert_key not found in xwalk, but convert_key had key_predicate: %s." % ruleset.key_predicate.pattern])
        except RuleError as e:
              self.log.write('snttext_rule_errors', [row['id'], row['rapstatex'], e])
        
        return convert_key
    
    def recode_inc(self, row):
        if row['incmax'] != 99999999.99 and row['incmin'] == 99999999.99:
            row['incmin'] == 99899899.88 
        
        elif row['incmin'] != 99999999.99 and row['incmax'] == 99999999.99:
            row['incmax'] == 99799799.77
        
        return
      