from subprocess import Popen, PIPE
from datetime import datetime
from traceback import format_exc, extract_stack, format_list
from contextlib import closing 
import os
import cPickle

from ..predict import *
from ..configuration import config
from ..log import Log
from ..util import RUNDATETIME, get_hash, get_state_name

from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.linear_model import SGDClassifier
from sklearn.pipeline import Pipeline
from sklearn import svm


def run(**opt):
    opt['log'] = Log(time=datetime.now().isoformat('_').replace(':', '-'), 
                      segment='predict', var='predict', phase=6, log_dir=opt['log_dir'])
    try:
        if opt['phase'] == 'preprocess':
            opt['log'] = Log(time=datetime.now().isoformat('_').replace(':', '-'), 
                      segment='predict', var='predict', phase=6, log_dir=opt['log_dir'])
            pre_process(**opt)
            print "Training and test data created @ %s." % datetime.now().isoformat(' ')
        
        elif opt['phase'] == 'train':
            clf = {
            'sgd': SGDClassifier(penalty='elasticnet', 
                                     #loss='modified_huber',
                                     alpha=0.0001,
                                     l1_ratio=.9),
            'svc': svm.SVC(C=10, kernel='linear'),
            'linear_svc': svm.LinearSVC(C=10),
            }
            
            """Set the pipeline vectorizer and vecotrizer parameters to optimize""" 
            vect_params, vect_args = {}, {}
            for name, info in opt['vect_opt'].iteritems(): 
                if info[1]: vect_params[name] = info[0] #vect parameters
                else: vect_args[name] = info[0] #vect arguements
            
            params = {
            'svc':{
                # uncommenting more parameters will give better exploring power but will
                # increase processing time in a combinatorial way
                'tfidf__use_idf': (True, False),
                #'tfidf__norm': ('l1', 'l2'),
                #'clf__C': (1,10),
                #'clf__kernel': ('linear', 'rbf'),
                #'clf__class_weight': ('auto', None),
            },
            'linear_svc':{
                # uncommenting more parameters will give better exploring power but will
                # increase processing time in a combinatorial way
                'tfidf__use_idf': (True, False),
                #'tfidf__norm': ('l1', 'l2'),
                #'clf__C': (1,10),
                #'clf__kernel': ('linear', 'rbf'),
                #'clf__class_weight': ('auto', None),
            },
            'sgd': {
                # uncommenting more parameters will give better exploring power but will
                # increase processing time in a combinatorial way
                'tfidf__use_idf': (True, False),
                'tfidf__norm': ('l1', 'l2'),
                'clf__loss': ('hinge', 'log', 'modified_huber'),
                #'clf__alpha': (0.0001, 0.00001),
                #'clf__l1_ratio': [.1, .5, .9, .99], 
                'clf__n_iter': (5, 50),
            }
            }
            params[opt['clf']].update(dict([('vect__%s' % k, v) for k,v in vect_params.iteritems()]))
            vect = {'count_vect': CountVectorizer(**vect_args)}
            
            _tmp_path = os.path.join(config.tmp_out_dir, 'predict')
            if not os.path.exists(_tmp_path):
                os.makedirs(_tmp_path)
            p_opt = {'pipeline': Pipeline([('vect', vect[opt['vect_type']]),
                                         ('tfidf', TfidfTransformer(norm='l2')),
                                         ('clf', clf[opt['clf']]),]),
                     'parameters' : params[opt['clf']],
                     'variable': opt['var'],
                     'region': opt['region'],
                     'rule_dir': opt['rule_dir'],
                     'cv__n_folds': opt['cv__n_folds'],
                     'clf': opt['clf'],
                     'report_dir': config.report_dir
               }
            
           
            p_opt_hash = get_hash('|'.join(["%s_%s" % (str(k), str(v)) for k, v in p_opt.iteritems()]))
            
            _out_path = os.path.join(p_opt['report_dir'], 'predict', p_opt['region'], p_opt['variable'], p_opt_hash)        
            if os.path.exists(_out_path): print "Results already computed: %s" % _out_path
            else:
                p_opt['out_path'] = _out_path
                p_opt['hash'] = p_opt_hash
                
                with closing(open(os.path.join(_tmp_path, 'options.pkl'), 'wb')) as file:
                    cPickle.dump(p_opt, file)
                
                path = os.path.join(__file__, '..', '..', 'predict', 'train.py')
                p1 = Popen(['python', path], stdout=PIPE)
                #TODO figure out why below is not printing the PIPED data
                print p1.communicate()[0]
        
        elif opt['phase'] == 'classify':
            opt['log'] = Log(time=datetime.now().isoformat('_').replace(':', '-'),
                      segment='predict', var='classify', phase=6, log_dir=opt['log_dir'])
            #create preprocessor and extract / preprocess data
            if opt['region'] == 'fed':
                opt['arrest_where'] = "a.afed = 1 and rapstatex='WVFBI' and a.achg=-999"
                opt['sentence_where'] = "c.cfed = 1 and rapstatex='WVFBI' and c.cchg=-999"
            elif opt['region'] == 'wvfbi':
                opt['arrest_where'] = "rapstatex='WVFBI' and a.achg=-999"
                opt['sentence_where'] = "rapstatex='WVFBI' and c.cchg=-999"
            else:
                opt['arrest_where'] = "rapstatex != 'WVFBI' and a.achg is null and a.astate=%s" % get_state_name(opt['region'])
                opt['sentence_where'] = "rapstatex != 'WVFBI' and c.cchg is null and c.cstate=%s" % get_state_name(opt['region'])

            pp = PreProcesserClassify(**opt)
            for file, region, wvfbi, mtime in pp.get_paths():
                with closing(open(file, 'rb')) as crosswalk:
                    #extract the crosswalk data
                    segment = 'arrest' if 'ancic' in file else 'sentence'
                    pp.extract_rules(crosswalk, file, region, wvfbi, segment, 'rel2005_prs')

            #pp.extract_db(opt.get('project'))
            print 'Preprocessing complete'

            opt['pre_processor'] = pp
            opt['pipeline_import_dir'] = r'P:\7685\CHRARP\project_data\business rules\2005 rerun\rules\predict\data\%s' % opt['region']

            print 'Applying predictions'
            classify(**opt)

        elif opt['phase'] == 'report':
            report(**opt)
            
        return 1
    except:
        if opt['verbose']:
            raise
        return (format_exc(), format_list(extract_stack())) 
    
    
    
            
