import sys
import os
import shutil
import functools
import logging
import pandas as pd
import numpy as np
import click
import time
import csv
from rumi.io import config
from rumi.io import loaders
from rumi.io import constant
from rumi.io import demand as demandio
from rumi.io import functionstore as fs
from rumi.io import common
from rumi.io import filemanager
from rumi.io.logger import init_logger, get_event
from rumi.processing import utilities
from rumi.io.utilities import groupby_time
import rumi.io.utilities as ioutils
from rumi.processing.utilities import get_geographic_columns_from_dataframe
from rumi.io.common import get_geographic_columns
from rumi.io.common import get_time_columns
from rumi.io.multiprocessutils import execute_in_process_pool
logger = logging.getLogger(__name__)

@demandio.save_output
def compute_demand(demand_sector, energy_service, energy_carrier):
    """Compute demand for given set of demand_sector, energy_service, energy_carrier.

    :param: demand_sector: str -> Demand sector name
    :param: energy_service: str -> Energy serive name
    :param: energy_carrier: str -> Energy carrier name
    :returns: computed demand as a DataFrame

    """
    logger.info(
        f"Computing demand for {demand_sector},{energy_service},{energy_carrier}")
    type_ = demandio.get_type(demand_sector, energy_service)
    if type_ == "EXTRANEOUS":
        r = compute_extraneous_demand(demand_sector,
                                      energy_service,
                                      energy_carrier)
    elif type_ == "BOTTOMUP":
        r = compute_bottomup_demand(demand_sector,
                                    energy_service,
                                    energy_carrier)
    elif type_ == "RESIDUAL":
        r = compute_residual_demand(demand_sector,
                                    energy_service,
                                    energy_carrier)
    else:
        r = compute_gdpelasticity_demand(demand_sector,
                                         energy_service,
                                         energy_carrier)
    r = utilities.seasonwise_timeslices(r, 'EnergyDemand')
    return ioutils.order_rows(r)

def get_consumer_granularity(demand_sector,
                             energy_service,
                             energy_carrier):
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")
    granularity_map = DS_ES_EC_DemandGranularity_Map.set_index(['DemandSector',
                                                                'EnergyService',
                                                                'EnergyCarrier'])
    return granularity_map.loc[(demand_sector,
                                energy_service,
                                energy_carrier)]['ConsumerGranularity']

def get_time_granularity(demand_sector,
                         energy_service,
                         energy_carrier):
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")
    granularity_map = DS_ES_EC_DemandGranularity_Map.set_index(['DemandSector',
                                                                'EnergyService',
                                                                'EnergyCarrier'])
    return granularity_map.loc[(demand_sector,
                                energy_service,
                                energy_carrier)]['TimeGranularity']

def get_cons_columns(demand_sector,
                     energy_service,
                     energy_carrier):
    consgran = get_consumer_granularity(demand_sector,
                                        energy_service,
                                        energy_carrier)
    if consgran == 'CONSUMERALL':
        return demandio.get_cons_columns(demand_sector)
    return constant.CONSUMER_COLUMNS[consgran]

def get_query(energy_service, energy_carrier):
    return f"(EnergyService == '{energy_service}') & (EnergyCarrier == '{energy_carrier}')"

def compute_extraneous_demand(demand_sector,
                              energy_service,
                              energy_carrier):
    balancing_area = demandio.balancing_area(energy_carrier)
    balancing_time = demandio.balancing_time(energy_carrier)
    consumer_cols = get_cons_columns(
        demand_sector, energy_service, energy_carrier)
    groupcols = consumer_cols + list(get_geographic_columns(balancing_area))
    df = loaders.get_parameter("ExtraneousDemand", demand_sector=demand_sector)
    q = get_query(energy_service, energy_carrier)
    df = ioutils.filter_empty(df.query(q))
    demand = groupby_time(df, groupcols, balancing_time,
                          'EnergyDemand')
    return demand.drop(['EnergyService', 'EnergyCarrier'], axis=1)

def compute_gdp_rate(GDP):
    """computes gdp rate from actual gdp values
    """

    geocols = get_geographic_columns_from_dataframe(GDP)
    gdp = GDP.set_index(geocols)
    gdp = gdp.sort_index()
    index = gdp.index.unique()
    d = []
    for item in index:
        gdp_ = gdp.loc[item]
        gdp_ = gdp_.sort_values('Year')
        gdp_values = gdp_['GDP'].values
        year = gdp_['Year'].values[1:]
        gdp_rate = [gdp_ratio(gdp_values[i],  gdp_values[i-1])
                    for i, g in enumerate(gdp_values[1:], start=1)]
        df = pd.DataFrame({"Year": year,
                           "GDP_RATE": gdp_rate},
                          index=gdp_.index[1:])
        d.append(df)
    return pd.concat(d).reset_index()

def gdp_ratio(current, previous):
    return (current - previous)/previous

def get_demand_elasticity(demand_sector,
                          energy_service,
                          energy_carrier):
    q = get_query(energy_service, energy_carrier)
    df = loaders.get_parameter("DemandElasticity", demand_sector=demand_sector)
    return ioutils.filter_empty(df.query(q))

def get_base_year_demand(demand_sector,
                         energy_service,
                         energy_carrier):
    q = get_query(energy_service, energy_carrier)
    df = loaders.get_parameter("BaseYearDemand", demand_sector=demand_sector)
    return ioutils.filter_empty(df.query(q))

def compute_demand_growth_rate(demand_sector,
                               energy_service,
                               energy_carrier):
    """Multiplication of gdpelasticity and gdp_rate
    """
    geogran = demandio.get_geographic_granularity(demand_sector,
                                                  energy_service,
                                                  energy_carrier)

    elasticity = get_demand_elasticity(demand_sector,
                                       energy_service,
                                       energy_carrier)
    GDP = loaders.get_parameter("GDP")
    g_geocols = get_geographic_columns_from_dataframe(GDP)

    conscols = get_cons_columns(demand_sector, energy_service, energy_carrier)
    if conscols:  #
        elasticity = elasticity.set_index(conscols)
        gre = []
        for con in elasticity.index.unique():
            elasticity_ = elasticity.loc[con].reset_index()
            df = growth_rate_elasticity(GDP,
                                        elasticity_,
                                        conscols)
            n = len(df)
            for i, c in enumerate(conscols):
                df[c] = [con[i]]*n if len(conscols) > 1 else [con]*n
            gre.append(df)
        return pd.concat(gre)
    else:
        return growth_rate_elasticity(GDP, elasticity)

def growth_rate_elasticity(GDP, elasticity, conscols=[]):
    g_geocols = get_geographic_columns_from_dataframe(GDP)
    e_geocols = get_geographic_columns_from_dataframe(elasticity)
    other_cols = [c for c in e_geocols if c not in g_geocols]

    if other_cols:
        return growth_rate_elasticity_finer(GDP, elasticity,
                                            g_geocols,
                                            other_cols)
    else:
        return growth_rate_elasticity_coarser(GDP, elasticity, e_geocols)

def growth_rate_elasticity_finer(GDP, elasticity, g_geocols, indexcols):
    elasticity = elasticity.set_index(indexcols)
    elasticity.sort_index(level=1)
    gdp_rate = compute_gdp_rate(GDP)

    d = []

    for geo in elasticity.index.unique():
        # compute for every extra geographic granularity
        e_ = elasticity.loc[geo]
        e = e_.set_index(g_geocols + ['Year'])
        key = e.index.droplevel('Year')
        ukey = key.unique()
        if isinstance(ukey[0], tuple):
            ukey = key[0]
        q = " & ".join([f"({name} == '{ukey[i]}')" for i,
                        name in enumerate(key.names)])

        gr = gdp_rate.query(q)
        gr = gr.set_index(g_geocols + ['Year'])
        r = (gr['GDP_RATE']*e['Elasticity'])
        r.rename('GROWTH_RATE', inplace=True)
        df = r.reset_index()
        n = len(df)

        if isinstance(geo, tuple):
            df = pd.DataFrame([dict(zip(indexcols, geo))]*n).join(df)
        else:
            df = pd.DataFrame([dict(zip(indexcols, (geo,)))]*n).join(df)
        d.append(df)
    return pd.concat(d)

def growth_rate_elasticity_coarser(GDP, elasticity, e_geocols):
    gdp = GDP.groupby(e_geocols + ['Year']).sum().reset_index()
    gdp_rate = compute_gdp_rate(gdp)

    gdp_rate = gdp_rate.set_index(e_geocols + ['Year'])

    e = elasticity.set_index(e_geocols + ['Year'])
    r = e['Elasticity']*gdp_rate['GDP_RATE']
    r.rename('GROWTH_RATE', inplace=True)
    return r.reset_index()

def gdp_energy_demand(year, growth_rate, base_demand):
    """computes demand based on gdpgrowth and BaseYearDemand.

    it uses follwing recursion
    Demand[y] = DemandGrowthRate[y] * Demand[y-1]
    this actually resolves to
    Demand[y] = product(DemandGrowthRate[all x such x<=y]) * BaseYearDemand
    """
    bd = base_demand
    r = (growth_rate.query(f"Year <= {year}")['GROWTH_RATE']+1).prod()*bd
    return r

def compute_gdpelasticity_demand(demand_sector,
                                 energy_service,
                                 energy_carrier):
    """computes demand based on gdpgrowth and BaseYearDemand.

    it uses follwing recursion
    Demand[y] = DemandGrowthRate[y] * Demand[y-1]
    this actually resolves to
    Demand[y] = product(DemandGrowthRate[all x such x <= y]) * BaseYearDemand
    """
    demand_growth_rate = compute_demand_growth_rate(demand_sector,
                                                    energy_service,
                                                    energy_carrier)

    base_year_demand = get_base_year_demand(demand_sector,
                                            energy_service,
                                            energy_carrier)

    geogran = demandio.get_geographic_granularity(demand_sector,
                                                  energy_service,
                                                  energy_carrier)
    geocols = get_geographic_columns(geogran)
    geocols_dgr = get_geographic_columns_from_dataframe(demand_growth_rate)
    conscols = get_cons_columns(demand_sector, energy_service, energy_carrier)

    timegran = get_time_granularity(demand_sector,
                                    energy_service,
                                    energy_carrier)
    timecols = get_time_columns(timegran)
    indexcols = conscols + geocols + timecols

    base_year_demand = base_year_demand.set_index(conscols+geocols + timecols)

    gr = demand_growth_rate.set_index(conscols + geocols_dgr)
    gr = gr.sort_index(level=1)
    years = demand_growth_rate['Year'].unique()

    demand_dfs = []

    for item in base_year_demand.index.unique():
        index = base_year_demand.index
        key = tuple([item[index.names.index(c)]
                     for c in conscols + geocols_dgr])
        g = gr.loc[key]
        bd = base_year_demand.loc[item]
        base_demand = bd['BaseYearDemand']
        d = []
        demand = [gdp_energy_demand(y, g, base_demand) for y in years]
        indexnames = [n for n in indexcols if n != 'Year']
        year_index = indexcols.index('Year')
        indexvalues = tuple([x for i, x in enumerate(item) if i != year_index])
        index = pd.MultiIndex.from_tuples([indexvalues for y in years],
                                          names=indexnames)
        df = pd.DataFrame({"EnergyDemand": demand,
                           "Year": years},
                          index=index)

        demand_dfs.append(df)

    return pd.concat(demand_dfs).reset_index()

def filepath_demand_servicetech(demand_sector,
                                energy_service,
                                service_tech,
                                energy_carrier):
    output_path = filemanager.get_output_path("Demand")
    args = (demand_sector,
            energy_service,
            service_tech,
            energy_carrier)
    filename = "_".join(args+('Demand',))
    path = os.path.join(output_path, ".".join([filename, "csv"]))

    return path

class BottomupDemand:
    """ class to compute demand for <DS,ES,EC> which are of BOTTOMUP type
    """

    def save_st_output(demand=True):
        def save_st_output_(method):
            """decorator function to save results of energy demand per ST
            """

            @functools.wraps(method)
            def wrapper(instance, service_tech):
                if demand:
                    path = filepath_demand_servicetech(instance.demand_sector,
                                                       instance.energy_service,
                                                       service_tech,
                                                       instance.energy_carrier)
                    r = method(instance, service_tech)
                    result = r.rename(
                        'EnergyDemand', inplace=True).reset_index()
                    result = ioutils.order_rows(
                        utilities.seasonwise_timeslices(result, 'EnergyDemand'))

                    cols = ioutils.get_ordered_cols(result)
                    result[cols].to_csv(path, index=False)
                    return r
                else:
                    path = os.path.join(filemanager.get_output_path(
                        "Demand"), ".".join([f"TotalNumInstances_{service_tech}", "csv"]))
                    result = method(instance, service_tech)
                    if os.path.exists(path):
                        result = pd.concat([pd.read_csv(path), result])
                    cols = ioutils.get_ordered_cols(result)
                    cols.remove('DemandSector')
                    cols.insert(0, 'DemandSector')
                    result[cols].to_csv(path, index=False)
                    return result

            return wrapper

        return save_st_output_

    def __init__(self, demand_sector, energy_service, energy_carrier):
        self.demand_sector = demand_sector
        self.energy_service = energy_service
        self.energy_carrier = energy_carrier
        self.find_index_cols()

        self.__get_NumConsumers()
        self.__get_ST_Efficiency()
        self.__get_EfficiencyLevelSplit()
        self.__get_NumInstances()

    def compute_demand(self):
        service_techs = demandio.get_service_techs(self.demand_sector,
                                                   self.energy_service,
                                                   self.energy_carrier)
        total_demand = []

        for service_tech in service_techs:
            logger.debug(f"Computing for ServiceTech, {service_tech}")
            esu_demand = self.compute_esu_demand(service_tech)
            total_demand.append(esu_demand)

        d = sum_series(total_demand)
        d.rename('EnergyDemand', inplace=True)
        return d

    def save_tot_num_instances(self):
        service_techs = demandio.get_service_techs(self.demand_sector,
                                                   self.energy_service,
                                                   self.energy_carrier)
        total_demand = []

        for service_tech in service_techs:
            logger.debug(
                f"Computing NumAppliances for ServiceTech, {service_tech}")
            self.save_tot_num_instances_for_service_tech(service_tech)

    @save_st_output(demand=False)
    def save_tot_num_instances_for_service_tech(self, service_tech):
        ds = self.demand_sector
        es = self.energy_service

        ES_Demand = loaders.get_parameter('ES_Demand',
                                          demand_sector=ds,
                                          energy_service=es,
                                          service_tech=service_tech)
        ES_Demand = ES_Demand.set_index(self.demandindex)

        combinations = {name: tuple(name.split(constant.ST_SEPARATOR_CHAR))
                        for name in ES_Demand.columns if service_tech in name}

        appliances = []
        q = f"ServiceTech == '{service_tech}'"
        sts = demandio.get_corresponding_sts(self.demand_sector,
                                             self.energy_service,
                                             service_tech)

        indexcols = self.get_index_cols(sts)
        num_consumers = self.NumConsumers['NumConsumers']
        num_instances = self.NumInstances.set_index(
            indexcols).query(q)['NumInstances']

        ST_efficiency = self.ST_Efficiency.query(q)

        for name, comb in combinations.items():
            logger.debug(f"ServiceTech combination, {name}")
            p = loaders.get_parameter('Penetration',
                                      demand_sector=ds,
                                      energy_service=es,
                                      ST_combination=comb)
            p = p.set_index(self.get_index_cols(comb))

            d = num_consumers * p['Penetration'] * num_instances
            appliances.append(d)
        tot_num_instances = sum_series(appliances)

        efficiency_level_split = self.EfficiencyLevelSplit.set_index(
            indexcols).query(q)

        n = []
        for level in efficiency_level_split['EfficiencyLevelName'].unique():
            q = f'EfficiencyLevelName == "{level}"'
            split_share = efficiency_level_split.query(q)['SplitShare']
            df = tot_num_instances*split_share
            df = df.rename("TotalNumInstances").reset_index()
            df['EfficiencyLevelName'] = level
            n.append(df)

        r = pd.concat(n)
        r['DemandSector'] = self.demand_sector
        return r

    @save_st_output(demand=True)
    def compute_esu_demand(self, service_tech):
        """
        Compute ESU demand for given service_tech
        """
        ds = self.demand_sector
        es = self.energy_service

        ES_Demand = loaders.get_parameter('ES_Demand',
                                          demand_sector=ds,
                                          energy_service=es,
                                          service_tech=service_tech)
        ES_Demand = ES_Demand.set_index(self.demandindex)

        combinations = {name: tuple(name.split(constant.ST_SEPARATOR_CHAR))
                        for name in ES_Demand.columns if service_tech in name}
        esu_demand = []
        logger.debug(f"Total Combinations, {combinations}")
        sts = demandio.get_corresponding_sts(self.demand_sector,
                                             self.energy_service,
                                             service_tech)
        indexcols = self.get_index_cols(sts)

        for name, comb in combinations.items():
            logger.debug(f"ServiceTech combination, {name}")

            p = loaders.get_parameter('Penetration',
                                      demand_sector=ds,
                                      energy_service=es,
                                      ST_combination=comb)
            p = p.set_index(self.get_index_cols(comb))

            e = self.compute_esu_demand_per_comb(service_tech,
                                                 p['Penetration'],
                                                 ES_Demand[name],
                                                 indexcols)
            esu_demand.append(e)

        return sum_series(esu_demand)

    def compute_esu_demand_per_comb(self,
                                    service_tech,
                                    penetration,
                                    es_demand,
                                    indexcols):
        """compute ESU demand for particular combination with other
        service_tech
        """
        q = f"ServiceTech == '{service_tech}'"
        num_consumers = self.NumConsumers['NumConsumers']
        num_instances = self.NumInstances.set_index(
            indexcols).query(q)['NumInstances']
        efficiency_level_split = self.EfficiencyLevelSplit.set_index(
            indexcols).query(q)
        ST_efficiency = self.ST_Efficiency.query(q)

        esu_demand = []
        for level in ST_efficiency['EfficiencyLevelName'].unique():
            q = f'EfficiencyLevelName == "{level}"'
            efficiency = ST_efficiency.query(q)['Efficiency']
            split_share = efficiency_level_split.query(q)['SplitShare']

            d = num_consumers * penetration * num_instances * \
                es_demand * split_share * efficiency

            esu_demand.append(d)

        return sum_series(esu_demand)

    def __get_NumInstances(self):
        ds = self.demand_sector
        es = self.energy_service
        self.NumInstances = loaders.get_parameter('NumInstances',
                                                  demand_sector=ds,
                                                  energy_service=es)
        # self.NumInstances = NumInstances.set_index(self.indexcols)

    def __get_EfficiencyLevelSplit(self):
        ds = self.demand_sector
        es = self.energy_service
        self.EfficiencyLevelSplit = loaders.get_parameter('EfficiencyLevelSplit',
                                                          demand_sector=ds,
                                                          energy_service=es)
        # self.EfficiencyLevelSplit = efsplit.set_index(self.indexcols)

    def __get_ST_Efficiency(self):
        ST_Efficiency = loaders.get_parameter('ST_Efficiency',
                                              demand_sector=self.demand_sector)
        self.ST_Efficiency = ST_Efficiency.set_index('Year')
        # always given at Year level

    def get_index_cols(self, sts):
        ST_Granularity_Map = loaders.get_parameter('DS_ST_Granularity_Map')
        st_gran = ST_Granularity_Map.set_index(['DemandSector', 'ServiceTech'])

        g = ST_Granularity_Map.query(
            f"DemandSector == '{self.demand_sector}'  & ServiceTech in {sts}")
        consgran, ggran, tgran = demandio.coarsest(g, self.demand_sector)
        t = constant.TIME_COLUMNS[tgran]
        g = constant.GEO_COLUMNS[ggran]
        c = constant.CONSUMER_COLUMNS[consgran]
        return c + g + t

    def find_index_cols(self):
        geogran = demandio.get_geographic_granularity(self.demand_sector,
                                                      self.energy_service,
                                                      self.energy_carrier)
        geocols = get_geographic_columns(geogran)
        timegran = get_time_granularity(self.demand_sector,
                                        self.energy_service,
                                        self.energy_carrier)
        timecols = get_time_columns(timegran)
        self.conscols = get_cons_columns(self.demand_sector,
                                         self.energy_service,
                                         self.energy_carrier)

        self.demandindex = self.conscols + geocols + timecols

    def __get_NumConsumers(self):
        NumConsumers = loaders.get_parameter('NumConsumers',
                                             demand_sector=self.demand_sector)
        indexcols = self.conscols + self.get_index_cols_num_consumers()
        self.NumConsumers = NumConsumers.set_index(indexcols)

    def get_index_cols_num_consumers(self):
        demand_sector = self.demand_sector
        DS_Cons1_Map = loaders.get_parameter('DS_Cons1_Map')
        geogran = DS_Cons1_Map[demand_sector][0]
        timegran = DS_Cons1_Map[demand_sector][1]
        return get_geographic_columns(geogran) + get_time_columns(timegran)

def compute_bottomup_demand(demand_sector,
                            energy_service,
                            energy_carrier):
    bottomup = BottomupDemand(demand_sector,
                              energy_service,
                              energy_carrier)

    r = bottomup.compute_demand().reset_index()
    return r

def sum_series(items):
    """
    vector adds multiple pd.Series given as list like collection
    """
    s = items[0]
    for item in items[1:]:
        s = s + item
    return s

def get_non_bottomup_tuples(demand_sector,  energy_service, energy_carrier):
    DS_ES_EC_Map = loaders.get_parameter('DS_ES_EC_Map')
    return [row[:3] for row in DS_ES_EC_Map if row[0] ==
            demand_sector and row[2] == energy_carrier and row[1] != energy_service]

def get_bottomup_tuples(demand_sector, energy_carrier):
    DS_ES_ST_Map = loaders.get_parameter('DS_ES_ST_Map')
    DS_ES_ST = [(row[0], row[1], item)
                for row in DS_ES_ST_Map for item in row[2:] if row[0] == demand_sector]

    ST_Info = loaders.get_parameter('ST_Info')
    for ds, es, st in DS_ES_ST:
        ecs = ST_Info.query(
            f"EnergyCarrier == '{energy_carrier}' & ServiceTech == '{st}'")
        if len(ecs) > 0:
            yield ds, es, energy_carrier

def aggregate_demand(demand, aggcols):
    """
    Aggregates non residual demand to coarser level for
    corresponding residual demand.
    """
    # can be optimized if needed, aggregate only if required.
    return demand.reset_index().groupby(aggcols)['EnergyDemand'].sum()

def compute_residual_demand(demand_sector,
                            energy_service,
                            energy_carrier):
    def get_index_cols():
        dataset_cols = residual_demand.columns
        all_indexcols = constant.TIME_SLICES + \
            constant.GEOGRAPHIES + constant.CONSUMER_TYPES

        return [c for c in all_indexcols if c in dataset_cols]

    ResidualDemand = loaders.get_parameter("ResidualDemand",
                                           demand_sector=demand_sector)

    q = f"EnergyCarrier == '{energy_carrier}' & EnergyService == '{energy_service}'"
    residual_demand = ResidualDemand.query(q)
    indexcols = get_index_cols()
    residual_share = residual_demand.set_index(indexcols)['ResidualShare']

    non_bottomup = get_non_bottomup_tuples(demand_sector,
                                           energy_service,
                                           energy_carrier)

    bottomup = set(get_bottomup_tuples(demand_sector,
                                       energy_carrier))

    s = sum_series([aggregate_demand(compute_demand(*item),
                                     indexcols)
                    for item in non_bottomup+list(bottomup)])

    rs = residual_share*s
    rs.rename('EnergyDemand', inplace=True)
    return rs.reset_index()[indexcols + ['EnergyDemand']]

def coarsest(ds_es_ec, take_cons_cols):
    if take_cons_cols:
        c = min(ds_es_ec.to_dict(orient='records'),
                key=lambda x: len(get_cons_columns(x['DemandSector'], x['EnergyService'], x['EnergyCarrier'])))
        conscols = get_cons_columns(
            c['DemandSector'], c['EnergyService'], c['EnergyCarrier'])
    else:
        conscols = []
    g = min(ds_es_ec['GeographicGranularity'].values,
            key=lambda x: len(constant.GEO_COLUMNS[x]))
    t = min(ds_es_ec['TimeGranularity'].values,
            key=lambda x: len(constant.TIME_COLUMNS[x]))

    return constant.TIME_COLUMNS[t] + constant.GEO_COLUMNS[g] + conscols

def get_group_cols_for_ec(ec):
    g = get_geographic_columns(demandio.balancing_area(ec))
    t = get_time_columns(demandio.balancing_time(ec))
    return t+g

def finest_balancing_area_time(ds_es_ec):
    EC = ds_es_ec['EnergyCarrier'].unique()
    g = [get_geographic_columns(demandio.balancing_area(ec)) for ec in EC]
    t = [get_time_columns(demandio.balancing_time(ec)) for ec in EC]

    g = max(g, key=len)
    t = max(t, key=len)
    return t+g

def compute_demand_balancing(demand_sector, energy_service, energy_carrier):
    """aggregates the demand over balancing area and balancing time
    """
    cols = get_group_cols_for_ec(energy_carrier)
    return compute_demand_with_coarseness(demand_sector,
                                          energy_service,
                                          energy_carrier,
                                          cols)

def compute_demand_with_coarseness(demand_sector,
                                   energy_service,
                                   energy_carrier,
                                   columns):
    """aggregates the demand over the granularity given by columns
    """
    demand = compute_demand(demand_sector, energy_service, energy_carrier)
    return demand.groupby(columns).sum()

def compute_demand_with_coarseness_service_techs(demand_sector,
                                                 energy_service,
                                                 energy_carrier,
                                                 columns):
    """aggregates the demand with service_tech, over the granularity given by columns

    Parameters
    -----------
    demand_sector: str
    energy_service: str
    energy_carrier: str
    columns: list

    Returns
    -------
       a dataframe
    """
    demand = compute_demand(demand_sector, energy_service, energy_carrier)
    service_techs_files = find_service_tech_demand_filepath(demand_sector,
                                                            energy_service,
                                                            energy_carrier)
    if not service_techs_files:
        return ioutils.order_rows(demand.groupby(columns).sum().reset_index())
    else:
        d = []
        for st in service_techs_files:
            df = pd.read_csv(service_techs_files[st]).groupby(
                columns).sum().reset_index()
            df['ServiceTech'] = st
            d.append(ioutils.order_rows(df))
        return pd.concat(d)

def find_service_tech_demand_filepath(demand_sector,
                                      energy_service,
                                      energy_carrier):
    service_techs = demandio.get_service_techs(demand_sector,
                                               energy_service,
                                               energy_carrier)
    return {st: filepath_demand_servicetech(demand_sector,
                                            energy_service,
                                            st,
                                            energy_carrier) for st in service_techs}

def save_coarsest(entity_names=('EnergyService', 'EnergyCarrier')):
    """Aggregates Demand for EnergyService,EnergyCarrier over all DemandSectors
    """
    ds_es_ec_columns = ['DemandSector', 'EnergyService', 'EnergyCarrier']
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")
    entities = DS_ES_EC_DemandGranularity_Map.set_index(
        entity_names).index

    for items in entities:
        if isinstance(items, str):
            items = (items,)

        logging.debug(
            f"Writing results for " + ",".join(items) + " across all demand sectors")
        filepath = os.path.join(
            filemanager.get_output_path("Demand"), "_".join(items + ('Demand.csv',)))
        if os.path.exists(filepath):
            logger.debug(f"{filepath} exists, skipping")
            continue

        q = " & ".join([f"{name} == '{item}'" for name,
                        item in zip(entity_names, items)])
        ds_es_ec_map = DS_ES_EC_DemandGranularity_Map.query(q)
        ds_es_ec = ds_es_ec_map.set_index(ds_es_ec_columns).index
        cols = coarsest(ds_es_ec_map, "DemandSector" in entity_names)

        target_cols = ["EnergyDemand",
                       'SeasonEnergyDemand'] if 'Season' in cols else ['EnergyDemand']

        with open(filepath, "w", newline='') as f:
            csvf = csv.DictWriter(f, dialect='excel',
                                  fieldnames=cols + target_cols)
            csvf.writeheader()
            d = []
            for ds, es, ec in ds_es_ec:
                d.append(compute_demand_with_coarseness(ds, es, ec, cols))
            df = utilities.seasonwise_timeslices(sum_series(d).reset_index(),
                                                 'EnergyDemand')
            df = ioutils.order_rows(df)
            csvf.writerows(df.to_dict(orient='records'))

def check_energy_service_service_tech_count(ds_es_ec_map, ds_es_ec):
    """checks if combination of DS-EC-ES-ST has at least two items in it
    """
    if len(ds_es_ec_map) > 1:  # either multiple energy services
        return True
    else:
        ds, es, ec = next(iter(ds_es_ec))  # this will have only one item in it
        # or check multiple service_techs in next line
        return len(find_service_tech_demand_filepath(ds, es, ec)) > 1

def save_coarsest_with_ST():
    """Aggregates Demand for EnergyService,EnergyCarrier over all DemandSectors
    """
    entity_names = ['DemandSector', 'EnergyCarrier']
    ds_es_ec_columns = ['DemandSector', 'EnergyService', 'EnergyCarrier']
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")
    entities = DS_ES_EC_DemandGranularity_Map.set_index(
        entity_names).index
    print(f"Writing results across all demand sectors with ServiceTech and EnergyService")

    for items in entities:
        if isinstance(items, str):
            items = (items,)

        logging.debug(
            f"Writing results for " + ",".join(items) +
            " across all demand sectors with ServiceTech and EnergyService")
        filepath = os.path.join(
            filemanager.get_output_path("Demand"), "_".join(items + ('EnergyService_ServiceTech_Demand.csv',)))
        if os.path.exists(filepath):
            logger.debug(f"{filepath} exists, skipping")
            continue

        q = " & ".join([f"{name} == '{item}'" for name,
                        item in zip(entity_names, items)])
        ds_es_ec_map = DS_ES_EC_DemandGranularity_Map.query(q)
        ds_es_ec = ds_es_ec_map.set_index(ds_es_ec_columns).index
        cols = coarsest(ds_es_ec_map, "DemandSector" in entity_names)

        if not check_energy_service_service_tech_count(
                ds_es_ec_map.set_index(ds_es_ec_columns),
                ds_es_ec):
            continue

        target_cols = ['EnergyService',
                       'ServiceTech',
                       "EnergyDemand"]
        if 'Season' in cols:
            target_cols += ['SeasonEnergyDemand']

        with open(filepath, "w", newline='') as f:
            csvf = csv.DictWriter(f, dialect='excel',
                                  fieldnames=cols + target_cols)
            csvf.writeheader()
            d = []
            for ds, es, ec in ds_es_ec:
                df = compute_demand_with_coarseness_service_techs(
                    ds, es, ec, cols)
                df['EnergyService'] = es
                csvf.writerows(df.to_dict(orient='records'))

def complete_run():
    """runs validation and complete demand processing flow.
    """
    if config.get_config_value("validation") == 'True':
        validate()

    compute_demand_all()
    path = save_by_balancing_area_time()
    save_coarsest(entity_names=['DemandSector', 'EnergyCarrier'])
    save_coarsest(entity_names=['EnergyCarrier'])
    save_coarsest(entity_names=['EnergyService', 'EnergyCarrier'])
    save_coarsest_with_ST()
    copy_supply_parameter(path)

def validate():
    """Validate Common and Demand parameters
    returns True or False
    """
    valid = loaders.validate_params("Common")
    if not valid:
        raise Exception("Validation failed for Common")
    valid = valid and loaders.validate_params("Demand")
    if not valid:
        raise Exception("Validation failed for Demand")

def get_residual_services(ds_es_ec):
    return [(ds, es, ec) for ds, es, ec in ds_es_ec if demandio.get_type(ds, es) == "RESIDUAL"]

def get_non_residual_services(ds_es_ec):
    return [(ds, es, ec) for ds, es, ec in ds_es_ec if demandio.get_type(ds, es) != "RESIDUAL"]

def save_total_num_instances(ds_es_ec):
    bottomups = [(ds, es, ec) for ds, es,
                 ec in ds_es_ec if demandio.get_type(ds, es) == "BOTTOMUP"]
    for ds, es, ec in bottomups:
        b = BottomupDemand(ds, es, ec)
        b.save_tot_num_instances()

def compute_demand_all():
    """Computes demand for all combinations of demand_sector, energy_service
    and energy_carrier
    """
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")

    ds_es_ec = DS_ES_EC_DemandGranularity_Map.set_index(
        ['DemandSector', 'EnergyService', 'EnergyCarrier']).index

    path_all = os.path.join(
        filemanager.get_output_path("Demand"), "EndUseDemandEnergy.csv")

    fine_cols = ['EnergyCarrier'] + \
        finest_balancing_area_time(DS_ES_EC_DemandGranularity_Map) + \
        ['EndUseDemandEnergy', 'TotalEnergyDemand']

    print("Computing demand")
    logger.info("Computing demand")
    nonres_ds_es_ec = get_non_residual_services(ds_es_ec)
    logger.info("Computing non RESIDUAL demand")
    execute_in_process_pool(compute_demand, nonres_ds_es_ec)

    res_ds_es_ec = get_residual_services(ds_es_ec)
    logger.info("Computing RESIDUAL demand")
    execute_in_process_pool(compute_demand, res_ds_es_ec)

    logger.info("Computing total num instances")
    save_total_num_instances(ds_es_ec)

def check_valid_ds_es_ec(demand_sector,
                         energy_service,
                         energy_carrier):
    valid = True
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")
    ds_es_ec = DS_ES_EC_DemandGranularity_Map.set_index(
        ['DemandSector', 'EnergyService', 'EnergyCarrier']).index

    if demand_sector not in DS_ES_EC_DemandGranularity_Map.DemandSector.unique():
        print(f"Invalid value for demand_sector parameter, {demand_sector}")
        valid = False
    if energy_service not in DS_ES_EC_DemandGranularity_Map.EnergyService.unique():
        print(f"Invalid value for energy_service parameter, {energy_service}")
        valid = False
    if energy_carrier not in DS_ES_EC_DemandGranularity_Map.EnergyCarrier.unique():
        print(f"Invalid value for energy_carrier parameter, {energy_carrier}")
        valid = False
    if (demand_sector, energy_service, energy_carrier) not in ds_es_ec:
        print("Invalid combination of demand_sector, energy_service, energy_carrier")
        valid = False

    return valid

def save_by_balancing_area_time():
    """daves demand at balancing area and balancing time in EndUseDemandEnergy.csv
    """
    DS_ES_EC_DemandGranularity_Map = loaders.get_parameter(
        "DS_ES_EC_DemandGranularity_Map")

    ds_es_ec = DS_ES_EC_DemandGranularity_Map.set_index(
        ['DemandSector', 'EnergyService', 'EnergyCarrier']).index

    path_all = os.path.join(
        filemanager.get_output_path("Demand"), "EndUseDemandEnergy.csv")

    fine_cols = ['EnergyCarrier'] + \
        finest_balancing_area_time(DS_ES_EC_DemandGranularity_Map) + \
        ['EndUseDemandEnergy', 'TotalEnergyDemand']

    print("Writing results by balancing area and balancing time")
    logger.info("Writing results by balancing area and balancing time")
    with open(path_all, "w", newline='') as f:
        csvf = csv.DictWriter(f, dialect='excel', fieldnames=fine_cols)
        csvf.writeheader()
        for EC in DS_ES_EC_DemandGranularity_Map['EnergyCarrier'].unique():
            ds_es_EC = [(ds, es, ec)
                        for ds, es, ec in ds_es_ec if ec == EC]
            d = []
            for ds, es, ec in ds_es_EC:
                d.append(compute_demand_balancing(ds,
                                                  es,
                                                  EC))
            s = sum_series(d)
            df = s.reset_index()
            df = utilities.seasonwise_timeslices(df,
                                                 'EnergyDemand')
            if 'SeasonEnergyDemand' in df.columns:
                df = df.rename(
                    columns={'SeasonEnergyDemand': 'TotalEnergyDemand'})
            else:
                df['TotalEnergyDemand'] = df['EnergyDemand']
            df = df.rename(columns={'EnergyDemand': 'EndUseDemandEnergy'})

            df['EnergyCarrier'] = [EC]*len(df)
            df = ioutils.order_rows(df)
            csvf.writerows(df.to_dict(orient='records'))

    return path_all

def copy_supply_parameter(srcpath):
    """Copies EndUseDemandEnergy to supply paramters data
    """
    supplypath = filemanager.find_filepath('EndUseDemandEnergy')
    scenario = config.get_config_value("scenario")
    scenario_ = os.path.join("Scenarios", scenario)
    path = supplypath.replace("Global Data", scenario_)
    if os.path.exists(path):
        warning = f"Results of previous run are present at {path}. Results will be overwritten, press n to cancel, enter to continue (y/n)"
        check = input(warning)
        if check and check.strip() and check.strip().lower()[0] == "n":
            return
    else:
        os.makedirs(os.path.dirname(path), exist_ok=True)
    shutil.copy(srcpath, path)

def clean_output():
    """Deletes files from output directory.
    """
    outputpath = filemanager.get_output_path("Demand")
    if os.listdir(outputpath):
        warning = f"Results of previous run are present at {outputpath}. Results will be overwritten, press n to cancel, enter to continue (y/n)"
        check = input(warning)
        if check and check.strip() and check.strip().lower()[0] == "n":
            sys.exit(1)
        for p in [os.path.join(outputpath, f)
                  for f in os.listdir(outputpath)]:

            os.unlink(p)

def rumi_demand(model_instance_path: str,
                scenario: str,
                output: str,
                demand_sector: str,
                energy_service: str,
                energy_carrier: str,
                logger_level: str,
                numthreads: int,
                validation: bool):
    """Computes demand for given demand_sector,energy_service.energy_carrier. if none
    is given , it computes demand for all combinations.

    :param: model_instance_path : str
              Path where model instance is stored
    :param: scenario : str
              Name of Scenario
    :param: output : str
              Custom output folder
    :param: demand_sector : str
              Name of demand sector
    :param: energy_service : str
              Name of energy service
    :param: energy_carrier : str
              Name of energy carrier
    :param: logger_level : str
              Level for logging,one of INFO,WARN,DEBUG,ERROR
    :param: numthreads : int
              Number of threads/processes
    :param: validation : bool
              Whether to do validation

    """
    if not loaders.sanity_check_cmd_args("Demand",
                                         model_instance_path,
                                         scenario,
                                         logger_level,
                                         numthreads,
                                         cmd='rumi_demand'):
        return

    global logger
    config.initialize_config(model_instance_path, scenario)
    if output:
        config.set_config("output", output)
    config.set_config("numthreads", str(numthreads))
    config.set_config("validation", str(validation))

    if not all([demand_sector, energy_service, energy_carrier]):
        clean_output()

    init_logger("Demand", logger_level)
    logger = logging.getLogger("rumi.processing.demand")

    try:
        ds_es_ec = [demand_sector, energy_service, energy_carrier]
        if all(ds_es_ec):
            if not check_valid_ds_es_ec(demand_sector,
                                        energy_service,
                                        energy_carrier):
                pass
            else:
                print(compute_demand(demand_sector,
                                     energy_service,
                                     energy_carrier))
        elif any(ds_es_ec):  # any but not all!
            print(
                "Partial inputs given for demand_sector, energy_service and energy_carrier")
            print(
                "demand_sector, energy_service and energy_carrier , either all should be given or none.")
            return
        else:
            complete_run()
    except Exception as e:
        logger.exception(e)
        raise e
    finally:
        time.sleep(1)
        get_event().set()

@click.command()
@click.option("-m", "--model_instance_path",
              type=click.Path(exists=True),
              help="Path of the model instance root folder")
@click.option("-s", "--scenario",
              help="Name of the scenario within specified model")
@click.option("-o", "--output",
              help="Path of the output folder",
              default=None)
@click.option("-D", "--demand_sector",
              help="Name of the demand sector",
              default=None)
@click.option("-E", "--energy_service",
              help="Name of the energy service",
              default=None)
@click.option("-C", "--energy_carrier",
              help="Name of the energy carrier",
              default=None)
@click.option("-l", "--logger_level",
              help="Level for logging: one of INFO, WARN, DEBUG or ERROR (default: INFO)",
              default="INFO")
@click.option("-t", "--numthreads",
              help="Number of threads/processes (default: 2)",
              default=2)
@click.option("--validation/--no-validation",
              help="Enable/disable validation (default: Enabled)",
              default=True)
def _main(model_instance_path,
          scenario: str,
          output: str,
          demand_sector: str,
          energy_service: str,
          energy_carrier: str,
          logger_level: str,
          numthreads: int,
          validation: bool):
    """Command line interface for processing demand inputs.

    -m/--model_instance_path and -s/--scenario are mandatory arguments, while the
    others are optional.

    if demand_sector, energy_service, energy_carrier options are provided, demand
    will be computed only for given demand_sector, energy_service, energy_carrier
    combinations. If these parameters are not given (none of them),
    then demand will be processed for all demand_sector, energy_service and
    energy_carrier combinations.
    """
    rumi_demand(model_instance_path=model_instance_path,
                scenario=scenario,
                output=output,
                demand_sector=demand_sector,
                energy_service=energy_service,
                energy_carrier=energy_carrier,
                logger_level=logger_level,
                numthreads=numthreads,
                validation=validation)

def main():
    if len(sys.argv) == 1:
        print("To see valid options  run the command with --help")
        print("rumi_demand --help")
    else:
        _main()

if __name__ == "__main__":
    main()


import datetime as dt
import pathlib
from typing import Generic, TypeVar

from pydantic import HttpUrl

from pydantic_xml import BaseXmlModel, element

AuthType = TypeVar('AuthType')

class SoapHeader(
    BaseXmlModel, Generic[AuthType],
    tag='Header',
    ns='soap',
):
    auth: AuthType

class SoapMethod(BaseXmlModel):
    pass

MethodType = TypeVar('MethodType', bound=SoapMethod)

class SoapBody(
    BaseXmlModel, Generic[MethodType],
    tag='Body',
    ns='soap',
):
    call: MethodType

HeaderType = TypeVar('HeaderType', bound=SoapHeader)
BodyType = TypeVar('BodyType', bound=SoapBody)

class SoapEnvelope(
    BaseXmlModel,
    Generic[HeaderType, BodyType],
    tag='Envelope',
    ns='soap',
    nsmap={
        'soap': 'http://www.w3.org/2003/05/soap-envelope/',
    },
):
    header: HeaderType
    body: BodyType

class BasicAuth(
    BaseXmlModel,
    tag='BasicAuth',
    ns='auth',
    nsmap={
        'auth': 'http://www.company.com/auth',
    },
):
    user: str = element(tag='Username')
    password: str = element(tag='Password')

class CreateCompanyMethod(
    SoapMethod,
    tag='CreateCompany',
    ns='co',
    nsmap={
        'co': 'https://www.company.com/co',
    },
):
    trade_name: str = element(tag='TradeName')
    founded: dt.date = element(tag='Founded')
    website: HttpUrl = element(tag='WebSite')

CreateCompanyRequest = SoapEnvelope[
    SoapHeader[
        BasicAuth
    ],
    SoapBody[
        CreateCompanyMethod
    ],
]

xml_doc = pathlib.Path('./doc.xml').read_text()

request = CreateCompanyRequest.from_xml(xml_doc)

assert request == CreateCompanyRequest.parse_file('./doc.json')


from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
import pandas as pd
import requests

# import player names from csv data and save to a list for dynamic url querying
player_names = {}
#lookup table cooresponding abbreviations to team names
nhl_teams = {
  "ANA" : 'anaheim-ducks',
  "ARI" : 'arizona-coyotes',
  "BOS" : 'boston-bruins',
  "BUF" : 'buffalo-sabres',
  "CGY" : 'calgary-flames',
  "CAR" : 'carolina-hurricanes',
  "CHI" : 'chicago-blackhawks',
  "COL" : 'colorado-avalanche',
  "CBJ" : 'columbus-blue-jackets',
  "DAL" : 'dallas-stars',
  "DET" : 'detroit-red-wings',
  "EDM" : 'edmonton-oilers',
  "FLA" : 'florida-panthers',
  "LAK" : 'los-angeles-kings',
  "MIN" : 'minnesota-wild',
  "MTL" : 'montreal-canadians',
  "NSH" : 'nashville-predators',
  "NJD" : 'new-jersey-devils',
  "NYI" : 'new-york-islanders',
  "NYR" : 'new-york-rangers',
  "OTT" : 'ottawa-senators',
  "PHI" : 'philadelphia-flyers',
  "PIT" : 'pittsburgh-penguins',
  "SJS" : 'san-jose-sharks',
  "STL" : 'st-louis-blues',
  "TBL" : 'tampa-bay-lightning',
  "TOR" : 'toronto-maple-leafs',
  "VAN" : 'vancouver-canucks',
  "VEG" : 'vegas-golden-knights',
  "WSH" : 'washington-capitals',
  "WPG" : 'winnipeg-jets'
}

#read in csv with pandas
data = pd.read_csv("nhl_statistics.csv")

# looping through the csv to save the player name and team name to a dict for later reference
for index, row in data.iterrows():
    player_name = row['Player'].lower().replace(" ", "-").strip()
    team = nhl_teams[row['Tm']]
    player_names[player_name] = team

# use player names and BS to scrape player images
for name, team in player_names.items():
  try:
    req = Request(f"https://frozenpool.dobbersports.com/players/{name}", headers={'User-Agent': 'Mozilla/5.0'})
    webpage = urlopen(req, timeout=10).read()
    soup = BeautifulSoup(webpage, 'html.parser')
    # scrape all images tags in the webpage
    images = soup.find_all('img')

    #for each image url scraped from frozen tools, request and save the player image
    for item in images:
      #upload files was a key in determining which urls were the player images.
      if "uploadfiles" in item['src']:

        #using the requests library, save the images locally
        url = item['src']
        r=requests.get(url)
        with open(f'./images/{team}/{name}.jpg', 'wb') as f:
          f.write(r.content)
  #pass all errors, some players do not play anymore, retired etc.
  except:
    print("error")
    pass


from django.contrib import admin
from django.urls import path
from PruebaVocacional import views as test
from django.conf import settings
from django.conf.urls.static import static
from chat import views as chat
from herramientas import views as herramientas
from cuentas import views as cuentas

urlpatterns = [
    path('admin/', admin.site.urls),
    path('home/<int:id_estudiante>', cuentas.home,name='home'),
    path('',cuentas.home_name,name='home_name'),
    path('test/<int:id_estudiante>',test.test, name='test'),
    path('chat/<int:id_estudiante>',chat.chat,name="chat"),
    path('metodos-estudio/<int:id_estudiante>', herramientas.metodos_estudio, name="metodos-estudio"),
    path('test/answers/<int:id_estudiante>',test.answers,name='answers'),
    path('test/result/<int:id_estudiante>',test.result,name="result"),
    path('horario/<int:id_estudiante>',herramientas.horario,name='horario'),
    path('horario/agregar/<int:id_estudiante>', herramientas.agregar_clase , name='agregar_clase' ),
    path('calcular-promedio/<int:id_estudiante>', herramientas.calcular_promedio, name="calcular-promedio"),
    path('registro/',cuentas.register, name='registro'),
    path('profile/<int:id_estudiante>',cuentas.profile,name='perfil'),
    path('chat/<int:id_estudiante>',chat.chat,name="chat"),
    path('metodos-estudio/<int:id_estudiante>', herramientas.metodos_estudio, name="metodos-estudio"),
    path('analisis/<int:id_estudiante>', test.data, name="analisis")
]

if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from rest_framework.parsers import JSONParser
from django.http.response import JsonResponse
from EmployeeApp.models import Departaments,Employees
from EmployeeApp.serializers import DepartamentSerializer, EmployeeSerializer
from django.core.files.storage import default_storage

# Create your views here.
@csrf_exempt
def departamentApi(request,id=0):
    if request.method=='GET':
        departaments = Departaments.objects.all()
        departaments_serializer = DepartamentSerializer(departaments, many=True)
        return JsonResponse(departaments_serializer.data, safe=False)
    elif request.method=='POST':
        departament_data=JSONParser().parse(request)
        departament_serializer = DepartamentSerializer(data=departament_data)
        if departament_serializer.is_valid():
            departament_serializer.save()
            return JsonResponse("Added Successfully", safe=False)
        return JsonResponse("Failed to Add", safe=False)
    elif request.method=='PUT':
        departament_data = JSONParser().parse(request)
        departament=Departaments.objects.get(DepartamentId=departament_data['DepartamentId'])
        departament_serializer=DepartamentSerializer(departament, data=departament_data)
        if departament_serializer.is_valid():
            departament_serializer.save()
            return JsonResponse("Update Successfuly", safe=False)
        return JsonResponse("Failed to Update", safe=False)

    elif request.method=='DELETE':
        departament=Departaments.objects.get(DepartamentId=id)
        departament.delete()
        return JsonResponse("Deleted Successfuly", safe=False)

@csrf_exempt
def employeeApi(request,id=0):
    if request.method=='GET':
        employees = Employees.objects.all()
        employees_serializer = EmployeeSerializer(employees, many=True)
        return JsonResponse(employees_serializer.data, safe=False)
    elif request.method=='POST':
        employee_data=JSONParser().parse(request)
        employee_serializer = EmployeeSerializer(data=employee_data)
        if employee_serializer.is_valid():
            employee_serializer.save()
            return JsonResponse("Added Successfully", safe=False)
        return JsonResponse("Failed to Add", safe=False)
    elif request.method=='PUT':
        employee_data = JSONParser().parse(request)
        employee= Employees.objects.get(EmployeeId = employee_data['EmployeeId'])
        employee_serializer=EmployeeSerializer(employee, data = employee_data)
        if employee_serializer.is_valid():
            employee_serializer.save()
            return JsonResponse("Update Successfuly", safe=False)
        return JsonResponse("Failed to Update", safe=False)

    elif request.method=='DELETE':
        employee=Employees.objects.get(EmployeeId=id)
        employee.delete()
        return JsonResponse("Deleted Successfuly", safe=False)

@csrf_exempt
def SaveFile(request):
    file=request.FILES['uploadedFile']
    file_name = default_storage.save(file.name, file)

    return JsonResponse(file_name, safe=False)


from datetime import datetime
import pyotp
import base64
import random
import string
import math
from authenticate.models import User
from django.shortcuts import render
from .models import PhoneModel,OtpModel
from .serializer import MobileSerializer,OtpSerializer
from rest_framework.response import Response
from rest_framework.views import APIView
from django.core.exceptions import ObjectDoesNotExist
from .serializer import OtpSerializer
from rest_framework import  generics
from rest_framework.permissions import IsAuthenticated,IsAdminUser
from utils.permissions import IsOwnerOrReadOnly,IsSuper
from rest_framework.authentication import SessionAuthentication
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class generateKey:

    @staticmethod
    def returnValue(phone):
        digits = string.digits
        length = 12
        return str(phone) + str(datetime.date(datetime.now())) + str(''.join((random.choice(digits) for i in range(length))))

class getPhoneNumberRegistered(APIView):

    authentication_classes      =   []
    permission_classes          =   []
    serializer_class            =   MobileSerializer

    def post(self,request,*args,**kwargs):
        print('tst')
        print(request.data.get('mobile'))
        phone = request.data['mobile']

        try:
            user = User.objects.get(contact=phone)
            print(user)
        except ObjectDoesNotExist:
            return Response({"sorry":"phone number not registered"},status=404)

        if PhoneModel.objects.filter(mobile=phone).exists():
             Mobile = PhoneModel.objects.get(mobile=phone)
             print('exist already')
        else:
            PhoneModel.objects.create(mobile=phone)
            Mobile = PhoneModel.objects.get(mobile=phone)
            print('newly')

        Mobile.counter += 1 # Update Counter At every Call
        Mobile.save()
        keygen = generateKey()
        key = base64.b32encode(keygen.returnValue(phone).encode())
        OTP = pyotp.HOTP(key) # HOTP Model for OTP is created
        print(OTP.at(Mobile.counter))
        otp = OTP.at(Mobile.counter)
        PhoneModel.objects.filter(mobile=phone).update(otp=otp)

        # if OtpModel.objects.filter(pk=Mobile.pk).exists():
        #     OtpModel.objects.filter(pk=Mobile.pk).update(
        #                                             mobile=phone
        #                                             )
        # else:
        #     OtpModel.objects.create(pk=Mobile.pk,mobile=phone)

        # Using Multi-Threading send the OTP Using Messaging Services like Twilio or Fast2sms
        return Response({"OTP":OTP.at(Mobile.counter)},status=200) # Just for demonstration

class VerifyOtp(generics.CreateAPIView):
    queryset                =       OtpModel.objects.all()
    serializer_class        =       OtpSerializer
    permission_classes      =       [IsAuthenticated]
    authentication_classes  =       [JSONWebTokenAuthentication,SessionAuthentication]

    def post(self,request,*args,**kwargs):
        print('otp ')
        otp = request.data['otp']
        contact=request.user.contact
        try:
            Mobile = PhoneModel.objects.get(mobile=contact)
            eotp = Mobile.otp
            print(otp)
            print(eotp)

            if str(otp) == str(eotp):
                if OtpModel.objects.filter(user=request.user).exists():
                    OtpModel.objects.filter(user=request.user).update(otp=otp)
                    response  =   {"message":"authorized","otp":otp,"status":201}
                    return Response(response,status=201)
                else:
                    self.create(request,*args,**kwargs)
                    response  =   {"message":"authorized","otp":otp,"status":201}
                    return Response(response,status=201)
            else:
                return Response({"message":"invalid OTP"})
        except:
            return Response({"message":"something wrong"})

    def perform_create(self,serializer):
        serializer.save(user=self.request.user)

    # @staticmethod
    # def post(request,phone):
    #     try:
    #         Mobile = PhoneModel.objects.get(mobile=phone)

    #     except ObjectDoesNotExist:
    #         return Response("user doesn't exist",status=404)

    #     keygen = generateKey()
    #     key = base64.b32encode(keygen.returnValue(phone).encode()) # Generating Key
    #     OTP = pyotp.HOTP(key) # HOTP Model
    #     instance = OtpModel.objects.get(pk=Mobile.pk)
    #     print(instance)
    #     if (OTP.verify(instance.otp,Mobile.counter)): # Verifying the OTP
    #         Mobile.isVerified = True
    #         Mobile.save()
    #         return Response('you are authorized',status=200)
    #     return Response('OTP is Wrong',status=404)

#EXAMPLE

# import random
# import string

# # get random string password with letters, digits, and symbols
# def get_random_password_string(length):
#     password_characters = string.ascii_letters + string.digits + string.punctuation
#     password = ''.join(random.choice(password_characters) for i in range(length))
#     print("Random string password is:", password)

# get_random_password_string(10)
# get_random_password_string(10)

#OUTPUT
# Random string password is: "C:!|]@|sh
# Random string password is: 'Q^s2q!t-N


import cv2
import numpy as np
import math
from enum import Enum

class CalibrationStep(Enum):
	ASKING_FOR_POINTS = 1
	DONE = 2

corners = []
img = None
gray = None
obj_points = np.matrix([[0.0, 0.0, 0.0], [2.0, 0.0, 0.0], [0.0, 2.0, 0.0], [2.0, 2.0, 0.0], [1.0, 1.0, 0.0]], np.float32) # list of points in real coords
img_points = [] # list of points in image coords

point_idx_ask = 0 # o indice do ponto que se está a pedir
calibration_step = CalibrationStep.ASKING_FOR_POINTS

def ask_for_point():
	print("Select point " + str(point_idx_ask))
	print(obj_points[point_idx_ask])

def point_selected(point):
	global point_idx_ask, calibration_step, img_points

	img_points.append(point)
	point_idx_ask += 1

	if point_idx_ask == len(obj_points):
		calibrate_camera()
		calibration_step = CalibrationStep.DONE
		print("DONE!")
	else:
		ask_for_point()

def find_closest_corner(x, y):
	closestIndex = -1
	closestDist = -1
	for i, corner in enumerate(corners):
		dist = math.sqrt((corner[0]-x)**2 + (corner[1]-y)**2)
		if closestIndex == -1 or closestDist > dist:
			closestIndex = i
			closestDist = dist
	return closestIndex

def img_window_click(event, x, y, flags, param):
	if event == cv2.EVENT_LBUTTONUP:
		print(calibration_step)
		if calibration_step == CalibrationStep.ASKING_FOR_POINTS:

			clickedCornerIdx = find_closest_corner(x, y)
			print(corners[clickedCornerIdx])

			cv2.circle(img, (corners[clickedCornerIdx][0], corners[clickedCornerIdx][1]), 3, (0,0,255), -1)
			cv2.imshow('image',img)

			point_selected(corners[clickedCornerIdx])

def find_corners():
	global gray
	gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

	#find Harris corners
	gray = np.float32(gray)

	dst = cv2.cornerHarris(gray,2,3,0.04)
	dst = cv2.dilate(dst,None)
	ret, dst = cv2.threshold(dst,0.01*dst.max(),255,0)
	dst = np.uint8(dst)

	#find centroids
	ret, labels, stats, centroids = cv2.connectedComponentsWithStats(dst)

	#define the criteria to stop and refine the corners
	criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 0.001)
	return cv2.cornerSubPix(gray,np.float32(centroids),(7,7),(-1,-1),criteria)

def calibrate_camera():
	#print(np.array([np.array(obj_points, np.float32)]).asmatrix())
	img_points_np = np.matrix(img_points, np.float32)
	print(img_points_np)

	ret, cameraMatrix, distCoeffs, rvec, tvec = cv2.calibrateCamera([obj_points], [img_points_np], gray.shape[::-1],None,None)
	print(ret)
	print(cameraMatrix)
	print(rvec)
	print(tvec)

	print("\n\n")
	rotMatrix, jacobian = cv2.Rodrigues(rvec[0])

	rtMatrix = np.concatenate((rotMatrix, tvec[0]), axis=1)

	print("Camera matrix:")
	print(cameraMatrix.tolist())
	print("R|t matrix:")
	print(rtMatrix.tolist())

filename = 'a.png'
img = cv2.imread(filename)

corners = find_corners()
print(obj_points)
#here u can get corners
print (corners[0])
print (len(corners))

#Now draw them
#res = np.hstack((centroids,corners))
#res = np.int0(res)
#img[res[:,1],res[:,0]]=[0,0,255]
#img[res[:,3],res[:,2]] = [0,255,0]
cv2.imshow('image',img)
cv2.setMouseCallback("image", img_window_click)
ask_for_point()

cv2.waitKey(0)
cv2.destroyAllWindows()


from django.shortcuts import render
from rest_framework import viewsets
from rest_framework.response import Response
from api.models import RideOffer
from api.models import RideSeek
from api.models import Search
from api.models import Filter
from api.serializers import RideOfferSerializer
from api.serializers import RideSeekSerializer
from api.serializers import SearchSerializer
from api.serializers import FilterSerializer
from django_filters import rest_framework as filters

# Create your views here.

class RideOfferFilter(filters.FilterSet):
    class Meta:
        model = RideOffer
        fields = {
            'from_u' : ['icontains'],
            'to_u' : ['icontains'],
            'when_u' : ['lte', 'gte'],
            'cost_u' : ['lte'],
        }

class RideOfferViewSet(viewsets.ModelViewSet):
    queryset = RideOffer.objects.all()
    serializer_class = RideOfferSerializer
    filterset_class = RideOfferFilter
    #def list(self, request):   inherets this from modelviewset

class RideSeekFilter(filters.FilterSet):
    class Meta:
        model = RideSeek
        fields = {
            'from_u' : ['icontains'],
            'to_u' : ['icontains'],
            'when_u' : ['lte', 'gte'],
        }

class RideSeekViewSet(viewsets.ModelViewSet):
    queryset = RideSeek.objects.all()
    serializer_class = RideSeekSerializer
    filterset_class = RideSeekFilter

class SearchViewSet(viewsets.ModelViewSet):
    queryset = Search.objects.all()
    serializer_class = SearchSerializer

class FilterViewSet(viewsets.ModelViewSet):
    queryset = Filter.objects.all()
    serializer_class = FilterSerializer


from django.test import TestCase

from couchdbkit import ResourceNotFound

from corehq.apps.commtrack.tests.util import (
    TEST_DOMAIN,
    bootstrap_domain,
    bootstrap_products,
)
from corehq.apps.commtrack.util import make_program
from corehq.apps.products.models import Product, SQLProduct
from corehq.apps.programs.models import Program

class ProgramsTest(TestCase):
    def test_programs(self):
        self.domain = bootstrap_domain(TEST_DOMAIN)
        self.addCleanup(self.domain.delete)
        bootstrap_products(self.domain.name)
        self.products = sorted(Product.by_domain(self.domain.name), key=lambda p: p._id)
        self.default_program = Program.by_domain(self.domain.name).one()
        self.new_program = make_program(
            self.domain.name,
            'new program',
            'newprogram'
        )
        self.assertTrue(self.default_program.default)
        self.assertFalse(self.new_program.default)

        with self.assertRaises(Exception) as context:
            self.default_program.delete()

        self.assertEqual(str(context.exception), 'You cannot delete the default program')

        # assign some product to the new program
        self.products[0].program_id = self.new_program._id
        self.products[0].save()

        # make sure start state is okay
        self.assertEqual(
            2,
            len(Program.by_domain(self.domain.name))
        )
        self.assertEqual(2, self.default_program.get_products_count())
        self.assertEqual(1, self.new_program.get_products_count())
        self.assertEqual(
            self.new_program._id,
            self.products[0].program_id
        )
        self.assertEqual(
            self.new_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )

        # stash the id before we delete
        new_program_id = self.new_program._id
        self.new_program.delete()

        with self.assertRaises(ResourceNotFound):
            Program.get(new_program_id)

        self.assertEqual(1, len(Program.by_domain(self.domain.name)))
        self.assertEqual(3, self.default_program.get_products_count())
        self.assertEqual(
            self.default_program._id,
            Product.get(self.products[0]._id).program_id
        )
        self.assertEqual(
            self.default_program._id,
            SQLProduct.objects.get(product_id=self.products[0]._id).program_id
        )


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri July 31 17:35:32 2020

@author: vivekmodi
"""

import pandas as pd, sys, os, gzip, argparse
from Bio import PDB

from Kincore.modules.assign_default_values import assign_default_values
from Kincore.modules.extract_sequence import extract_seq
from Kincore.modules.run_hmmsearch import run_hmmsearch
from Kincore.modules.identify_restypes import identify_restypes
from Kincore.modules.identify_group import identify_group
from Kincore.modules.identify_residues import identify_residues
from Kincore.modules.compute_distance import compute_distance
from Kincore.modules.compute_dihedrals import compute_dihedrals
from Kincore.modules.chelix import chelix_conformation
from Kincore.modules.spatial_label import spatial_label
from Kincore.modules.dihedral_label import dihedral_label
from Kincore.modules.delete_files import delete_files
from Kincore.modules.extract_ligands import extract_ligands
from Kincore.modules.classify_ligands import classify_ligands

def read_inputlist(hmm_loc,pdbfilename,align,user_chain,user_lys,user_glu,user_phe,header):     #Function to read input file list
    fhandle_files=open(pdbfilename,'r')
    for names in fhandle_files:
        name=names.strip();names=names.split()
        identify_state(hmm_loc,name,align,user_chain,user_lys,user_glu,user_phe,header)
        header=1

def print_header_withoutgroup(pdbfilename,index,conf_df):       #Print Header when align=False
    print('Input'.rjust(len(pdbfilename)+1)+'Model'.rjust(6)+'Chain'.rjust(6)+'Spatial_label'.rjust(14)+\
          'Dihedral_label'.rjust(15)+'C-helix_label'.rjust(14)+'X-DFG Φ Ψ'.center(22)+'DFG-Asp Φ Ψ'.center(22)+'DFG-Phe Φ Ψ χ1'.center(30))

def print_header_withgroup(pdbfilename,index,conf_df):    #Print Header when align=True
    print('Input'.rjust(len(pdbfilename)+1)+'Group'.rjust(6)+'Model'.rjust(6)+'Chain'.rjust(6)+'Spatial_label'.rjust(14)+\
    'Dihedral_label'.rjust(15)+'C-helix_label'.rjust(14)+'Ligand'.rjust(len(conf_df.at[index,'Ligand'])+1)+'Ligand_label'.rjust(len(conf_df.at[index,'Ligand_label'])+9)+\
    'X-DFG Φ Ψ'.center(22)+'DFG-Asp Φ Ψ'.center(22)+'DFG-Phe Φ Ψ χ1'.center(30))

def identify_state(pwd,pdbfilename,align,user_chain,user_lys,user_glu,user_phe,header):
    conf_df=pd.DataFrame()
    chain_list=list()

    if '.gz' in pdbfilename.lower():      #Check if the file is compressed
        handle=gzip.open(pdbfilename,'rt')
    else:
        handle=open(pdbfilename,'r')

    if '.cif' in pdbfilename.lower():
            parser=PDB.MMCIFParser(QUIET=True)
    if '.pdb' in pdbfilename.lower():
            parser=PDB.PDBParser(QUIET=True)

    structure=parser.get_structure(pdbfilename, handle)

    if align.upper()=='FALSE':
        for model in structure:
            index=int(model.id)
            conf_df.at[index,'Model_id']=int(model.id)
            for chain in model:
                for chains in list(user_chain.split(',')):
                    if chain.id==chains:       #Match user chain with chain in structure
                        conf_df.at[index,'Chain_id']=chain.id
                        conf_df=assign_default_values(index,conf_df)
                        conf_df.at[index,'Lys_num']=int(user_lys)
                        conf_df.at[index,'Glu_num']=int(user_glu)
                        conf_df.at[index,'Glu4_num']=int(user_glu)+4
                        conf_df.at[index,'Phe_num']=int(user_phe)
                        conf_df.at[index,'XDFG_num']=int(user_phe)-2
                        conf_df.at[index,'Asp_num']=int(user_phe)-1
                        conf_df=identify_restypes(pdbfilename,conf_df,index,structure)
                        conf_df=compute_distance(pdbfilename,index,conf_df,structure)
                        conf_df=compute_dihedrals(pdbfilename,index,conf_df,structure)
                        conf_df=spatial_label(index,conf_df)
                        conf_df=dihedral_label(index,conf_df,0.45)
                        conf_df=chelix_conformation(index,conf_df)
                        if header==0:
                            print_header_withoutgroup(pdbfilename,index,conf_df)
                            header=1
                        xdfg_string=str(str(int(conf_df.at[index,'XDFG_num']))+conf_df.at[index,'XDFG_restype'])
                        asp_string=str(str(int(conf_df.at[index,'Asp_num']))+conf_df.at[index,'Asp_restype'])
                        phe_string=str(str(int(conf_df.at[index,'Phe_num']))+conf_df.at[index,'Phe_restype'])
                        print(pdbfilename.rjust(len(pdbfilename)+1)+str(int(conf_df.at[index,'Model_id'])).rjust(6)+conf_df.at[index,'Chain_id'].rjust(6)+\
                              conf_df.at[index,'Spatial_label'].rjust(14)+conf_df.at[index,'Dihedral_label'].rjust(15)+conf_df.at[index,'Chelix'].rjust(14)+\
                              xdfg_string.rjust(6)+str('%.2f' %conf_df.at[index,'XDFG_Phi']).rjust(8)+str('%.2f' %conf_df.at[index,'XDFG_Psi']).rjust(8)+\
                              asp_string.rjust(6)+str('%.2f' %conf_df.at[index,'Asp_Phi']).rjust(8)+str('%.2f' %conf_df.at[index,'Asp_Psi']).rjust(8)+phe_string.rjust(6)+str('%.2f' %conf_df.at[index,'Phe_Phi']).rjust(8)+\
                              str('%.2f' %conf_df.at[index,'Phe_Psi']).rjust(8)+str('%.2f' %conf_df.at[index,'Phe_Chi1']).rjust(8))

    elif align.upper()=='TRUE':
        index=-1
        for model in structure:
            for chain in model:
                if len(chain.get_list())<=30:
                    continue
                chain_list.append(chain.id)
                index+=1

                for residue in chain:
                    if residue.id[2]!=' ':
                        print(f'{pdbfilename} Please enter a structure file without insertion codes.')
                        sys.exit()
                conf_df.at[index,'Model_id']=str(model.id)
                conf_df.at[index,'Chain_id']=chain.id
                conf_df=assign_default_values(index,conf_df)

                conf_df=extract_seq(pdbfilename,index,conf_df)
                run_hmmsearch(pwd,pdbfilename,index,conf_df)
                conf_df=identify_group(pdbfilename,index,conf_df)

                if conf_df.at[index,'Group']=='None':
                    delete_files(pdbfilename,conf_df.at[index,'Model_id'],conf_df.at[index,'Chain_id'], conf_df.at[index,'Group'])

                else:
                    conf_df=identify_residues(pdbfilename,index,conf_df)
                    if conf_df.at[index,'Lys_restype']=='X' or conf_df.at[index,'Glu_restype']=='X' or conf_df.at[index,'Phe_restype']=='X' or conf_df.at[index,'XDFG_restype']=='X' or conf_df.at[index,'Asp_restype']=='X':
                        #print('#'+pdbfilename.rjust(13)+conf_df.at[index,'Group'].rjust(6)+str(int(conf_df.at[index,'Model_id'])).rjust(6)+conf_df.at[index,'Chain_id'].rjust(6)+'       Conserved residues missing in the structure.')
                        delete_files(pdbfilename,conf_df.at[index,'Model_id'],conf_df.at[index,'Chain_id'], conf_df.at[index,'Group'])

                    else:
                        conf_df=compute_distance(pdbfilename,index,conf_df,structure)
                        conf_df=compute_dihedrals(pdbfilename,index,conf_df,structure)
                        conf_df=chelix_conformation(index,conf_df)
                        conf_df=spatial_label(index,conf_df)
                        conf_df=dihedral_label(index,conf_df,0.45)
                        conf_df=chelix_conformation(index,conf_df)
                        conf_df=extract_ligands(pdbfilename,index,conf_df,structure)
                        try:
                            conf_df=classify_ligands(pdbfilename,index,conf_df,structure)
                        except:
                            conf_df.at[index,'Ligand_label']='Error'

                        if header==0:
                            print_header_withgroup(pdbfilename,index,conf_df)
                            header=1

                        xdfg_string=str(str(int(conf_df.at[index,'XDFG_num']))+conf_df.at[index,'XDFG_restype'])
                        asp_string=str(str(int(conf_df.at[index,'Asp_num']))+conf_df.at[index,'Asp_restype'])
                        phe_string=str(str(int(conf_df.at[index,'Phe_num']))+conf_df.at[index,'Phe_restype'])
                        print(pdbfilename.rjust(len(pdbfilename)+1)+conf_df.at[index,'Group'].rjust(6)+conf_df.at[index,'Model_id'].rjust(6)+conf_df.at[index,'Chain_id'].rjust(6)+\
                        # conf_df.at[index,'Spatial_label'].rjust(14)+conf_df.at[index,'Dihedral_label'].rjust(15)+conf_df.at[index,'Chelix'].rjust(14)+conf_df.at[index,'Ligand'].rjust(len(conf_df.at[index,'Ligand'])+1)+\
                        # conf_df.at[index,'Ligand_label'].rjust(len(conf_df.at[index,'Ligand_label'])+9)+xdfg_string.rjust(6)+str('%.2f' %conf_df.at[index,'XDFG_Phi']).rjust(8)+str('%.2f' %conf_df.at[index,'XDFG_Psi']).rjust(8)+\
                        # asp_string.rjust(6)+str('%.2f' %conf_df.at[index,'Asp_Phi']).rjust(8)+str('%.2f' %conf_df.at[index,'Asp_Psi']).rjust(8)+phe_string.rjust(6)+str('%.2f' %conf_df.at[index,'Phe_Phi']).rjust(8)+\
                        # str('%.2f' %conf_df.at[index,'Phe_Psi']).rjust(8)+str('%.2f' %conf_df.at[index,'Phe_Chi1']).rjust(8))
                        str('%.3f' %conf_df.at[index,'Glu4-Phe-dis']).rjust(8)+str('%.3f' %conf_df.at[index,'Lys-Phe-dis']).rjust(8))

                        delete_files(pdbfilename,conf_df.at[index,'Model_id'],conf_df.at[index,'Chain_id'],conf_df.at[index,'Group'])

        for i in conf_df.index:
            if conf_df.at[i,'Group']=='None':
                print(f'# {pdbfilename} Model {conf_df.at[i,"Model_id"]} Chain {conf_df.at[i,"Chain_id"]} is probably not a protein kinase.')
            if conf_df.at[i,'Group']!='None' and (conf_df.at[i,'Lys_restype']=='X' or conf_df.at[i,'Glu_restype']=='X' or conf_df.at[i,'Phe_restype']=='X' or conf_df.at[i,'XDFG_restype']=='X' or conf_df.at[i,'Asp_restype']=='X'):
                print(f'# {pdbfilename} Model {conf_df.at[i,"Model_id"]} Chain {conf_df.at[i,"Chain_id"]} is missing the required residues.')

    return conf_df

if __name__ == '__main__':
    hmm_loc=os.path.dirname(os.path.realpath(__file__))+'/HMMs'    #gets the original location of the file
    parser=argparse.ArgumentParser()
    parser.add_argument('PDB',help='PDB file in .cif or .pdb format. You can also provide compressed file as file.cif.gz or file.pdb.gz or list of filenames in a .txt file.')
    parser.add_argument('Align',help='True/False; If "True" (Slower) then the program will align the input protein sequence to pre-computed HMMs and identify conserved \
                        residues to determine kinase conformational labels and ligand type (Example $python kinase_state.py 1GAG.pdb True).\
                        If "False" (Faster) then please provide the optional arguments (Example $python kinase_state.py -L 1030 -G 1047 -P 1151 -C A,B,C 1GAG.pdb False). Please note that \
                        the program can provide ligand information only when this argument is True.')

    parser.add_argument('-L','--Lys',help='Residue number of the conserved B3-Lys in the input PDB file')
    parser.add_argument('-G','--Glu',help='Residue number of the conserved C-helix-Glu in the input PDB file')
    parser.add_argument('-P','--Phe',help='Residue number of the conserved DFG-Phe in the input PDB file')
    parser.add_argument('-C','--Chain',type=str,help='Chain id of the protein kinase chain in the input file')
    args=parser.parse_args()

    pdbfilename=args.PDB
    if args.Align.upper()=='TRUE':
        user_chain=user_lys=user_glu=user_phe=align=''
    else:
        if not args.Lys or not args.Glu or not args.Phe or not args.Chain:
            print('Please provide residue numbers and chain id.')
            exit()
        else:
            user_chain=str(args.Chain);user_lys=int(args.Lys);user_glu=int(args.Glu);user_phe=int(args.Phe)

    header=0
    if '.txt' in pdbfilename:
        read_inputlist(hmm_loc,pdbfilename,args.Align,user_chain,user_lys,user_glu,user_phe,header)
    else:
        identify_state(hmm_loc,pdbfilename,args.Align,user_chain,user_lys,user_glu,user_phe,header)


from time import time
from pathlib import Path
import random, os, warnings
from collections import OrderedDict

import numpy as np

import nltk
from nltk.tokenize import sent_tokenize, word_tokenize
import gensim

from .core import Transform

from tqdm import tqdm

class Word2Vec(Transform):
    """
    Transform for Word2Vec so we can train Word2Vec on our dataset and use it as a transform

    We do this using nltk and gensim.models.Word2Vec

    Parameters
    ----------
    text_dir: String
        Directory of the text files we want to do this on
    dim: Integer
        Dimensionality of the Word2Vec embeddings
    workers: Integer
        Number of workers to use to train the Word2Vec
    """
    def __init__(self, text_dir, dim = 128, workers = 10):
        self.text_dir = text_dir
        self.dim = dim
        self.workers = workers

    def train(self):
        # Start training the Word2Vec
        # First create a list of files
        self.file_list = [s for s in list(Path(self.text_dir).rglob("*.txt"))]

        # Now read and tokenize
        print('Loading texts')
        self.sentences = ' '.join([Path(fn).read_text() for fn in tqdm(self.file_list)])
        print('Tokenising texts')
        self.sentences = [word_tokenize(sent.lower()) for sent in tqdm(sent_tokenize(self.sentences))] # Lower case everything

        # I've commented this section out because we could usep pretrained stuff but they may not have the vocabulary we need
        #word2vec_sample = str(nltk.data.find('models/word2vec_sample/pruned.word2vec.txt'))
        #self.model = gensim.models.KeyedVectors.load_word2vec_format(word2vec_sample, binary=False)]

        # Need to set min_count = 1, so we can deal with words we onyl encounter once if we have to
        print('Training Word2Vec model')
        self.model = gensim.models.Word2Vec(self.sentences, size = self.dim, workers = self.workers, min_count = 1)
        print('Done')

    def __call__(self, x): # We expect the input to be a string of sentences
        # Don't need to split it into sentences then into words, tokenising every word is enough
        sentence = word_tokenize(x.lower())

        out = np.zeros((len(sentence), self.dim), dtype = np.float32)
        for i, w in enumerate(sentence):
            out[i] = self.model[w]
        return out

    def save(self, fn):
        self.model.save(fn)

    def load(self, fn):
        self.model = Word2Vec.load(fn)

    def __repr__(self):
        format_string = self.__class__.__name__ + '('
        format_string += 'text_dir={0}'.format(self.text_dir)
        format_string += 'dim={0}'.format(self.dim)
        format_string += 'workers={0}'.format(self.workers)
        format_string += ')'
        return format_string

class Char2Vec(Transform):
    """
    Simple transform to convert ASCII characters to integers or one hot

    Parameters
    ----------
    one_hot: Boolean
        Whether to output the data in one hot format
    """
    def __init__(self, one_hot = False):
        self.one_hot = one_hot

    def __call__(self, x):
        if self.one_hot:
            out = np.zeros((len(x), 256), dtype = np.long) # Fix dimensionality to 256 for 8bit ASCII
            for i, c in enumerate(x):
                out[i, ord(c)] = 1 # Convert to 1 hot
        else:
            out = np.zeros((len(x),), dtype = np.long)
            for i, c in enumerate(x):
                out[i] = ord(c)

        return out


from dependencies.dependency import getSecurityManager
from dependencies.dependency import aq_inner
from lims import logger
from lims.interfaces import IRoutineAnalysis
from lims.subscribers import doActionFor
from lims.subscribers import skip
from lims.utils import changeWorkflowState
from dependencies.dependency import DateTime
from dependencies.dependency import REFERENCE_CATALOG
from dependencies.dependency import ObjectInitializedEvent
from dependencies.dependency import getToolByName
from dependencies.dependency import WorkflowException
from dependencies import transaction
from dependencies.dependency import event
from dependencies.dependency import alsoProvides

def ObjectInitializedEventHandler(instance, event):

    # This handler fires for DuplicateAnalysis because
    # DuplicateAnalysis also provides IAnalysis.
    # DuplicateAnalysis doesn't have analysis_workflow.
    if instance.portal_type == "DuplicateAnalysis":
        return

    if instance.portal_type == 'Analysis':
        alsoProvides(instance, IRoutineAnalysis)

    workflow = getToolByName(instance, 'portal_workflow')

    ar = instance.aq_parent
    ar_state = workflow.getInfoFor(ar, 'review_state')
    ar_ws_state = workflow.getInfoFor(ar, 'worksheetanalysis_review_state')

    # Set the state of the analysis depending on the state of the AR.
    if ar_state in ('sample_registered',
                    'to_be_sampled',
                    'sampled',
                    'to_be_preserved',
                    'sample_due',
                    'sample_received'):
        changeWorkflowState(instance, "bika_analysis_workflow", ar_state)
    elif ar_state in ('to_be_verified'):
        # Apply to AR only; we don't want this transition to cascade.
        if 'workflow_skiplist' not in ar.REQUEST:
            ar.REQUEST['workflow_skiplist'] = []
        ar.REQUEST['workflow_skiplist'].append("retract all analyses")
        workflow.doActionFor(ar, 'retract')
        ar.REQUEST['workflow_skiplist'].remove("retract all analyses")

    if ar_ws_state == 'assigned':
        workflow.doActionFor(ar, 'unassign')
        skip(ar, 'unassign', unskip=True)

    instance.updateDueDate()

    return

def ObjectRemovedEventHandler(instance, event):

    # This handler fires for DuplicateAnalysis because
    # DuplicateAnalysis also provides IAnalysis.
    # DuplicateAnalysis doesn't have analysis_workflow.
    if instance.portal_type == "DuplicateAnalysis":
        return

    # May need to promote the AR's review_state
    #  if all other analyses are at a higher state than this one was.
    workflow = getToolByName(instance, 'portal_workflow')
    ar = instance.aq_parent
    can_submit = True
    can_attach = True
    can_verify = True
    can_publish = True

    # We add this manually here, because during admin/ZMI removal,
    # it may possibly not be added by the workflow code.
    if not 'workflow_skiplist' in instance.REQUEST:
        instance.REQUEST['workflow_skiplist'] = []

    for a in ar.getAnalyses():
        a_state = a.review_state
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',):
            can_submit = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received', 'attachment_due',):
            can_attach = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified',):
            can_verify = False
        if a_state in \
           ('to_be_sampled', 'to_be_preserved',
            'sample_due', 'sample_received',
            'attachment_due', 'to_be_verified', 'verified',):
            can_publish = False

    # Note: AR adds itself to the skiplist so we have to take it off again
    #       to allow multiple promotions (maybe by more than one deleted instance).
    if can_submit and workflow.getInfoFor(ar, 'review_state') == 'sample_received':
        try:
            workflow.doActionFor(ar, 'submit')
        except WorkflowException:
            pass
        skip(ar, 'submit', unskip=True)
    if can_attach and workflow.getInfoFor(ar, 'review_state') == 'attachment_due':
        try:
            workflow.doActionFor(ar, 'attach')
        except WorkflowException:
            pass
        skip(ar, 'attach', unskip=True)
    if can_verify and workflow.getInfoFor(ar, 'review_state') == 'to_be_verified':
        instance.REQUEST["workflow_skiplist"].append('verify all analyses')
        try:
            workflow.doActionFor(ar, 'verify')
        except WorkflowException:
            pass
        skip(ar, 'verify', unskip=True)
    if can_publish and workflow.getInfoFor(ar, 'review_state') == 'verified':
        instance.REQUEST["workflow_skiplist"].append('publish all analyses')
        try:
            workflow.doActionFor(ar, 'publish')
        except WorkflowException:
            pass
        skip(ar, 'publish', unskip=True)

    ar_ws_state = workflow.getInfoFor(ar, 'worksheetanalysis_review_state')
    if ar_ws_state == 'unassigned':
        if not ar.getAnalyses(worksheetanalysis_review_state = 'unassigned'):
            if ar.getAnalyses(worksheetanalysis_review_state = 'assigned'):
                try:
                    workflow.doActionFor(ar, 'assign')
                except WorkflowException:
                    pass
                skip(ar, 'assign', unskip=True)

    return


"""
The model definitions for the social app
"""

from pathlib import Path

from playhouse.dataset import DataSet

HERE = Path(__file__).parent

DEFAULT_DB_NAME = HERE / "social.db"

def get_dataset(filename=None, clear=False):
    """
    setup and return a database to use for the models

    :param filename: name of DB file, or ":memory:" for in=memory temp DB

    :param clear=False: Whether to clear out the old db and return an
                        empty one.

    :returns: PeeWee Dataset object
    """

    if filename == ":memory:":
        dataset = DataSet('sqlite:///:memory:')
    else:  # pragma: no cover (not used in tests)
        if filename is None:
            filename = DEFAULT_DB_NAME
        if clear:
            Path(filename).unlink(missing_ok=True)
        dataset = DataSet(f'sqlite:///{filename}')

    # note: limitations not implimented yet

    # * The ``Users`` table will have the following fields:
    #     * user_id (Primary Key, limited to 30 characters).
    #     * user_name (Limited to 30 characters).
    #     * user_last_name (Limited to 100 characters).
    #     * user_email.
    # * The ``Status`` table will have these fields:
    #     * status_id (Primary Key).
    #     * user_id (Foreign Key from the ``Users`` table).
    #     * status_text.

    # set up the user's table
    users = dataset['users']
    # insert a dummy record to get the table set up
    users.insert(user_id='temp',
                 user_name='ausername',
                 user_last_name='Example',
                 user_email='example@nothing.com')
    # create index to make user_id unique
    users.create_index(['user_id'], unique=True)
    # Delete the dummy record afterwards.
    users.delete(user_id='temp')

    statuses = dataset['statuses']
    # insert a dummy record to get the table set up
    statuses.insert(status_id='temp',
                    user_id='xxx',
                    status_text='an example status message')
    # create index to make status_id unique
    statuses.create_index(['status_id'], unique=True)
    # Delete the dummy record afterwards.
    statuses.delete(status_id='temp')

    return dataset

# class User(BaseModel):
#     """
#     Model for the users in the socialnetwork
#     """
#     user_id = pw.CharField(primary_key=True, max_length=30)
#     user_name = pw.CharField(max_length=30)
#     user_last_name = pw.CharField(max_length=100)
#     user_email = pw.CharField()

# class UserStatus(BaseModel):
#     """
#     Model for the status messages
#     """
#     status_id = pw.CharField(primary_key=True, max_length=30)
#     user_id = pw.ForeignKeyField(model=User,
#                                  field='user_id',
#                                  backref='status_messages',
#                                  on_delete='CASCADE',
#                                  )
#     status_text = pw.TextField()


import logging
import json

from flask import request, jsonify

from codeitsuisse import app

logger = logging.getLogger(__name__)

@app.route('/tickerStreamPart1', methods = ['POST'])
def ticker1():
    data = request.get_json()
    logging.info("data sent for evaluation {}".format(data))
    stream = data.get("stream")
    cumu_list = {}
    grouped_list = {}
    ret_list = []
    for data in stream:
        ticks = data.split(",")
        curr_time = ticks[0]
        if curr_time not in grouped_list:
            grouped_list[curr_time] = data[6:]
        else:
            grouped_list[curr_time] += f';{data[6:]}'
    grouped_list = sorted(grouped_list.items()
                          )  # A dict sorted by timestamp with ticks as values
    for i in grouped_list:
        ticks = i[1].split(";")
        ticks.sort(key = lambda x: x[0])  # sort ticker by alphabet
        ret = f'{i[0]},'
        for j in range(len(ticks)):
            tick = ticks[j]
            tick = tick.split(",")
            ticker = tick[0]
            quantity = int(tick[1])
            notion = round(float(tick[2]), 1)
            if ticker not in cumu_list:
                cumu_list[ticker] = [quantity, round(notion * quantity, 1)]
            else:
                cumu_list[ticker][0] += quantity
                cumu_list[ticker][1] += round(quantity * notion, 1)
            ret += f'{ticker},{cumu_list[ticker][0]},{round(cumu_list[ticker][1], 1)}'
            if j != len(ticks) - 1:
                ret += ","
        ret_list.append(f'{ret}')
    logging.info("My result :{}".format(ret_list))
    result = { "output": ret_list}
    return json.dumps(result)

@app.route('/tickerStreamPart2', methods = ['POST'])
def ticker2():
    data = request.get_json()
    logging.info("data sent for evaluation {}".format(data))
    stream = data.get("stream")
    quantity_block = data.get("quantityBlock")
    data = []
    for stuffs in stream:
        ticks = stuffs.split(",")
        data.append(ticks)
    data.sort(key = lambda x: x[0])
    pairs = []
    cumu_list = {}
    for ticks in data:
        time = ticks[0]
        ticker = ticks[1]
        quantity = int(ticks[2])
        notion = round(float(ticks[3]), 1)
        original_floor = 0
        if ticker not in cumu_list:
            cumu_list[ticker] = [time, quantity, notion * quantity]
        else:  # Adding true q and n before applying q_block
            original_floor = cumu_list[ticker][1] // quantity_block  # if q=11, b=5, then of=2
            cumu_list[ticker][1] += quantity
            cumu_list[ticker][2] += quantity * notion
        new_floor = cumu_list[ticker][1] // quantity_block  # if q=16, b=5, then of=3
        if (new_floor != original_floor):
            adj_quantity = cumu_list[ticker][
                               1] // quantity_block * quantity_block
            adj_notion = cumu_list[ticker][2] - (cumu_list[ticker][1] %
                                                 quantity_block * notion)
            # use new floor (q = 15)

            pairs.append([time, ticker, adj_quantity, round(adj_notion, 1)])
    ret_dict = {}
    for i in pairs:
        time = i[0]
        if i[0] not in ret_dict:
            ret_dict[time] = [[i[1], i[2], i[3]]]
        else:
            ret_dict[time].append([i[1], i[2], i[3]])
        ret_dict[time].sort(key = lambda x: x[0])
    ret_list = []
    for i in ret_dict.keys():
        ret_str = f'{i},'
        for j in range(len(ret_dict[i])):
            if j != len(ret_dict[i]) - 1:
                for k in ret_dict[i][j]:
                    ret_str += f'{k},'
            else:
                for k in range(len(ret_dict[i][j])):
                    if k != len(ret_dict[i][j]) - 1:
                        ret_str += f'{ret_dict[i][j][k]},'
                    else:
                        ret_str += f'{ret_dict[i][j][k]}'
        ret_list.append(ret_str)
    logging.info("My result :{}".format(ret_list))
    result = { "output": ret_list}
    return json.dumps(result)


import json
from pathlib import Path

class PathEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Path):
            return str(obj)
        # Let the base class default method raise the TypeError
        return json.JSONEncoder.default(self, obj)


import stripe
from django.conf import settings
# Create your views here.
from django.shortcuts import redirect, render

def home(request):
    template_name = 'payments/pages/home.html'
    stripe.api_key = settings.STRIPE_SECRET_KEY
    return render(request, template_name)

def charge(request):
    if request.method == 'POST':
        checkout_session = stripe.checkout.Session.create(
            line_items=[
                {
                    'price': 'price_1MCqakASQv92CGV2YGc5bOYM',
                    'quantity': 1,
                },
            ],
            mode='payment',
            success_url='http://localhost:8000',
            cancel_url='http://localhost:8000',
        )
        return redirect(checkout_session.url, code=303)


#!/usr/bin/env python

from fabric.api import run
from cloudify import ctx

def retrieve_file_content(file_name):
    ctx.logger.info("In retrieve_file_content file_name is {0} ...".format(file_name))
    command = "cat {0}".format(file_name)
    ctx.logger.info("Command is {0}".format(command))
    curr_output = run(command)
    ctx.logger.info("Command output is {0}".format(curr_output))
    ctx.instance.runtime_properties[file_name] = curr_output
    ctx.logger.info("Command output is stored in rt.{0} {1}".format(file_name, curr_output))
    ctx.logger.info("End of retrieve_file_content ...")

# https://github.com/cloudify-examples/clearwater-nfv-blueprint/blob/e004a11122398f1b38f3e5187362b25059dd4aa2/types/clearwater.yaml
#https://github.com/cloudify-examples/simple-kubernetes-blueprint/blob/a5ea7c3a81241f0350d7c25112bdfe930b7c5384/imports/kubernetes.yaml

#ssh -i ~/.ssh/nec_aws15_11.pem -o 'IdentitiesOnly yes' centos@13.125.3.21

#cfy exe start execute_operation -d $dep -p operation=utils.get_file_content --allow-custom-parameters -p node_ids=CentOS7
#cfy exe start execute_operation -d $dep -p operation=utils.get_file_content --allow-custom-parameters -p node_ids=CentOS7 -p "{'operation_kwargs':{'task_properties':{'file_name':'/home/centos/111.222'}}}" -p allow_kwargs_override=true
#export file_name=/home/centos/111.222
#cfy exe start execute_operation -d $dep -p operation=utils.get_file_content --allow-custom-parameters -p node_ids=CentOS7 -p "{'operation_kwargs':{'task_properties':{'file_name':'${file_name}'}}}" -p allow_kwargs_override=true