#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import math
import sqlalchemy as sqla # Import knihovny sqlalchemy - pro komunikaci s mysql serverem
import pandas as pd # Knihovna pro operaace s dataframama (tabulkama)
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

#from functools32 import lru_cache

""" -------------------------------------------------------------------------------------
POPIS:
Tento skript obsahuje funkce potřebné pro výpočet ROC:

get_reviewed_data(patient_id) - připojení do databáze, vrací dataFrame s označenými lékařsky hodnotami
get_data(database, seeg, patient_id, columns = '*') - připojení do databáze, získávání soz_info z lékařsky označených kanálů, získání dat na základě zvolené databáze a čísla pacienta, agregace dat
parse_hfo_events(dataframe) - původní verze pro zjištění počtu detekcí HFO v jednotlivých kanálech, již nepoužívat, je zabudovaná ve starých skriptech  (nyní count_hfo_events), výstupem:
        'channel_names': channel_names, # vrátí výsledek v jenom sloupci
        'channels_count': channels_count,
        'SOZ': SOZ,
        'IZ': IZ,
        'NON_SOZ': NON_SOZ
count_hfo_events(dataframe) - nová verze pro zjištění počtu detekcí HFO v jednotlivých kanálech, vrací výsledek v dataFramu count_df
print_subplot_sum_hfo(patients, patient_id, hfo_events) - funkce pro vykreslování počtů detekcí pro SOZ, NON_SOZ a IZ
determine_graph_sizes(patients_count) - určení počtu subplotů pro vykreslování výsledků
------------------------------------------------------------------------------------- """
def square(x):
    square = x * x
    return (square)

def get_reviewed_data(patient_id):
    """
    Tato funkce ... 
    :param patient_id:    číslo 2 až ..33, pacienti 34, 36 a dál již nemají kanály označeny
    :return:
    """

    #připojení do databáze - přihlašovací údaje jsou úmyslně vymazány
    db_remote = {'user': '', 'pwd': '', 'host': '', 'port': '', 'database': ''}
    db = db_remote
    engine = sqla.create_engine('mysql+pymysql://{}:{}@{}:{}/{}'.format(db['user'],db['pwd'],db['host'],db['port'],db['database']))
    conn = engine.connect()

    #print('good')

    if patient_id / 10 == 0:
        id = '00'
    elif patient_id / 100 == 0:
        id = '0'
    else:
        id = ''

    seeg=patient_id

    print('Getting channels and onset_channel from seeg={}'.format(seeg))
    query = 'SELECT seeg, channel_name, onset_channel FROM reviewed_events.seizures WHERE seeg='+str(seeg)+' '
    res = conn.execute(query)
    id += str(patient_id) # volba pacienta ve formátu 01 až 49


    print('Getting data')
    ll_df = pd.read_sql(query,conn) # Vytvori dataframe s vysledky sql prikazu

    conn.close()

    return ll_df


def get_reviewed_data_resected(patient_id):
    """
    Tato funkce ... 
    :param patient_id:    číslo 2 až ..33, pacienti 34, 36 a dál již nemají kanály označeny
    :return:
    """

    #připojení do databáze
    db_remote = {'user': '', 'pwd': '', 'host': '', 'port': '', 'database': ''}
    db = db_remote
    engine = sqla.create_engine('mysql+pymysql://{}:{}@{}:{}/{}'.format(db['user'],db['pwd'],db['host'],db['port'],db['database']))
    conn = engine.connect()


    if patient_id / 10 == 0:
        id = '00'
    elif patient_id / 100 == 0:
        id = '0'
    else:
        id = ''

    seeg=patient_id

    print('Getting channels and onset_channel from seeg={}'.format(seeg))
    query = 'SELECT seeg, channel_name, resection_image FROM patientInfo.channel_map WHERE seeg='+str(seeg)+' ' #SELECT seeg, channel_name, resection_image FROM patientInfo.channel_map WHERE seeg=7
    res = conn.execute(query)
    id += str(patient_id) # volba pacienta ve formátu 01 až 49

    print('Getting data')
    ll_df = pd.read_sql(query,conn) # Vytvori dataframe s vysledky sql prikazu

    conn.close()

    return ll_df


def get_data_smazat_bez_resected(database, seeg, patient_id, columns = '*'): #table_name_prefix

    """
    :param database:            'LL_alg_Fnusa'
    :param table_name_prefix:   'fnusa_'
    :param patient_id:          49
    :param columns:             '*' nebo 'event_start, event_stop, channel_name'
    :return:
    """

    #--- připojení do databáze
    db_remote = {'user': '', 'pwd': '', 'host': '', 'port': '', 'database': ''}
    db = db_remote
    engine = sqla.create_engine('mysql+pymysql://{}:{}@{}:{}/{}'.format(db['user'],db['pwd'],db['host'],db['port'],db['database']))
    conn = engine.connect()

    #--- získávání soz_info z lékařsky označených kanálů
    print('Getting IZ_channels from seeg={}'.format(seeg))
    query = 'SELECT channel_name FROM reviewed_events.seizures WHERE seeg='+str(seeg)+' AND onset_channel="IrritativeZone"'
    res = conn.execute(query)
    IZ_channels = [x[0] for x in res.fetchall()] # Seznam kanalu, ktere byly oznaceny jako IZ

    print('Getting SOZ_channels from seeg={}'.format(seeg))
    query = 'SELECT channel_name FROM reviewed_events.seizures WHERE seeg='+str(seeg)+' AND onset_channel="SOZ"'
    res = conn.execute(query)

    SOZ_channels = [x[0] for x in res.fetchall()] # Seznam kanalu, ktere byly oznaceny jako SOZ

    # ----ošetření vstupu patient_id, vstup ve formátu 1 až 32
    if patient_id / 10 == 0:
        id = '00'
    elif patient_id / 100 == 0:
        id = '0'
    else:
        id = ''

    id += str(patient_id)

    # ---vytazeni relax souboru
    query = "SELECT file_name FROM patientInfo.file_map WHERE seeg="+id+" AND file_content=1 LIMIT 1"
    res = conn.execute(query)
    file_name = res.fetchall()[0][0]

    # ---vytažení dat na základě zvolené databáze a čísla pacienta
    if database == 'hilbert_alg_v2':
        table_name_prefix = 'fnusa_'
        query = 'SELECT {} FROM {}.{}{}_hfo WHERE data_source="{}"'.format(columns, database, table_name_prefix, id, file_name)

    elif database == 'Matt_alg_Fnusa':
        table_name_prefix = 'fnusa_'
        query = 'SELECT {} FROM {}.{}{} WHERE algorithm = "Matt_conglom" AND data_source="{}"'.format(columns, database, table_name_prefix, id, file_name)
        #SELECT * FROM Matt_alg_Fnusa.fnusa_002 WHERE algorithm = 'Matt_conglom';

    elif database == 'LL_alg_Fnusa':
        table_name_prefix = 'fnusa_'
        query = 'SELECT {} FROM {}.{}{} WHERE data_source="{}"'.format(columns, database, table_name_prefix, id, file_name)

    #--- vytvoření dataframe s vysledky sql prikazu
    print('Working on getting the data with "{}"'.format(query))
    ll_df = pd.read_sql(query,conn)

    #--- Vytvoreni noveho sloupecku v dataframu a oznaceni defaultni hodnoty jako NON_SOZ (nepatologicke)
    ll_df['soz_info'] = 'NON_SOZ'

    #--- výpis seznamu kanalu v ll_df dataframu
    channels = ll_df.channel_name.unique()

    #--- vsechny zaznamy v ll_df, ktere maji kanal v IZ seznamu jsou oznaceny jako IZ
    print('Marking IZ & SOZ channels')
    for channel in channels:
        if channel in IZ_channels:
            ll_df.loc[(ll_df.channel_name == channel), 'soz_info'] = 'IZ'
        if channel in SOZ_channels:
            ll_df.loc[(ll_df.channel_name == channel), 'soz_info'] = 'SOZ'

    print('IZ & SOZ channels have been marked')
    conn.close()

    #--- výstupem DataFrame s agregovanými daty
    return ll_df


def get_data(database, seeg, patient_id, columns = '*'): #table_name_prefix

    """
    :param database:            'LL_alg_Fnusa'
    :param table_name_prefix:   'fnusa_'
    :param patient_id:          49
    :param columns:             '*' nebo 'event_start, event_stop, channel_name'
    :return:
    """

    #--- připojení do databáze
    db_remote = {'user': '', 'pwd': '', 'host': '', 'port': '', 'database': ''}
    db = db_remote
    engine = sqla.create_engine('mysql+pymysql://{}:{}@{}:{}/{}'.format(db['user'],db['pwd'],db['host'],db['port'],db['database']))
    conn = engine.connect()

    #--- získávání soz_info z lékařsky označených kanálů

    print('Getting IZ_channels from seeg={}'.format(seeg))
    query = 'SELECT channel_name FROM reviewed_events.seizures WHERE seeg='+str(seeg)+' AND onset_channel="IrritativeZone"'
    res = conn.execute(query)
    IZ_channels = [x[0] for x in res.fetchall()] # Seznam kanalu, ktere byly oznaceny jako IZ

    print('Getting SOZ_channels from seeg={}'.format(seeg))
    query = 'SELECT channel_name FROM reviewed_events.seizures WHERE seeg='+str(seeg)+' AND onset_channel="SOZ"'
    res = conn.execute(query)

    SOZ_channels = [x[0] for x in res.fetchall()] # Seznam kanalu, ktere byly oznaceny jako SOZ

    # ----ošetření vstupu patient_id, vstup ve formátu 1 až 32
    if patient_id / 10 == 0:
        id = '00'
    elif patient_id / 100 == 0:
        id = '0'
    else:
        id = ''

    id += str(patient_id)

    # ---vytazeni relax souboru
    query = "SELECT file_name FROM patientInfo.file_map WHERE seeg="+id+" AND file_content=1 LIMIT 1"
    res = conn.execute(query)
    file_name = res.fetchall()[0][0]

    # ---vytažení dat na základě zvolené databáze a čísla pacienta
    if database == 'hilbert_alg_v2':
        table_name_prefix = 'fnusa_'
        query = 'SELECT {} FROM {}.{}{}_hfo WHERE data_source="{}" order by channel_name'.format(columns, database, table_name_prefix, id, file_name)

    elif database == 'Matt_alg_Fnusa':
        table_name_prefix = 'fnusa_'
        query = 'SELECT {} FROM {}.{}{} WHERE algorithm = "Matt_conglom" AND data_source="{}" order by channel_name'.format(columns, database, table_name_prefix, id, file_name)
        #SELECT * FROM Matt_alg_Fnusa.fnusa_002 WHERE algorithm = 'Matt_conglom';

    elif database == 'LL_alg_Fnusa':
        table_name_prefix = 'fnusa_'
        query = 'SELECT {} FROM {}.{}{} WHERE data_source="{}" order by channel_name'.format(columns, database, table_name_prefix, id, file_name)

    #--- vytvoření dataframe s vysledky sql prikazu
    print('Working on getting the data with "{}"'.format(query))
    ll_df = pd.read_sql(query,conn)

    #--- Vytvoreni noveho sloupecku v dataframu a oznaceni defaultni hodnoty jako NON_SOZ (nepatologicke)
    ll_df['soz_info'] = 'NON_SOZ'



    #--- výpis seznamu kanalu v ll_df dataframu
    channels = ll_df.channel_name.unique()

    #--- vsechny zaznamy v ll_df, ktere maji kanal v IZ seznamu jsou oznaceny jako IZ
    print('Marking IZ & SOZ channels')
    for channel in channels:
        if channel in IZ_channels:
            ll_df.loc[(ll_df.channel_name == channel), 'soz_info'] = 'IZ'
        if channel in SOZ_channels:
            ll_df.loc[(ll_df.channel_name == channel), 'soz_info'] = 'SOZ'

    print('IZ & SOZ channels have been marked')

    # ----resected
    #ll_df['resected'] = 0
    print('Adding resection info')
    ll_df['resection'] = 'non_resected'

    # for seeg in seegs:
    # sub_events = ll_df[(ll_df.seeg == seeg)]

    channels = ll_df.channel_name.unique()

    query = 'SELECT channel_name FROM patientInfo.channel_map WHERE seeg=' + str(seeg) + ' AND resection_image=1'
    res = conn.execute(query)
    res_channels = [x[0] for x in res.fetchall()]

    for channel in channels:
        if channel in res_channels:
            ll_df.loc[(ll_df.channel_name == channel), 'resection'] = 'resected'

    conn.close()

    #--- výstupem DataFrame s agregovanými daty
    return ll_df

def parse_hfo_events(dataframe):
    """
    #původní verze sčítání HFO, již nepoužívat, jen je zabudovaná ve starých skriptech  (nyní count_hfo_events)
    :param dataframe:       objekt vraceny z funkce get_data
    :return:    funkce vrátí počet HFO events v jednotlivých kanálech, lze zobrazit při hfo_events= parse_hfo_events(ll_df) například příkazem  hfo_events['SOZ']

    """
    channel_names = set() # mnozina
    channels_count = -1

    # Initialize matrices
    SOZ = []
    NON_SOZ = []
    IZ = []

    count_df = pd.DataFrame(columns=("channel_name","SOZ_count","IZ_count","NON_SOZ_count"))

    channel_names = list(dataframe.channel_name.unique())
    channel_count = dataframe.channel_name.count()

    for channel in channel_names:
        soz_info = dataframe[dataframe.channel_name == channel].soz_info.unique()
        if len(soz_info) > 1:
            print("Warning - more than one soz info")
            return

        if soz_info == "SOZ":
            SOZ.append(len(dataframe[dataframe.channel_name == channel]))
            IZ.append(0)
            NON_SOZ.append(0)
        elif soz_info == "IZ":
            IZ.append(len(dataframe[dataframe.channel_name == channel]))
            SOZ.append(0)
            NON_SOZ.append(0)
        else:
            NON_SOZ.append(len(dataframe[dataframe.channel_name == channel]))
            SOZ.append(0)
            IZ.append(0)


    print('Aggregating channels with respect to SOZ, NON_SOZ & IZ')

    return {
        'channel_names': channel_names, # vrátí výsledek v jenom sloupci
        'channels_count': channels_count,
        'SOZ': SOZ,
        'IZ': IZ,
        'NON_SOZ': NON_SOZ
    }


def count_hfo_events(dataframe):
    """

    :param dataframe:       objekt vraceny z funkce get_data
    :return:    funkce vrátí počet HFO events v jednotlivých kanálech, lze zobrazit při hfo_events= parse_hfo_events(ll_df) například příkazem  hfo_events['SOZ']

    """
    channel_names = set() # mnozina
    channels_count = -1

    # Initialize matrices
    SOZ = []
    NON_SOZ = []
    IZ = []
    resected = []

    count_df = pd.DataFrame(columns=("channel_name","SOZ_count","IZ_count","NON_SOZ_count"))

    channel_names = list(dataframe.channel_name.unique())
    channel_count = dataframe.channel_name.count()

    #resected_cnt = len(dataframe.loc[dataframe['resection'] == 'resected'])

    i=0


    for channel in channel_names:
        soz_info = dataframe[dataframe.channel_name == channel].soz_info.unique()

        if len(soz_info) > 1:
            print("Warning - more than one soz info")
            return

        if soz_info == "SOZ":
            SOZ_cnt = len(dataframe[dataframe.channel_name == channel])
            IZ_cnt = 0
            NON_SOZ_cnt = 0

        elif soz_info == "IZ":
            SOZ_cnt = 0
            IZ_cnt = len(dataframe[dataframe.channel_name == channel])
            NON_SOZ_cnt = 0

        else:
            SOZ_cnt = 0
            IZ_cnt = 0
            NON_SOZ_cnt = len(dataframe[dataframe.channel_name == channel])
            #NON_SOZ.append(len(dataframe[dataframe.channel_name == channel]))
            #SOZ.append(0)
            #IZ.append(0)

        count_df.loc[i,:] = [channel,SOZ_cnt,IZ_cnt,NON_SOZ_cnt]
        i += 1


    print('Aggregating channels with respect to SOZ, NON_SOZ & IZ')
    # ---------- prohledání výsledků řádek po řádku ----------

    return count_df #vrátí výsledek v dataframu




#
#
def count_hfo_events_resected(dataframe):
    #---vstupem ll_df z get_data

    count_resected=pd.DataFrame()
    #count_resected = dataframe.loc(['channel_name', 'soz_info', 'resection'])
    count_resected['channel_name'] = dataframe['channel_name']
    count_resected['soz_info'] = dataframe['soz_info']
    count_resected['resection'] = dataframe['resection']

    count_resected.loc[count_resected['soz_info'] == 'NON_SOZ'] #--pro zajímavost
    count_resected.loc[count_resected['soz_info'] == 'SOZ'] #--pro zajímavost

    # for i in range(0,len(dataframe)):
    #      if count_resected.resection.loc[i]=='resected':
    #          count_resected.soz_info.loc[i] = 'SOZ'
    #      else:
    #          count_resected.soz_info.loc[i] = 'NON_SOZ'
    dataframe = dataframe.groupby(by=('channel_name', 'resection')).agg("count")

    count_resected=count_resected.groupby(by=('channel_name', 'resection')).agg("count")

    return count_resected

'''
    return {
        'channel_names': channel_names, # vrátí výsledek v jenom sloupci
        'channels_count': channels_count,
        'SOZ': SOZ,
        'IZ': IZ,
        'NON_SOZ': NON_SOZ
    }
'''

def print_subplot_sum_hfo(patients, patient_id, hfo_events):

    events_count = 1 # jedna se o sumu .. proto jedna
    index = np.arange(events_count)
    bar_width = 0.8
    opacity = 0.4

    SOZ_sum = sum(hfo_events['SOZ'])
    IZ_sum = sum(hfo_events['IZ'])
    NON_SOZ_sum = sum(hfo_events['NON_SOZ'])

    patient_rank = patients.index(patient_id) + 1

    lines, cols = determine_graph_sizes(len(patients))
    plt.subplot(lines, cols, patient_rank)

    xticks_columns = []

    if SOZ_sum != 0:
        xticks_columns.append('SOZ')
        rects1 = plt.bar(index, SOZ_sum, bar_width,
                     alpha=opacity,
                     color='b',
                     label='SOZ')

    if IZ_sum != 0:
        xticks_columns.append('IZ')
        rects2 = plt.bar(index + bar_width, IZ_sum, bar_width,
                     alpha=opacity,
                     color='y',
                     label='IZ')

    if NON_SOZ_sum != 0:
        xticks_columns.append('NON_SOZ')
        rects3 = plt.bar(index + 2 * bar_width, NON_SOZ_sum, bar_width,
                     alpha=opacity,
                     color='r',
                     label='NON_SOZ')

    plt.xlabel('Patient {}'.format(patient_id))
    plt.ylabel('Scores')

    # Zobraz jen ty, ktere jsou v xticks_columns
    # plt.xticks(np.arange(len(xticks_columns)), xticks_columns)

def determine_graph_sizes(patients_count):
    sqrt_count = patients_count ** (1.0 / 2)

    # predpoklad, ze se vzdy bude zobrazovat ctvercovy graf
    lines = math.ceil(sqrt_count) # math.ceil zaokrohluje nahoru, math.floor dolu

    return (lines)
