from allensdk.api.queries.brain_observatory_api import BrainObservatoryApi
from allensdk.api.cache import cacheable
from allensdk.core.brain_observatory_cache import BrainObservatoryCache
import allensdk.internal.core.lims_utilities as lu
import os
import collections
import pandas as pd
import sys

sql_query_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'pre_release_sql')

with open(os.path.join(sql_query_dir, 'experiment_pre_release_query.sql'), 'r') as f:
    experiment_pre_release_query = f.read()

with open(os.path.join(sql_query_dir, 'container_pre_release_query.sql'), 'r') as f:
    container_pre_release_query = f.read()

with open(os.path.join(sql_query_dir, 'cell_specimens_pre_release_query.sql'), 'r') as f:
    cell_specimens_pre_release_query = f.read()

class BrainObservatoryApiPreRelease(BrainObservatoryApi):

    @cacheable()
    def get_experiment_containers(self):

        query_result = lu.query(container_pre_release_query)
        container_list = []
        for q in query_result:
            
            # # For development: print key/val pairs generated from LIMS query:
            # for key, val in sorted(q.items(), key=lambda x: x[0]):
            #     print key, val
            # raise

            c = collections.defaultdict(collections.defaultdict)

            c['id'] = q['ec_id']
            c['targeted_structure']['acronym'] = q['acronym']
            c['specimen']['donor'] = collections.defaultdict(collections.defaultdict)
            c['specimen']['donor']['external_donor_name'] = q['external_donor_name']
            c['specimen']['donor']['transgenic_lines'] = [collections.defaultdict(collections.defaultdict), collections.defaultdict(collections.defaultdict)]
            c['specimen']['donor']['transgenic_lines'][0]['transgenic_line_type_name'] = 'driver'
            c['specimen']['donor']['transgenic_lines'][0]['name'] = q['driver']
            c['specimen']['donor']['transgenic_lines'][1]['transgenic_line_type_name'] = 'reporter'
            c['specimen']['donor']['transgenic_lines'][1]['name'] = q['reporter']
            c['specimen']['name'] = q['specimen']
            c['imaging_depth'] = q['depth']
            c['failed'] = q['oa_state'] == 'failed'


            if q['donor_tags'] == u'Epileptiform Events':
                c['specimen']['donor']['conditions'] = [collections.defaultdict(collections.defaultdict)]
                c['specimen']['donor']['conditions'][0]['name'] = u'Epileptiform Events'
            elif q['donor_tags'] == u'':
                pass
            else:
                raise

            container_list.append(c)
        return container_list


    @cacheable()
    def get_ophys_experiments(self):

        query_result = lu.query(experiment_pre_release_query)
        experiment_list = []
        for q in query_result:
            c = collections.defaultdict(collections.defaultdict)

            # # For development: print key/val pairs generated from LIMS query:
            # for key, val in sorted(q.items(), key=lambda x: x[0]):
            #     print key, val
            # raise

            c['id'] = q['o_id']
            c['imaging_depth'] = q['depth']
            c['targeted_structure']['acronym'] = q['acronym']
            c['specimen']['donor'] = collections.defaultdict(collections.defaultdict)
            c['specimen']['donor']['external_donor_name'] = q['acronym']
            c['specimen']['donor']['transgenic_lines'] = [collections.defaultdict(collections.defaultdict), collections.defaultdict(collections.defaultdict)]
            c['specimen']['donor']['transgenic_lines'][0]['transgenic_line_type_name'] = 'driver'
            c['specimen']['donor']['transgenic_lines'][0]['name'] = q['driver']
            c['specimen']['donor']['transgenic_lines'][1]['transgenic_line_type_name'] = 'reporter'
            c['specimen']['donor']['transgenic_lines'][1]['name'] = q['reporter']
            c['date_of_acquisition'] = q['date_of_acquisition']
            c['specimen']['donor']['date_of_birth'] = q['date_of_birth']
            c['experiment_container_id'] = q['ec_id']
            c['stimulus_name'] = q['stimulus_name']
            c['specimen']['donor']['external_donor_name'] = q['external_donor_name']
            c['specimen']['name'] = q['specimen']
            c['fail_eye_tracking'] = q['fail_eye_tracking']

            experiment_list.append(c)
        return experiment_list

    @cacheable()
    def get_cell_metrics(self):
        query_result = lu.query(cell_specimens_pre_release_query)

        mappings = self.get_stimulus_mappings()
        thumbnails = [m['item'] for m in mappings if m['item_type'] == 'T' and m['level'] == 'R']

        cell_list = []
        for q in query_result:
            c = collections.defaultdict(collections.defaultdict)

            c['all_stim'] = q['a_valid'] and q['b_valid'] and q['c_valid']
            for key in ['cell_specimen_id', 'area', 'donor_full_genotype', 'experiment_container_id', 'imaging_depth', 'specimen_id', 'tld1_id',
                        'tld1_name', 'tld2_id', 'tld2_name', 'tlr1_id', 'tlr1_name']:
                c[key] = q[key]

            if q['failed_experiment_container'] == 't':
                c['failed_experiment_container'] = True
            elif q['failed_experiment_container'] == 'f':
                c['failed_experiment_container'] = False
            else:
                raise RuntimeError('Unexpected value: {} not in ("t", "f")'.format(q['failed_experiment_container']))
            

            # Session A metrics:
            for key in ['dsi_dg', 'g_dsi_dg', 'g_osi_dg', 'osi_dg', 'p_dg', 'p_run_mod_dg', 'peak_dff_dg', 'pref_dir_dg', 'pref_tf_dg', 'reliability_dg',
                        'reliability_nm3', 'run_mod_dg', 'tfdi_dg', 'tfdi_dg']:
                if q['crara_data'] is None:
                    c[key] = None
                else:
                    c[key] = q['crara_data']['roi_cell_metrics'].get(key,None)

            # Session B metrics:
            for key in ['g_osi_sg', 'image_sel_ns', 'osi_sg', 'p_ns', 'p_run_mod_ns', 'p_run_mod_sg', 'p_sg', 'peak_dff_ns', 'peak_dff_sg', 'pref_image_ns',
                        'pref_ori_sg', 'pref_phase_sg', 'pref_sf_sg', 'pref_image_ns', 'pref_ori_sg', 'reliability_ns', 'reliability_sg',
                        'run_mod_ns','run_mod_sg','sfdi_sg', 'time_to_peak_ns', 'time_to_peak_sg']:
                
                if q['crarb_data'] is None:
                    c[key] = None
                else:
                    c[key] = q['crarb_data']['roi_cell_metrics'].get(key,None)

            # Session C metrics:
            for key in ['reliability_nm2', 'rf_area_off_lsn', 'rf_area_on_lsn', 'rf_center_off_x_lsn', 'rf_center_off_y_lsn',
                        'rf_center_on_x_lsn', 'rf_center_on_y_lsn', 'rf_chi2_lsn', 'rf_distance_lsn', 'rf_overlap_index_lsn',
                        ]:
                if q['crarc_data'] is None:
                    c[key] = None
                else:
                    c[key] = q['crarc_data']['roi_cell_metrics'].get(key,None)
            
            for suffix in ['a', 'b', 'c']:
                if not q['crar%s_data' % suffix] is None:
                    c['reliability_nm1_%s' % suffix] = q['crar%s_data' % suffix]['roi_cell_metrics'].get('reliability_nm1',None)
                else:
                    c['reliability_nm1_%s' % suffix] = None
            
            # Fake in thumbnail images:
            for t in thumbnails:
                c[t] = None

            # # For development: print key/val pairs generated from LIMS query:
            # for key, val in sorted(q.items(), key=lambda x: x[0]):
            #     if key == 'crarb_data':
            #         print 'crarb_data[roi_cell_metrics]'
            #         for key2, val2 in sorted(val['roi_cell_metrics'].items(), key=lambda x: x[0]):
            #             print '    ', key2, val2
            #     else:
            #         print key, val
            # raise

            cell_list.append(c)

        return cell_list