# Copyright 2020 Forrest Sheng Bao
# GNU GPL v3.0 or later

import operator
import numpy, sklearn, sklearn.tree

def estimate_gini_impurity(feature_values, threshold, labels, polarity):
	"""Compute the gini impurity for comparing a feature value against a threshold under a given polarity

	feature_values: 1D numpy array, feature_values for samples on one feature dimension
	threshold: float
	labels: 1D numpy array, the label of samples, only +1 and -1.
	polarity: operator type, only operator.gt or operator.le are allowed

	Examples
	-------------
	>>> feature_values = numpy.array([1,2,3,4,5,6,7,8])
	>>> labels = numpy.array([+1,+1,+1,+1, -1,-1,-1,-1])
	>>> for threshold in range(0,8):
	...	 estimate_gini_impurity(feature_values, threshold, labels, operator.gt)
	0.5
	0.489795918367347
	0.4444444444444444
	0.31999999999999984
	0.0
	0.0
	0.0
	0.0
	>>> for threshold in range(0,8):
	...	 estimate_gini_impurity(feature_values, threshold, labels, operator.le)
	1.0
	0.0
	0.0
	0.0
	0.0
	0.31999999999999984
	0.4444444444444445
	0.48979591836734704
	"""

	# YOUR CODE HERE
	# 						  Gini impurity per node:
	# 				  1 - (numYes/numTot)^2 - (numNo/numTot)^2
	#								      OR
	#   (numYes/numTot)(1 - numYes/numTot) + (numNo/numTot)(1 - numNo/numTot)

	#		Avg = (#Node1 / #Tot)*Node1Score + (#Node2 / #Tot)*Node2Score

	a = polarity(feature_values, threshold)
	length = sum(a)
	numYes = sum(numpy.logical_and(a, labels == +1))
	numNo  = length - numYes

	if(length == 0):
		#return numpy.finfo(float).eps
		return 1.0

	gini_impurity = (float(numYes)/length)*(1-numYes/length) + (float(numNo)/length)*(1-numNo/length)

	return gini_impurity

def estimate_gini_impurity_expectation(feature_values, threshold, labels):
	"""Compute the expectation of gini impurity given the feature values on one  feature dimension and a threshold

	feature_values: 1D numpy array, feature_values for samples on one feature dimension
	threshold: float
	labels: 1D numpy array, the label of samples, only +1 and -1.

	Examples
	---------------
	>>> feature_values = numpy.array([1,2,3,4,5,6,7,8])
	>>> labels = numpy.array([+1,+1,+1,+1, -1,-1,-1,-1])
	>>> for threshold in range(0,9):
	...	 estimate_gini_impurity_expectation(feature_values, threshold, labels)
	0.5
	0.4285714285714286
	0.3333333333333333
	0.1999999999999999
	0.0
	0.1999999999999999
	0.33333333333333337
	0.42857142857142866
	0.5

	"""

	# YOUR CODE HERE

	g1 = estimate_gini_impurity(feature_values, threshold, labels, operator.gt)
	g2 = estimate_gini_impurity(feature_values, threshold, labels, operator.le)

	numYes = sum(operator.gt(feature_values, threshold))
	totNum = len(feature_values)

	expectation = (numYes/totNum)*g1 + ((totNum - numYes)/totNum)*g2

	return expectation

def midpoint(x):
	"""Given a sequqence of numbers, return the middle points between every two consecutive ones.
	>>> x= numpy.array([1,2,3,4,5])
	>>> (x[1:] + x[:-1]) / 2
	array([1.5, 2.5, 3.5, 4.5])
	"""
	return (x[1:] + x[:-1]) / 2

def grid_search_split_midpoint(X, y):
	"""Given a dataset, compute the gini impurity expectation for all pairs of features and thresholds.

	Inputs
	----------
		X: 2-D numpy array, axis 0 or row is a sample, and axis 1 or column is a feature
		y: 1-D numpy array, the labels, +1 or -1

	Returns
	---------
		grid: 2-D numpy array, axis 0 or row is a threshold, and axis 1 or column is a feature

	Examples
	-------------
	>>> numpy.random.seed(1) # fix random number generation starting point
	>>> X = numpy.random.randint(1, 10, (8,3)) # generate training samples
	>>> y = numpy.array([+1,+1,+1,+1, -1,-1,-1,-1])
	>>> grid, feature_id, bts = grid_search_split_midpoint(X, y)
	>>> print (grid)
	[[0.42857143 0.5		0.46666667]
	 [0.46666667 0.5		0.46666667]
	 [0.46666667 0.46666667 0.46666667]
	 [0.375	  0.5		0.46666667]
	 [0.5		0.5		0.46666667]
	 [0.5		0.5		0.5	   ]
	 [0.5		0.42857143 0.42857143]]
	>>> clf = sklearn.tree.DecisionTreeClassifier(max_depth=1)
	>>> clf = clf.fit(X,y)
	>>> print (clf.tree_.feature[0], clf.tree_.threshold[0], feature_id, bts)
	0 7.0 0 7.0
	>>> print(clf.tree_.feature[0] == feature_id)
	True
	>>> print( clf.tree_.threshold[0] == bts)
	True

	>>> # Antoher test case
	>>> numpy.random.seed(2) # fix random number generation starting point
	>>> X = numpy.random.randint(1, 30, (8,3)) # generate training samples
	>>> grid, feature_id, bts = grid_search_split_midpoint(X, y)
	>>> print (grid)
	[[0.42857143 0.42857143 0.42857143]
	 [0.5		0.5		0.33333333]
	 [0.375	  0.46666667 0.46666667]
	 [0.375	  0.5		0.5	   ]
	 [0.46666667 0.46666667 0.46666667]
	 [0.33333333 0.5		0.5	   ]
	 [0.42857143 0.42857143 0.42857143]]
	>>> clf = clf.fit(X,y) # return the sklearn DT
	>>> print (clf.tree_.feature[0], clf.tree_.threshold[0], feature_id, bts)
	2 8.5 2 8.5
	>>> print(clf.tree_.feature[0] == feature_id)
	True
	>>> print( clf.tree_.threshold[0] == bts)
	True

	>>> # yet antoher test case
	>>> numpy.random.seed(4) # fix random number generation starting point
	>>> X = numpy.random.randint(1, 100, (8,3)) # generate training samples
	>>> grid, feature_id, bts = grid_search_split_midpoint(X, y)
	>>> print (grid)
	[[0.42857143 0.42857143 0.42857143]
	 [0.5		0.5		0.33333333]
	 [0.46666667 0.46666667 0.375	 ]
	 [0.375	  0.375	  0.375	 ]
	 [0.46666667 0.2		0.46666667]
	 [0.5		0.42857143 0.5	   ]
	 [0.42857143 0.42857143 0.42857143]]
	>>> clf = clf.fit(X,y) # return the sklearn DT
	>>> print (clf.tree_.feature[0], clf.tree_.threshold[0], feature_id, bts)
	1 47.5 1 47.5
	>>> print(clf.tree_.feature[0] == feature_id)
	True
	>>> print( clf.tree_.threshold[0] == bts)
	True
	"""

	X_sorted = numpy.sort(X, axis=0)
	thresholds = numpy.apply_along_axis(midpoint, 0, X_sorted)

	# YOUR CODE HERE

	grid = []

	for i in range(len(X.T)):
		features = X.T[i]
		thresh = thresholds.T[i]
		temp = []

		for threshold in thresh:
			temp.append(estimate_gini_impurity_expectation(features, threshold, y))

		grid.append(temp)

	grid = numpy.array(grid).T

	minIndex = numpy.argmin(grid)
	minX = minIndex % len(grid[0])
	minY = (int)(minIndex / len(grid[0]))

	best_feature = minX
	best_threshold = thresholds[minY][minX]

	return grid, best_feature, best_threshold

def you_rock(N, R, d):
	"""
	N: int, number of samples, e.g., 1000.
	R: int, maximum feature value, e.g., 100.
	d: int, number of features, e.g., 3.

	"""
	numpy.random.seed() # re-random the seed
	hits = 0
	for _ in range(N):
		X = numpy.random.randint(1, R, (8,d)) # generate training samples
		y = numpy.array([+1,+1,+1,+1, -1,-1,-1,-1])
		_, feature_id, bts = grid_search_split_midpoint(X, y)
		clf = sklearn.tree.DecisionTreeClassifier(max_depth=1)
		clf = clf.fit(X,y)

		if clf.tree_.feature[0] == feature_id and clf.tree_.threshold[0] == bts:
			hits += 1
	print ("your Decision tree is {:2.2%} consistent with Scikit-learn's result.".format(hits/N))

if __name__ == "__main__":
	import doctest
	doctest.testmod()
	you_rock(1000, 100, 3)

'''
feature_values = numpy.array([1,2,3,4,5,6,7,8])
labels = numpy.array([+1,+1,+1,+1, -1,-1,-1,-1])
for threshold in range(0, 9):
	print( estimate_gini_impurity(feature_values, threshold, labels, operator.gt) )

X = numpy.random.randint(1, 10, (8,3)) # generate training samples
y = numpy.array([+1,+1,+1,+1, -1,-1,-1,-1])
grid, feature_id, bts = grid_search_split_midpoint(X, y)

'''


from azure.data.tables import TableClient
import logging
from . import config

def connect_to_table_service() -> TableClient:
    """
    Connects to an Azure Table  client and returns the TableClient object.
    """
    table_client = TableClient.from_connection_string(conn_str=config.storage_connection_string, table_name=config.storage_table_name)
    try:
       table_client.create_table()
       logging.debug("Created table")
    except:
        logging.info("Table already exists or unable to create table")
    return table_client

def store_dicts_in_table(data_list: list):
    """
    Stores a list of dictionaries in an Azure Table using batch operations.
    """
    table_client = connect_to_table_service()
    operations = []
    for i, data in enumerate(data_list):
        operation = ('upsert', data)
        operations.append(operation)
        if (i+1) % 99 == 0 or (i+1) == len(data_list):
            try:
                table_client.submit_transaction(operations)
                operations = []
            except Exception as e:
                logging.info(operations)
                logging.info(str(e))


from django.db import migrations

from constructor import models

JSON_PATH = [
    'CPU',
    'MOTHERBOARDS',
    'VIDEO CARDS',
    'RAMS',
    'COOLERS',
    'HDD',
    'DVD',
    'CASES POWER'
]

def add_category_to_db(apps, schema_editor):
    for key in JSON_PATH:
        models.Category.objects.create(
            name=key
        )

class Migration(migrations.Migration):
    dependencies = [
        ('constructor', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(add_category_to_db)
    ]


# -*- coding: utf-8 -*-
""" This script is used to optimize the parameters which are inferred from
non-dividing traces under the EM algorithm.
Update : Script deprecated since no parameter except the coupling is optimized
using EM. """
""""""""""""""""""""" MODULE IMPORT """""""""""""""""""""
### Import external modules
import pickle
import numpy as np
import sys
import copy
import matplotlib
import os
matplotlib.use('Agg') #to run the script on a distant server
import matplotlib.pyplot as plt

sys.path.insert(0, os.path.realpath('..'))
sys.path.insert(0, os.path.realpath('../Classes'))
sys.path.insert(0, os.path.realpath('../Functions'))

### Import internal modules
from Classes.LoadData import LoadData
from Classes.HMM_SemiCoupled import HMM_SemiCoupled
from Classes.PlotResults import PlotResults
import Classes.EM as EM

###Import internal functions
from Functions.signal_model import signal_model
from Functions.create_hidden_variables import create_hidden_variables
from Functions.display_parameters import display_parameters_from_file
from Functions.clean_waveform import clean_waveform

#access main directory
os.chdir('..')
""""""""""""""""""""" LOAD SHELL ARGUMENTS """""""""""""""""
try:
    nb_iter = int(sys.argv[1])
    nb_traces = int(sys.argv[2])
    size_block = int(sys.argv[3])
    cell = sys.argv[4]
    if sys.argv[5]=="None":
        temperature = None
    else:
        temperature = int(sys.argv[5])
except:
    print("No shell input given, default arguments used")
    nb_iter = 15
    nb_traces = 1000
    size_block = 100
    cell = 'NIH3T3'
    temperature = None

""""""""""""""""""""" LOAD INIT GUESS PARAMETERS """""""""""""""""
path = 'Parameters/Real/init_parameters_nodiv_'+str(temperature)+"_"+cell+".p"
with open(path, 'rb') as f:
    l_parameters = [dt, sigma_em_circadian, W, pi,
    N_theta, std_theta, period_theta, l_boundaries_theta, w_theta,
    N_phi, std_phi, period_phi, l_boundaries_phi, w_phi,
    N_amplitude_theta, mu_amplitude_theta, std_amplitude_theta,
    gamma_amplitude_theta, l_boundaries_amplitude_theta,
    N_background_theta, mu_background_theta, std_background_theta,
    gamma_background_theta, l_boundaries_background_theta,
    F] = pickle.load(f)

""""""""""""""""""""" DISPLAY PARAMETERS """""""""""""""""
display_parameters_from_file(path, show = False)

""""""""""""""""""""" CREATE HIDDEN VARIABLES """""""""""""""""
theta_var_coupled, amplitude_var, background_var \
                        = create_hidden_variables(l_parameters = l_parameters )
""""""""""""""""""""" LOAD DATA """""""""""""""""
if cell == 'NIH3T3':
    path =  "Data/NIH3T3.ALL.2017-04-04/ALL_TRACES_INFORMATION.p"
    dataClass=LoadData(path, nb_traces, temperature = temperature,
                        division = False)
else:
    path = "Data/U2OS-2017-03-20/ALL_TRACES_INFORMATION_march_2017.p"
    dataClass=LoadData(path, nb_traces, temperature = temperature,
                        division = True) #all thz U2OS divide

(ll_area_tot_flat, ll_signal_tot_flat, ll_nan_circadian_factor_tot_flat,
    ll_obs_phi_tot_flat, T_theta, T_phi) = dataClass.load()
print(len(ll_signal_tot_flat), " traces kept")

""""""""""""""""""""" CREATE BLOCK OF TRACES """""""""""""""""
ll_area_tot = []
ll_signal_tot = []
first= True
#print(ll_area_tot_flat)
#print(ll_signal_tot_flat)

for index, (l_area, l_signal) in enumerate(zip(ll_area_tot_flat,
                                                ll_signal_tot_flat)):
    if index%size_block==0:
        if not first:
            ll_area_tot.append(ll_area)
            ll_signal_tot.append(ll_signal)

        else:
            first = False
        ll_area = [l_area]
        ll_signal = [l_signal]
    else:
        ll_area.append(l_area)
        ll_signal.append(l_signal)
#get remaining trace
ll_area_tot.append(ll_area)
ll_signal_tot.append(ll_signal)

""""""""""""""""""""" OPTIMIZATION """""""""""""""""
lP=0
l_lP=[]
l_idx_to_remove = []
for it in range(nb_iter):
    print("Iteration :", it)
    l_jP_phase = []
    l_jP_amplitude = []
    l_jP_background = []
    l_gamma = []
    l_gamma_0 = []
    l_logP = []
    ll_signal_hmm = []

    """ CLEAN TRACES AFTER FIRST ITERATION """
    if it==1:
        ll_signal_tot_flat = ll_signal_hmm_clean
        print("nb traces apres 1ere iteration : ", len(ll_signal_tot_flat))
        ll_signal_tot = []
        first= True
        for index, l_signal in enumerate( ll_signal_tot_flat):
            if index%size_block==0:
                if not first:
                    ll_signal_tot.append(ll_signal)
                else:
                    first = False
                ll_signal = [l_signal]
            else:
                ll_signal.append(l_signal)
        #get remaining trace
        ll_signal_tot.append(ll_signal)

    for ll_signal in ll_signal_tot:

        """ INITIALIZE AND RUN HMM """
        l_var = [theta_var_coupled, amplitude_var, background_var]
        hmm=HMM_SemiCoupled(l_var, ll_signal, sigma_em_circadian,
                            ll_val_phi = [], waveform = W ,  pi = pi,
                            crop = False )
        (l_gamma_0_temp, l_gamma_temp ,l_logP_temp,  ll_alpha,  ll_beta, l_E,
            ll_cnorm, ll_idx_phi_hmm_temp, ll_signal_hmm_temp,
            ll_nan_circadian_factor_temp) = hmm.run_em()

        #create ll_mat_TR
        ll_mat_TR = [np.array([theta_var_coupled.TR_no_coupling \
                        for i in gamma_temp]) for gamma_temp in l_gamma_temp ]

        """ PLOT TRACE EXAMPLE """
        zp = zip(enumerate(ll_signal_hmm_temp),l_gamma_temp, l_logP_temp)
        for (idx, signal), gamma, logP in zp:
            plt_result = PlotResults(gamma, l_var, signal_model, signal,
                                    waveform = W, logP = None,
                                    temperature = temperature, cell = cell)
            plt_result.plotEverythingEsperance(False, idx)
            if idx==0:
                break

        l_jP_phase_temp, l_jP_amplitude_temp,l_jP_background_temp \
            = EM.compute_jP_by_block(ll_alpha, l_E, ll_beta, ll_mat_TR,
                                    amplitude_var.TR, background_var.TR,
                                    N_theta, N_amplitude_theta,
                                    N_background_theta)
        l_jP_phase.extend(l_jP_phase_temp)
        l_jP_amplitude.extend(l_jP_amplitude_temp)
        l_jP_background.extend(l_jP_background_temp)
        l_gamma.extend(l_gamma_temp)
        l_logP.extend(l_logP_temp)
        l_gamma_0.extend(l_gamma_0_temp)
        ll_signal_hmm.extend(ll_signal_hmm_temp)

    t_l_jP = (l_jP_phase, l_jP_amplitude,l_jP_background)

    """ REMOVE BAD TRACES IF FIRST ITERATION"""
    if it==0:
        Plim = np.percentile(l_logP, 10)
        #Plim = -10000
        for idx_trace, P in enumerate(l_logP):
            if P<=Plim:
                l_idx_to_remove.append(idx_trace)
        for index in sorted(l_idx_to_remove, reverse=True):
            del t_l_jP[0][index]
            del t_l_jP[1][index]
            del t_l_jP[2][index]
            del l_gamma[index]
            del l_logP[index]
            del l_gamma_0[index]
            del ll_signal_hmm[index]
        ll_signal_hmm_clean = copy.deepcopy(ll_signal_hmm)

    """ PARAMETERS UPDATE """
    ll_idx_obs_phi = None
    [F_up, pi_up, std_theta_up, sigma_em_circadian_up, ll_coef,
    std_amplitude_theta_up, std_background_theta_up, mu_amplitude_theta_up,
    mu_background_theta_up, W_up] = EM.run_EM(l_gamma_0, l_gamma, t_l_jP,
                                              theta_var_coupled, ll_idx_obs_phi,
                                              F, ll_signal_hmm,  amplitude_var,
                                              background_var, W,
                                              ll_idx_coef = None )

    if np.mean(l_logP)-lP<10**-9:
        print("diff:", np.mean(l_logP)-lP)
        print(print("average lopP:", np.mean(l_logP)))
        break
    else:
        lP = np.mean(l_logP)
        print("average lopP:", lP)
        l_lP.append(lP)

    """ PLOT WAVEFORM """
    plt.plot(theta_var_coupled.domain, W_up)
    plt.xlabel('Circadian phase')
    plt.ylabel(r'$W(\theta)$')
    plt.ylim([-0.1,1.5])
    plt.show()
    plt.close()

    """ CHOOSE NEW PARAMETERS """

    cond_F = False
    cond_pi = False
    cond_std_theta = False
    cond_sigma_em_circadian = False
    cond_std_amplitude_theta = False
    cond_std_background_theta = False
    cond_mu_amplitude_theta = False
    cond_mu_background_theta = False
    cond_W = False

    """ PUT ITERATION CONDITIONS ON THE UPDATE """
    [cond_it_F, cond_it_pi, cond_it_std_theta, cond_it_sigma_em_circadian,
    cond_it_std_amplitude_theta, cond_it_std_background_theta,
    cond_it_mu_amplitude_theta, cond_it_mu_background_theta, cond_it_W] \
                    = [False,False,False,False,False,False,False,False,False]

    '''
    if it>=0:   cond_it_F = True
    if it>=18:   cond_it_pi = True
    if it>=25:   cond_it_std_theta = True
    if it>=18:   cond_it_sigma_em_circadian = True
    if it>=10:   cond_it_std_amplitude_theta = True
    if it>=14:   cond_it_std_background_theta = True
    if it>=10:   cond_it_mu_amplitude_theta = True
    if it>=14:   cond_it_mu_background_theta = True
    if it>=0:   cond_it_W = True
    '''

    if it>=0:   cond_it_F = True
    if it>=0:   cond_it_pi = True
    if it>=0:   cond_it_std_theta = True
    if it>=0:   cond_it_sigma_em_circadian = True
    if it>=0:   cond_it_std_amplitude_theta = True
    if it>=0:   cond_it_std_background_theta = True
    if it>=0:   cond_it_mu_amplitude_theta = True
    if it>=0:   cond_it_mu_background_theta = True
    if it>=0:   cond_it_W = True

    """ REINPUT NEW PARAMETERS """
    if cond_F and cond_it_F:
        F = F_up
    if cond_pi and cond_it_pi:
        pi = pi_up
    #block simga_theta to 0.2 to keep good inference
    if cond_std_theta and cond_it_std_theta and std_theta_up<0.2:
        std_theta = std_theta_up
    #block sigma_e to 0.1 to prevent divergence
    if cond_sigma_em_circadian and cond_it_sigma_em_circadian \
                                                and sigma_em_circadian_up>0.:
        sigma_em_circadian = sigma_em_circadian_up
    if cond_std_amplitude_theta and cond_it_std_amplitude_theta:
        std_amplitude_theta = std_amplitude_theta_up
    if cond_std_background_theta and cond_it_std_background_theta:
        std_background_theta = std_background_theta_up
    if cond_mu_amplitude_theta and cond_it_mu_amplitude_theta:
        mu_amplitude_theta = mu_amplitude_theta_up
    if cond_mu_background_theta and cond_it_mu_background_theta:
        mu_background_theta = mu_background_theta_up
    if cond_W and cond_it_W:
        W = W_up

    #redefine boundaries OU process if first iterations
    if it<10:
        l_boundaries_amplitude_theta = (mu_amplitude_theta-5*std_amplitude_theta,
                                    mu_amplitude_theta+5*std_amplitude_theta)
    if it<14:
        l_boundaries_background_theta = (mu_background_theta\
                                    -5*std_background_theta,
                                    mu_background_theta+5*std_background_theta)

    l_parameters = [dt, sigma_em_circadian, W, pi,
    N_theta, std_theta, period_theta, l_boundaries_theta, w_theta,
    N_phi, std_phi, period_phi, l_boundaries_phi, w_phi,
    N_amplitude_theta, mu_amplitude_theta, std_amplitude_theta,
    gamma_amplitude_theta, l_boundaries_amplitude_theta,
    N_background_theta, mu_background_theta, std_background_theta,
     gamma_background_theta, l_boundaries_background_theta,
    F]

    theta_var_coupled, amplitude_var, background_var \
                        = create_hidden_variables(l_parameters = l_parameters)

plt.plot(l_lP)
plt.savefig("Parameters/Real/opt_parameters_nodiv_"+str(temperature)+"_"\
                                                                +cell+'.pdf')
#plt.show()
plt.close()

""""""""""""""""""""" RENORMALIZE WAVEFORM AND UPDATE PARAMETERS """""""""""""""
W = clean_waveform(W)

l_parameters = [dt, sigma_em_circadian, W, pi,
N_theta, std_theta, period_theta, l_boundaries_theta, w_theta,
N_phi, std_phi, period_phi, l_boundaries_phi, w_phi,
N_amplitude_theta, mu_amplitude_theta, std_amplitude_theta,
gamma_amplitude_theta, l_boundaries_amplitude_theta,
N_background_theta, mu_background_theta, std_background_theta,
gamma_background_theta, l_boundaries_background_theta,
F]

""""""""""""""""""""" WRAP PARAMETERS """""""""""""""""
path = "Parameters/Real/opt_parameters_nodiv_"+str(temperature)+"_"+cell+".p"
pickle.dump( l_parameters, open( path, "wb" ) )
""""""""""""""""""""" DISPLAY PARAMETERS """""""""""""""""
display_parameters_from_file(path, show = True)


import torch
import torch.nn as nn
import torch.nn.functional as F

def gumbel_softmax(logits, temperature, gpu_id=None, hard=False):
    if gpu_id:
        gumbel = torch.distributions.Gumbel(torch.zeros(logits.shape).cuda(gpu_id), torch.ones(logits.shape).cuda(gpu_id))
    else:
        gumbel = torch.distributions.Gumbel(torch.zeros(logits.shape), torch.ones(logits.shape))

    if hard:
        n_classes = logits.size(-1)
        z = torch.argmax(logits + gumbel.sample(), dim=-1)
        return F.one_hot(z, n_classes).float()
    else:
        return F.softmax((logits + gumbel.sample()) / temperature, dim=-1)

class Gumbel_Softmax_VAE(nn.Module):
    def __init__(self, img_dim, K, N, temperature, init_weights=True, gpu_id=None):
        super(Gumbel_Softmax_VAE, self).__init__()
        self.encoder = nn.Sequential(nn.Linear(img_dim, 512), nn.ReLU(),
                                     nn.Linear(512, 256), nn.ReLU(),
                                     nn.Linear(256, N*K))
        self.decoder = nn.Sequential(nn.Linear(N*K, 256), nn.ReLU(),
                                     nn.Linear(256, 512), nn.ReLU(),
                                     nn.Linear(512, img_dim), nn.Sigmoid())

        self.K, self.N, self.temperature = K, N, temperature
        self.gpu = gpu_id

        if init_weights: self._initialize_weights()
        if gpu_id: torch.cuda.set_device(self.gpu)

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Linear):
                nn.init.kaiming_normal_(m.weight, nonlinearity='relu')
                nn.init.constant_(m.bias, 0)

    def sample(self, logits, temperature):
        if self.training: return gumbel_softmax(logits, temperature, self.gpu, hard=False)
        else: return gumbel_softmax(logits, temperature, self.gpu, hard=True)

    def forward(self, x):
        x = self.encoder(x)
        logits = F.softmax(x.view(-1, self.N, self.K), dim=-1)
        sample = self.sample(torch.log(logits+1e-10), self.temperature).view(-1, self.N*self.K)
        output = self.decoder(sample)
        return output, logits


# -*- coding: utf-8 -*-
"""
Created on Wed May 10 15:28:38 2017

@author: whisp
"""
# Prob 4
import numpy as np
import matplotlib.pyplot as plt

r = np.linspace(10,250,100000)
y = np.zeros(100000)
alpha = 60
beta = 120

for i in range(len(r)):
    r_ = r[i]
    y[i] = max(((r_-alpha)/(r_+alpha))**2, ((r_-beta)/(r_+beta))**2)

plt.plot(r,y)
print(np.sqrt(alpha*beta))
print(r[np.argmin(y)])
print(np.sqrt(alpha*beta)-r[np.argmin(y)])

#%%
import numpy as np
import matplotlib.pyplot as plt

steps = 100000
error1 = np.ndarray([steps])
n = 10
b = np.ones(n)
x = np.random.randn(n)
x0 = x
A = np.ndarray([n, n])
for i in range(n):
    for j in range(n):
        A[i, j] = 1/(i + j +1)

# True answer
ans = np.linalg.solve(A, b)
plt.figure()

# Single-Step method=SSM=Gauss-Seidel method
for step in range(steps):
    for j in range(n):
        sum1 = 0
        for i in range(n):
            if i != j:
                sum1 += A[j, i] * x[i]
        x[j] = (-sum1 + b[j])/A[j, j]
    error1[step] = max(ans - x)
print(ans - x)
plt.plot(range(steps),error1, label="Gauss-Seidel")

# Total-Step method=TSM=Jacobi method

x = x0 # Start from the same initial point
error2 = np.ndarray([steps])
for step in range(steps):
    x_old = x
    for j in range(n):
        sum1 = 0
        sum2 = 0
        for i in range(n):
            if i < j:
                sum1 += A[j, i] * x[i]
            if i > j:
                sum2 += A[j, i] * x_old[i]
        x[j] = (- sum1 - sum2 + b[j])/A[j, j]
    error2[step] = max(ans - x)
print(ans - x)
plt.plot(range(steps),error2, label="Jacobi")

# Relaxation Methods
omega = 1.2
x = x0 # Start from the same initial point
error3 = np.ndarray([steps])
for step in range(steps):
    x_old = x
    for j in range(n):
        sum1 = 0
        for i in range(n):
            if i != j:
                sum1 += A[j, i] * x[i]
        x[j] = x_old[j] + omega * ((-sum1 + b[j])/A[j, j] - x_old[j])
    error3[step] = max(ans - x)
print(ans - x)

plt.xlabel('steps')
plt.ylabel('error')
plt.title('Comparasion of convergence n=%d' % n)
plt.plot(range(steps),error3, label='Relaxation')
plt.legend()
plt.savefig('n%d-all.pdf' % n)

plt.figure()
plt.xlabel('steps')
plt.ylabel('error')
plt.subplot(211)
plt.title('Comparasion of convergence n=%d' % n)
plt.plot(range(steps),error1, 'C0', label="Gauss-Seidel")
plt.plot(range(steps),error2, 'C1', label="Jacobi")
plt.legend()

plt.subplot(212)
plt.plot(range(steps),error2, 'C1', label="Jacobi")
plt.plot(range(steps),error3, 'C2', label='Relaxation')
plt.legend()
plt.savefig('n%d.pdf' % n)

# Relaxation Methods
plt.figure()
for omega in np.asarray([1.1, 1.2, 1.8]):
    x = x0 # Start from the same initial point
    error3 = np.ndarray([steps])
    for step in range(steps):
        x_old = x
        for j in range(n):
            sum1 = 0
            for i in range(n):
                if i != j:
                    sum1 += A[j, i] * x[i]
            x[j] = x_old[j] + omega * ((-sum1 + b[j])/A[j, j] - x_old[j])
        error3[step] = max(ans - x)
    print(ans - x)
    plt.plot(range(steps),error3, label = 'omega = %2.1f' % omega)
plt.title('Comparasion of omega n=%d' % n)
plt.xlabel('steps')
plt.ylabel('error')
plt.legend()
plt.savefig('omega n%d.pdf' % n)


#example
#등차수열 제너레이터

class ArithmeticProgression:
	def __init__(self, begin, step, end=None):
		self.begin=begin
		self.step=step
		self.end=end #none: infinite

	def __iter__(self):
		result=type(self.begin+self.step)(self.begin) #int(object)와 같은 것임. self.begin+self.step의 자료형으로 self.begin을 형변환한다
		forever=self.end is None
		index=0
		while forever or result<self.end:
			yield result
			index +=1
			result=self.begin+self.step*index

#for test #ArithmeticProgression(begin, step[, end])
ap=ArithmeticProgression(0,1,3)
assert list(ap)==[0,1,2]
ap=ArithmeticProgression(1,.5,3)
assert list(ap)==[1.0, 1.5, 2.0, 2.5]
ap=ArithmeticProgression(0,1/3,1)
assert list(ap)==[0,1/3,2/3]
from fractions import Fraction
ap=ArithmeticProgression(0,Fraction(1,3),1)
assert list(ap)==[Fraction(0,1),Fraction(1,3),Fraction(2,3)]
from decimal import Decimal
ap=ArithmeticProgression(0,Decimal('.1'),.3)
assert list(ap)==[Decimal('0.0'),Decimal('0.1'),Decimal('0.2')]

#그런데 위와 같은 일 하려면 그냥 제너레이터 함수 하나 만들면 됨
def aritprog_gen(begin, step, end=None):
	result=type(begin+step)(begin)
	forever=end is None
	index=0
	while forever or result<end:
		yield result
		index +=1
		result=begin+step*index

#for test
ap=aritprog_gen(0,1,3) #(제너레이터 함수는 자체를 호출시에는 초기상태 반복자를 반환한다)
print(next(ap)) #0
print(next(ap)) #1
print(next(ap)) #2
ap=aritprog_gen(0,1,3)
print(list(ap)) #[0, 1, 2]

#itertools 모듈의 제너레이터 이용
import itertools
gen=itertools.count(1,0.5) #itertools.count(begin, step) #<-기본적으로 무한히 만들어낸다
print(next(gen)) #1
print(next(gen)) #1.5
print(next(gen)) #2.0

gen=itertools.takewhile(lambda n:n<3, itertools.count(1,0.5)) #itertools.takewhile(predicate, generator) #제너레이터를 소비하면서, predicate가 False가 되면 중단한다
print(list(gen)) #[1, 1.5, 2.0, 2.5]

def aritprog_gen_2(begin, step, end=None):
	first=type(begin+step)(begin)
	ap_gen=itertools.count(first,step)
	if end is not None:
		ap_gen=itertools.takewhile(lambda n:n<end, ap_gen)
	return ap_gen
	#yield가 없어서 제너레이터 함수는 아니지만, 리턴이 제너레이터이므로, 일종의 제너레이터 팩토리로 기능한다

#for test
ap=aritprog_gen_2(0,1,3)
print(list(ap))


import setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="iotdb-session-0.10.1",
    version="0.1.5",
    author="Julian Feinauer",
    author_email="j.feinauer@pragmaticminds.de",
    description="A small iotdb python client",
    long_description=long_description,
    long_description_content_type="text/markdown",
    url="https://github.com/JulianFeinauer/iotdb-session-py",
    packages=setuptools.find_packages(),
    classifiers=[
        "Programming Language :: Python :: 3",
        "License :: OSI Approved :: Apache Software License",
        "Operating System :: OS Independent",
    ],
    install_requires=[
        'apache-iotdb==0.10.1',
        'six==1.15.0',
        'thrift==0.13.0'''
    ],
    python_requires='>=3.6',
)


#!/usr/bin/python3
"""Testing file
"""
import json
import requests

if __name__ == "__main__":
    """ Get amenity_ids with name Wifi or Ethernet
    """
    r = requests.get("http://0.0.0.0:5000/api/v1/amenities")
    r_j = r.json()

    amenity_ids = []
    for amenity_j in r_j:
        if amenity_j.get('name') == "Wifi" or amenity_j.get('name') == "Ethernet":
            amenity_ids.append(amenity_j.get('id'))

    """ POST /api/v1/places_search
    """
    r = requests.post("http://0.0.0.0:5000/api/v1/places_search", data=json.dumps({ 'amenities': amenity_ids }), headers={ 'Content-Type': "application/json" })
    r_j = r.json()
    print(r_j)
    print(len(r_j))


# coding=utf-8

import re
from jinja2 import Environment, PackageLoader

class ViewModel(object):

    class Property(object):
        def __init__(self, name, type_name):
            super(ViewModel.Property, self).__init__()
            self.name = name
            self.type_name = type_name

        def __str__(self):
            return "let {}: Driver<{}>".format(self.name, self.type_name)

    def __init__(self, vm_text):
        super(ViewModel, self).__init__()
        self.vm_text = vm_text

    @property
    def view_model_name(self):
        try:
            regex = re.compile(r'(?:struct|extension) (\w+)ViewModel')
            mo = regex.search(self.vm_text)
            return mo.group(1)
        except Exception:
            print("The ViewModel in the pasteboard is invalid.")
            exit(1)

    @property
    def properties(self):
        try:
            str = self.vm_text

            # Input
            input_block_regex = re.compile("struct Input {([^}]+)")
            input_block = input_block_regex.search(str).group(1)
            input_properties_regex = re.compile(r'let (\w+): Driver<([^>]+)>')
            input_properties = [
                ViewModel.Property(p[0], p[1])
                for p in input_properties_regex.findall(input_block)
            ]

            # Output
            output_block_regex = re.compile("struct Output {([^}]+)")
            output_block = output_block_regex.search(str).group(1)
            output_properties_regex = re.compile(r'(?:let|var) (\w+)(?: =|:)(?:.*)')
            output_properties = [
                ViewModel.Property(p, 'Any')
                for p in output_properties_regex.findall(output_block)
            ]

            return (input_properties, output_properties)
        except Exception:
            print("The ViewModel in the pasteboard is invalid.")
            exit(1)

class UnitTest(ViewModel):

    def create_tests(self):
        input_properties, output_properties = self.properties
        env = Environment(
            loader=PackageLoader('igen_templates', 'commands'),
            trim_blocks=True,
            lstrip_blocks=True
        )
        template = env.get_template("UnitTest.swift")
        content = template.render(
            name=self.view_model_name,
            input_properties=input_properties,
            output_properties=output_properties
        )
        return content

class BindViewModel(ViewModel):

    def create_bind_view_model(self):
        input_properties, output_properties = self.properties
        env = Environment(
            loader=PackageLoader('igen_templates', 'commands'),
            trim_blocks=True,
            lstrip_blocks=True
        )
        template = env.get_template("BindViewModel.swift")
        content = template.render(
            name=self.view_model_name,
            input_properties=input_properties,
            output_properties=output_properties
        )
        return content


from django.urls import path
from book import views

urlpatterns = [
    path('addbook/',views.add),
    path('viewbook/',views.display),
    path('updatebook/<int:did>', views.updatebook),
    path('delete/<int:did>', views.delete),
    path('register/', views.registeruser, name='register'),
    path('login/', views.loginuser, name='login'),
    path('logout/', views.logoutuser, name='logout'),
    path('upcomingbook/', views.upcomingbook),
    path('updatebook/<str:id>', views.search, name='search'),
    path('contact/', views.contactus),
    path('about/', views.aboutus),
    path('htol/', views.htol),
    path('ltoh/', views.ltoh),
    path('AtoZ/', views.AtoZ),
    path('ZtoA/', views.ZtoA),
    path("AatoZz/",views.AatoZz),
    path("ZztoAa/",views.ZztoAa),
    path('lowtohigh/',views.lowtohigh),
    path('hightolow/',views.hightolow),
    path('CAtoZ/',views.CAtoZ),
    path('CZtoA/',views.CZtoA),
    path('catfilter/<str:cat>',views.catfilter)
]


from flask import Flask, render_template
app = Flask(__name__)

posts = [
    {
        'author': 'Reza Bojnordi',
        'title': 'Blog Post 1',
        'content': 'First post content',
        'data': 'April 20, 2018'
    },
    {
        'author': 'aria Bojnordi',
        'title': 'Blog Post 2',
        'content': 'Second post content',
        'data': 'April 21, 2018'
    }

]
@app.route("/")
@app.route("/home")

def home():
    return render_template("home.html", posts=posts)
    #return "
Home Page
"

@app.route("/about")
def about():
    return render_template("about.html", title="About")

if __name__ == "__main__":
    app.run(debug=True)


"""
hash_type.py
The heavy hitter of hashing.
"""
from __future__ import absolute_import

import six

from hashit.core.mappings.hashlib_mapping import HASHLIB_MAPPING
from hashit.core.mappings.custom_crc_mapping import CRCMOD_CUSTOM_MAPPING

class HashIt(object):
    """The object to preform hashing"""

    def __init__(self, hash_type=None, hash_data=None):
        self.hash_type = hash_type
        self.data = hash_data

    def next_chunk(self):
        """Hash the next chunk of data"""
        return self._hash(self.data.next_chunk())

    def hash_it(self, hash_type=None, hash_data=None):
        """Hash all of the data"""
        if hash_type is not None:
            self.hash_type = hash_type

        if hash_data is not None:
            self.data = hash_data

        return self._hash(self.data.next_chunk())

    def _hash(self, data):
        """Internal hashing mapping"""
        hash_str = ""
        data = self._sanatize_data(data)

        if self.hash_type in HASHLIB_MAPPING:
            hash_str = self._hashlib_hash(data)
        elif self.hash_type in CRCMOD_CUSTOM_MAPPING:
            hash_str = hex(CRCMOD_CUSTOM_MAPPING[self.hash_type](data))[
                2:].upper()
        else:
            raise NotImplementedError
        if len(hash_str) != self.hash_type.hash_str_length():
            hash_str = hash_str.zfill(self.hash_type.hash_str_length())
        return hash_str

    @staticmethod
    def _sanatize_data(data):
        """Temporary py2/py3 data helper"""
        if six.PY3:
            try:
                data = data.encode('utf-8')
            except (UnicodeDecodeError, AttributeError):
                pass
        else:
            data = str(data)
        return data

    def _hashlib_hash(self, data):
        """Internal hashing mapping specifically for hashlib like interfaces"""
        hasher = HASHLIB_MAPPING[self.hash_type]()
        hasher.update(data)
        return hasher.hexdigest().upper()


"""Class and methods to handle activity routes"""
import traceback
from fastapi import APIRouter
from services.activity_service import get_activity_list
from common.utils.logging_handler import Logger
from common.utils.http_exceptions import InternalServerError
from schemas.error_schema import (InternalServerErrorResponseModel,
                                  ValidationErrorResponseModel,
                                  UnauthorizedUserErrorResponseModel)

router = APIRouter(
  prefix="/activities",
  responses={
    500: {
      "model": InternalServerErrorResponseModel
    },
    422: {
      "model": ValidationErrorResponseModel
    },
    401: {
      "model": UnauthorizedUserErrorResponseModel
    }
  })

@router.get("")
def get_activities():
  """
  Endpoint to get activities
  """
  try:
    response = get_activity_list()
    return {
      "success": True,
      "message": "Successfully fetched all activities",
      "data": response
    }
  except Exception as e:
    Logger.error(e)
    Logger.error(traceback.print_exc())
    raise InternalServerError(str(e)) from e


import logging

_logger = logging.getLogger(__name__)
from openerp import api, exceptions, fields, models
import openerp.addons.decimal_precision as dp
from operator import attrgetter
from lxml import etree
from openerp.osv.orm import setup_modifiers
from openerp.exceptions import Warning, ValidationError
from openerp.tools.translate import _
from presupuesto_estructura import TIPO_DOCUMENTO

# TODO: GAP 126 SPRING 6
class grpCoreCotizacionSiif(models.Model):
    _inherit = 'grp.cotizaciones'

    def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
        res = super(grpCoreCotizacionSiif, self).fields_view_get(cr, uid, view_id=view_id, view_type=view_type,
                                                                 context=context,
                                                                 toolbar=toolbar, submenu=submenu)
        doc = etree.XML(res['arch'])
        if view_type == 'form':
            for field in res['fields']:
                node = doc.xpath("//field[@name='" + field + "']")[0]
                if field == 'estimate_ids':
                    readonly = (self.pool.get('res.users').has_group(cr, uid,
                                                                     'grp_seguridad.grp_compras_pc_Comprador')) or (
                               self.pool.get(
                                   'res.users').has_group(cr, uid, 'grp_seguridad.grp_compras_apg_Responsable_SIIF'))
                    node.set('readonly', '0' if readonly else '1')
                setup_modifiers(node, res['fields'][field])

        res['arch'] = etree.tostring(doc)
        return res

    # TODO Spring 6 GAP 126
    provider_ids = fields.One2many('grp.cotizaciones.proveedor.pesos', 'cot_id', string='Proveedor pesos')
    estimate_ids = fields.One2many('grp.cotizaciones.estimado.comprometer', 'cot_id', string='Estimado de comprometer')
    provider_compromise_ids = fields.One2many('grp.cotizaciones.compromiso.proveedor', 'cot_id', string='Compromisos')
    total_estimado = fields.Float(compute='get_total_pesos', string='Total estimado pesos',
                                  digits_compute=dp.get_precision('Cantidad'))

    # TODO Spring 7 GAP 440
    diff_apg_total_estimado = fields.Float(string="Diferencia entre APGs y total adjudicado",
                                           digits_compute=dp.get_precision('Cantidad'))

    partners_name = fields.Char('Nombre de proveedores', compute='_compute_partners_name', store=True)

    @api.multi
    @api.depends('provider_ids.provider_id')
    def _compute_partners_name(self):
        for rec in self:
            rec.partners_name = '; '.join([x.provider_id.name_get()[0][1] for x in rec.provider_ids])

    @api.multi
    def _set_provider_amount(self):
        for rec in self:
            rec.provider_ids.suspend_security().unlink()
            partner_dict = {}
            if len(rec.sice_page_aceptadas):
                for line in rec.sice_page_aceptadas:
                    if line.proveedor_cot_id.id not in partner_dict:
                        partner_dict[line.proveedor_cot_id.id] = {'total': 0}
                    partner_dict[line.proveedor_cot_id.id]['total'] += line.subtotal_pesos

            rec.suspend_security().write({'provider_ids': [(0, 0,
                                         {'provider_id': k, 'total_amount': round(v['total'])}) for k, v in
                                        partner_dict.iteritems()]})

    # TODO Spring 6 GAP 126
    @api.multi
    def _set_estimate(self):
        for rec in self:
            estimate = [(5,)]
            fiscalyear = False
            name_split = rec.name.split('-')
            if len(name_split) > 1:
                year = name_split[0]
                fiscalyear = self.env['account.fiscalyear'].search([('name', '=', year)]).id
            for line in rec.provider_ids:
                estimate.append((0, 0, {'fiscalyear_id': fiscalyear, 'provider_id': line.provider_id.id,
                                        'total_amount': round(line.total_amount)}))
            rec.suspend_security().write({'estimate_ids': estimate})

    # TODO Spring 6 GAP 126
    @api.multi
    def write(self, vals):
        _super = super(grpCoreCotizacionSiif, self).write(vals)
        if _super and vals.has_key('sice_page_aceptadas'):
            for rec in self:
                rec._set_provider_amount()
        return _super

    @api.model
    def create(self, vals):
        _super = super(grpCoreCotizacionSiif, self).create(vals)
        _super._set_provider_amount()
        return _super

    # TODO R Spring 6 GAP 126
    @api.multi
    def button_create_compromise(self):
        self.ensure_one()
        self.control_apg()
        return {
            'name': _("Crear compromiso"),
            'view_mode': 'form',
            'view_type': 'form',
            'res_model': 'grp.cotizaciones.comprometer.wizard',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'domain': '[]',
            'context': {
                'cot_id': self.id,

            }
        }

    # TODO Spring 7 GAP 440
    # TODO: R GAP 440
    @api.multi
    def control_apg(self):
        for rec in self:
            monto_apg = 0
            apg_ids = set(
                rec.page_apg.filtered(lambda x: x.state not in ['desafectado', 'rechazado', 'anulada']).mapped(
                    lambda apg: apg.id))
            apg_obj = self.env['grp.compras.apg'].browse(list(apg_ids))
            for apg in apg_obj:
                if apg.state == 'afectado':
                    for llave in apg.llpapg_ids:
                        monto_apg += llave.importe
                else:
                    if apg.moneda.id != apg.company_currency_id.id:
                        monto_apg += apg.monto_fnc
                    else:
                        monto_apg += apg.monto_divisa
            if round(rec.total_estimado) > monto_apg:
                raise Warning(
                    u"Para poder Comprometer una adjudicación, deben estar creadas todas las APG, incluidas las de años futuros por el total de la adjudicación")
            rec.write({'diff_apg_total_estimado': monto_apg - round(rec.total_estimado)})
        return True

    # RAGU action para actualizar la diferencia con la apg
    @api.multi
    def action_update_diff_apg_total_estimado(self):
        for rec in self:
            monto_apg = 0
            apg_ids = set(
                rec.page_apg.filtered(lambda x: x.state not in ['desafectado', 'rechazado', 'anulada']).mapped(
                    lambda apg: apg.id))
            apg_obj = self.env['grp.compras.apg'].browse(list(apg_ids))
            for apg in apg_obj:
                if apg.state == 'afectado':
                    for llave in apg.llpapg_ids:
                        monto_apg += llave.importe
                else:
                    if apg.moneda.id != apg.company_currency_id.id:
                        monto_apg += apg.monto_fnc
                    else:
                        monto_apg += apg.monto_divisa
            rec.write({'diff_apg_total_estimado': monto_apg - round(rec.total_estimado)})
        return True

    @api.one
    def act_cotizaciones_validado(self):
        to_return = super(grpCoreCotizacionSiif, self).act_cotizaciones_validado()
        self._set_estimate()
        return to_return

    #MVARELA 02/02/2018 se comenta control. incidencia=2098 Error control monto comprometido
    # # TODO: SPRING 8 GAP 125
    # @api.multi
    # def cotizaciones_in_authorization(self):
    #     for rec in self:
    #         if rec.provider_compromise_ids:
    #             compromises = rec.provider_compromise_ids.filtered(lambda x: x.state == 'committed')
    #             if not compromises:
    #                 raise exceptions.ValidationError(
    #                     (u'Se debe comprometer alguno de los compromisos antes de continuar con el proceso.'))
    #     return super(grpCoreCotizacionSiif, self).cotizaciones_in_authorization()

    @api.constrains('estimate_ids')
    def _check_estimate_amount(self):
        for rec in self:
            provider_dict = {}
            for obj in rec.estimate_ids:
                if obj.provider_id.id not in provider_dict:
                    provider_dict[obj.provider_id.id] = 0
                provider_dict[obj.provider_id.id] += obj.total_amount
                provider = rec.provider_ids.filtered(lambda x: x.provider_id.id == obj.provider_id.id)
                if not len(provider) or provider.total_amount < provider_dict[obj.provider_id.id]:
                    raise exceptions.ValidationError(
                        u'La suma por proveedor-año fiscal no debe superar el total adjudicado por proveedor en pesos.')

    @api.multi
    @api.depends('provider_ids')
    def get_total_pesos(self):
        for rec in self:
            total_estimado = 0
            for provider in rec.provider_ids:
                total_estimado += round(provider.total_amount)
            rec.total_estimado = total_estimado

# TODO Spring 6 GAP 126
class grpCotizacionesLineasAceptadas(models.Model):
    _inherit = 'grp.cotizaciones.lineas.aceptadas'

    subtotal_pesos = fields.Float(compute='_get_subtotal_pesos', digits_compute=dp.get_precision('Account'),
                                  string='Subtotal pesos', store=True)

    @api.multi
    @api.depends('subtotal', 'currency')
    def _get_subtotal_pesos(self):
        for rec in self:
            rec.subtotal_pesos = rec.subtotal
            base_currency_id = rec.pedido_cot_id.company_currency_id.id
            if rec.currency.id != base_currency_id:
                dates = rec.currency.rate_ids.sorted(key=attrgetter('name'))
                rec.subtotal_pesos = rec.subtotal * dates[-1].rate_presupuesto if len(dates) else rec.subtotal

# TODO Spring 6 GAP 126
class grpCotizacionesProveedorPesos(models.Model):
    _name = 'grp.cotizaciones.proveedor.pesos'

    cot_id = fields.Many2one('grp.cotizaciones', 'Cotización')
    provider_id = fields.Many2one('res.partner', 'Proveedor')
    total_amount = fields.Float(digits_compute=dp.get_precision('Account'), string='Total estimado pesos proveedor')

# TODO Spring 6 GAP 126
class grpCotizacionesEstimadoComprometer(models.Model):
    _name = 'grp.cotizaciones.estimado.comprometer'

    cot_id = fields.Many2one('grp.cotizaciones', 'Cotización')
    fiscalyear_id = fields.Many2one('account.fiscalyear', 'Año fiscal')
    provider_id = fields.Many2one('res.partner', 'Proveedor')
    total_amount = fields.Float(digits_compute=dp.get_precision('Account'), string='Monto estimado a consumir')
    cot_provider_ids = fields.Many2many(comodel_name="res.partner", string='Proveedores', compute='_get_providers')

    # TODO R Spring 6 GAP 126
    @api.onchange('fiscalyear_id', 'total_amount', 'cot_id')
    def _onchange_fiscalyear_provider(self):
        domain = {
            'provider_id': [('id', 'in', self.cot_id.provider_ids.mapped(lambda x: x.provider_id.id))]
        }
        return {'domain': domain}

    @api.multi
    def _get_providers(self):
        for rec in self:
            rec.cot_provider_ids = [prov.provider_id.id for prov in rec.cot_id.provider_ids]

    _sql_constraints = [
        (
        'fp_unique', 'unique(cot_id,fiscalyear_id,provider_id)', u'Ya ha generado líneas para ese año fiscal-proveedor')
    ]

# TODO Spring 6 GAP 126
class grpCotizacionesCompromisosXProveedor(models.Model):
    _name = 'grp.cotizaciones.compromiso.proveedor'
    _inherit = ['mail.thread']

    _description = 'Compromiso por proveedor'

    name = fields.Char(u'Número', default='/')
    date = fields.Date("Fecha", required=True, default=lambda *a: fields.Date.today())
    nro_compromiso = fields.Integer(u'Nro Compromiso', readonly=True)
    total_number_comp = fields.Integer(u'Total a comprometer', readonly=False)
    cot_id = fields.Many2one('grp.cotizaciones', u'Número de adjudicación', readonly=True)
    fiscalyear_id = fields.Many2one('account.fiscalyear', u'Año fiscal', required=True, readonly=True)
    inciso_siif_id = fields.Many2one('grp.estruc_pres.inciso', 'Inciso', readonly=True)
    ue_siif_id = fields.Many2one('grp.estruc_pres.ue', 'Unidad ejecutora', readonly=True)
    apg_id = fields.Many2one('grp.compras.apg', 'APG', required=True, readonly=True)
    pc_id = fields.Many2one('grp.pedido.compra', 'Pedido de compra', readonly=True)
    provider_id = fields.Many2one('res.partner', 'Proveedor', required=True, readonly=True)
    nro_afectacion_siif = fields.Integer(u'Nro Afectación SIIF', help=u'Nro. de afectación SIIF', related='apg_id.nro_afectacion_siif', readonly=True)
    siif_tipo_ejecucion = fields.Many2one('tipo.ejecucion.siif', u'Tipo de ejecución',
                                          readonly=True, related='apg_id.siif_tipo_ejecucion')

    siif_concepto_gasto = fields.Many2one('presupuesto.concepto', string=u'Concepto del gasto',
                                          readonly=True, related='apg_id.siif_concepto_gasto')

    siif_financiamiento = fields.Many2one('financiamiento.siif', string=u'Fuente de financiamiento',
                                          readonly=True, related='apg_id.siif_financiamiento')

    siif_codigo_sir = fields.Many2one('codigo.sir.siif', string=u'Código SIR',
                                      readonly=True, related='apg_id.siif_codigo_sir')

    siif_nro_fondo_rot = fields.Many2one('fondo.rotatorio.siif', string=u'Nro doc. fondo rotatorio',
                                         readonly=True, related='apg_id.siif_nro_fondo_rot')

    siif_tipo_documento = fields.Many2one('tipo.documento.siif', string=u'Tipo de documento',
                                          domain=[('visible_documento_compromiso', '=', True)])
    siif_descripcion = fields.Text(string=u'Descripción SIIF', size=100)

    llpapg_ids = fields.One2many('grp.cotizaciones.compromiso.proveedor.llavep', 'compromiso_id',
                                 string=u'Llaves presupuestales')
    state = fields.Selection([('draft', 'Borrador'), ('committed', 'Comprometido'), ('recalled', 'Anulado en SIIF'),
                              ('anulado', u'Anulado')],
                             'Estado', size=86, readonly=True, default='draft')
    modif_compromiso_log_ids = fields.One2many('modif.cot_compromiso.siif.log', 'cotizacion_compromiso_id', 'Log')
    anulacion_siif_log_ids = fields.One2many('cot_compromiso.anulacion.siif.log', 'cotizacion_compromiso_id', 'Log anulaciones')
    nro_comp_sist_aux = fields.Char(u'Nro Compromiso Sist. aux')
    anulada_siif = fields.Boolean('Anulada en SIIF', default=False)
    total_llave = fields.Integer("Total llave presupuestal", compute='_compute_total_llave')
    siif_sec_compromiso = fields.Char(u'Secuencial compromiso')
    siif_ult_modif = fields.Integer(u'Última modificación')
    # TODO: R I 280
    total_comprometido = fields.Integer(u'Total comprometido', compute='_compute_total_comprometido', store=True)
    obligaciones_count = fields.Integer(compute='_obligaciones_count', string="Obligaciones")
    filtro_sir = fields.Char(string=u'Filtro código SIR', compute='_compute_filtro_sir')

    @api.multi
    @api.depends('inciso_siif_id','ue_siif_id','siif_financiamiento')
    def _compute_filtro_sir(self):
        for rec in self:
            #Si el financiamiento es 11 filtro solo por financiamiento
            if rec.siif_financiamiento and rec.siif_financiamiento.codigo.zfill(2) == '11':
                rec.filtro_sir = '_____' + rec.siif_financiamiento.codigo.zfill(2) + '__________'
            #Si tiene inciso_siif_id, ue_siif_id y financiamiento != 11, filtro por inciso, ue y financiamiento
            elif rec.inciso_siif_id and rec.ue_siif_id and rec.siif_financiamiento:
                rec.filtro_sir = rec.inciso_siif_id.inciso + rec.ue_siif_id.ue + rec.siif_financiamiento.codigo.zfill(2) + '__________'
            # Si no finaciamiento, o el financiamiento es != 11 y no tiene inciso_siif_id o ue_siif_id, no muestra nada
            else:
                rec.filtro_sir = 'xxxxxxxxxxxxxxx'

    def _obligaciones_count(self):
        for compromiso in self:
            compromiso.obligaciones_count = self.env['account.invoice'].search_count([('compromiso_proveedor_id', '=', compromiso.id)])

    @api.multi
    def view_obligaciones(self):
        return {
            'type': 'ir.actions.act_window',
            'view_type': 'form',
            'view_mode': 'tree,form',
            'res_model': 'account.invoice',
            'domain': [('compromiso_proveedor_id', 'in', self.ids)]
        }

    @api.multi
    def action_anular(self):
        self.write({'state': 'anulado'})

    @api.multi
    @api.depends('modif_compromiso_log_ids.importe')
    def _compute_total_comprometido(self):
        for rec in self:
            rec.total_comprometido = sum(map(lambda x: x.importe, rec.modif_compromiso_log_ids))

    @api.depends("llpapg_ids.importe")
    def _compute_total_llave(self):
        for record in self:
            total = 0
            for llave in record.llpapg_ids:
                total += llave.importe
            record.total_llave = total

    @api.multi
    def action_llpapg_reload(self):
        for rec in self:
            rec.llpapg_ids.unlink()
            llpapg_data = []
            if rec.apg_id:
                for llavep in rec.apg_id.llpapg_ids:
                    llpapg_data.append((0, 0, {
                        'odg_id': llavep.odg_id.id,
                        'auxiliar_id': llavep.auxiliar_id.id,
                        'programa_id': llavep.programa_id.id,
                        'proyecto_id': llavep.proyecto_id.id,
                        'fin_id': llavep.fin_id.id,
                        'mon_id': llavep.mon_id.id,
                        'tc_id': llavep.tc_id.id,
                        'importe': llavep.importe,
                    }))
            rec.llpapg_ids = llpapg_data

    @api.multi
    def _check_llpapg_ids(self):
        for rec in self:
            if sum(map(lambda x: x.importe, rec.llpapg_ids)) != rec.total_number_comp:
                raise ValidationError(_('La suma de los importes de las Llaves Presupuestales no puede ser distinto que el Total Comprometido!'))

    @api.multi
    def compromiso_impactar_presupuesto(self):
        estructura_obj = self.env['presupuesto.estructura']
        for compromiso in self:
            if compromiso.llpapg_ids:
                for llave in compromiso.llpapg_ids:
                    estructura = estructura_obj.obtener_estructura(compromiso.fiscalyear_id.id,
                                                                   compromiso.apg_id.inciso_siif_id.inciso,
                                                                   compromiso.apg_id.ue_siif_id.ue,
                                                                   llave.programa, llave.proyecto, llave.mon, llave.tc,
                                                                   llave.fin, llave.odg, llave.auxiliar)
                    # Control 2: que no exista una estructura
                    if estructura is None:
                        desc_error = '(%s - %s - %s - %s - %s - %s - %s - %s - %s - %s)' % \
                                     (compromiso.fiscalyear_id.code, compromiso.inciso_siif_id.inciso, compromiso.ue_siif_id.ue,
                                      llave.odg, llave.auxiliar, llave.fin, llave.programa, llave.proyecto, llave.mon,
                                      llave.tc)
                        raise exceptions.ValidationError(u'No se encontró estructura con la llave presupuestal asociada al Compromiso: ' + desc_error)

                    # Control 3: que no alcance el disponible para el monto de la llave presupuestal
                    # if estructura.disponible < llave.importe:
                    #    raise osv.except_osv('Error', 'El disponible de la estructura no es suficiente para cubrir el importe de la llave presupuestal.')

                    res_comprometer = estructura_obj.comprometer(compromiso.id, TIPO_DOCUMENTO.COMPROMISO, llave.importe, estructura)

            else:
                raise exceptions.ValidationError(u'No existen llaves presupuestales asociada al compromiso.')
        return True

    @api.multi
    def compromiso_enviar_siif(self):
        generador_xml = self.env['grp.siif.xml_generator']
        siif_proxy = self.env['siif.proxy']
        for compromiso in self:
            if compromiso.siif_tipo_ejecucion and compromiso.siif_tipo_ejecucion.codigo == 'P' and not compromiso.siif_nro_fondo_rot:
                raise exceptions.ValidationError(u'Si el tipo de ejecución es Fondo Rotatorio, se debe cargar Nro. de Fondo Rotatorio.')
            if compromiso.provider_id.tipo_doc_rupe == '' or compromiso.provider_id.nro_doc_rupe == '':
                raise exceptions.ValidationError(u'El proveedor debe tener configurado tipo y número de documento de RUPE.')

            # se compromete contra el SIIF
            anio_fiscal = compromiso.fiscalyear_id and compromiso.fiscalyear_id.id or False
            nro_carga = self.env['ir.sequence'].with_context({'fiscalyear_id': anio_fiscal}).get('num_carga_siif') # AÑO-INCISO-UE
            nro_carga = nro_carga[4:]
            nro_comp_sist_aux = self.env['ir.sequence'].with_context({'fiscalyear_id': anio_fiscal}).get('sec.siif.compromiso')
            nro_comp_sist_aux = nro_comp_sist_aux[4:]

            # Control de no enviar campos de SICE si alguna de las llaves tiene exceptuado_sice = True
            enviar_datos_sice = False
            if compromiso.siif_financiamiento.exceptuado_sice or compromiso.siif_tipo_ejecucion.exceptuado_sice or compromiso.siif_concepto_gasto.exceptuado_sice:
                enviar_datos_sice = False
            else:
                objeto_gasto_obj = self.env['presupuesto.objeto.gasto']
                for llave_pres in compromiso.llpapg_ids:
                    objeto_gasto_ids = objeto_gasto_obj.search([('name', '=', llave_pres.odg),
                                                                ('auxiliar', '=', llave_pres.auxiliar)], limit=1)
                    if objeto_gasto_ids:
                        if not objeto_gasto_ids.exceptuado_sice:
                            enviar_datos_sice = True
                    else:
                        raise exceptions.ValidationError(u'No se encontró objeto del gasto con ODG %s, y Auxiliar %s.' %
                                                         (llave_pres.odg, llave_pres.auxiliar))

            xml_compromiso = generador_xml.gen_xml_cotizacion_compromiso(cotizacion_compromiso=compromiso, llaves_presupuestales=compromiso.llpapg_ids,
                                              importe=compromiso.total_llave, nro_carga=nro_carga, tipo_doc_grp='02',
                                              nro_modif_grp=0,
                                              tipo_modificacion='A',
                                              enviar_datos_sice=enviar_datos_sice,
                                              nro_comp_sist_aux=nro_comp_sist_aux)

            resultado_siif = siif_proxy.put_solic(xml_compromiso)

            # conversiones del xml resultado
            xml_root = etree.fromstring(resultado_siif)
            str_xml_list = xml_root.xpath("//*[local-name()='return']")
            str_xml = str_xml_list[0].text
            if str_xml.find('?>') != -1:
                str_xml = str_xml.split('?>')[1]
            xml_root = etree.fromstring(str_xml)

            dicc_modif = {}
            descr_error = ''
            for movimiento in xml_root.findall('movimiento'):
                if dicc_modif.get('nro_compromiso', None) is None and movimiento.find(
                        'nro_compromiso').text and movimiento.find('nro_compromiso').text.strip():
                    dicc_modif['nro_compromiso'] = movimiento.find('nro_compromiso').text
                if dicc_modif.get('resultado', None) is None and movimiento.find(
                        'resultado').text and movimiento.find('resultado').text.strip():
                    dicc_modif['resultado'] = movimiento.find('resultado').text
                if dicc_modif.get('siif_sec_compromiso', None) is None and movimiento.find(
                        'sec_compromiso').text and movimiento.find('sec_compromiso').text.strip():
                    dicc_modif['siif_sec_compromiso'] = movimiento.find('sec_compromiso').text
                if dicc_modif.get('siif_ult_modif', None) is None and movimiento.find(
                        'nro_modif_sist_aux').text and movimiento.find('nro_modif_sist_aux').text.strip():
                    dicc_modif['siif_ult_modif'] = movimiento.find('nro_modif_sist_aux').text
                if not descr_error and movimiento.find('comentario').text and len(movimiento.find('comentario').text) > 5:
                    descr_error = movimiento.find('comentario').text
                # MVARELA 07/01 Si viene E en alguno de los movimientos se larga el error
                if movimiento.find('resultado').text == 'E':
                    raise exceptions.ValidationError('Error al comprometer en SIIF: %s' %
                                                     (descr_error or u'Error no especificado por el SIIF'))
                if dicc_modif.get('nro_compromiso', False) and dicc_modif.get('nro_compromiso', False).strip() \
                        and dicc_modif.get('resultado', False):
                    break

            dicc_modif['nro_comp_sist_aux'] = nro_comp_sist_aux
            # 004 Pasa a Comprometido = True
            dicc_modif['anulada_siif'] = False
            res_write = compromiso.write(dicc_modif)

            if res_write:
                modif_compromiso_log_obj = self.env['modif.cot_compromiso.siif.log']
                for llave in compromiso.llpapg_ids:
                    vals = {
                        'cotizacion_compromiso_id': compromiso.id,
                        'tipo': 'A',
                        'fecha': fields.Date.today(),
                        'programa': llave.programa,
                        'proyecto': llave.proyecto,
                        'moneda': llave.mon,
                        'tipo_credito': llave.tc,
                        'financiamiento': llave.fin,
                        'objeto_gasto': llave.odg,
                        'auxiliar': llave.auxiliar,
                        'importe': llave.importe,
                        'siif_sec_compromiso': dicc_modif.get('siif_sec_compromiso', False),
                        'siif_ult_modif': dicc_modif.get('siif_ult_modif', False),
                    }
                    modif_compromiso_log_obj.create(vals)
        return True

    @api.multi
    def button_comprometer(self):
        self._check_llpapg_ids()
        integracion_siif = self.env.user.company_id.integracion_siif or False
        if integracion_siif and self.filtered(lambda r: r.nro_compromiso):
            raise ValidationError("Este documento ya ha sido enviado a SIIF. Por favor, actualice el navegador.")
        self.compromiso_impactar_presupuesto()
        if integracion_siif:
            self.compromiso_enviar_siif()
        self.write({'state': 'committed'})

        for rec in self:
            partner_ids = [partner.id for partner in rec.pc_id.message_follower_ids]

            msg = _(
                """
                Para la Adjudicación <a href="#action=mail.action_mail_redirect&model=grp.cotizaciones&res_id=%s">%s<a/>   correspondiente al
                pedido de compra <a href="#action=mail.action_mail_redirect&model=grp.pedido.compra&res_id=%s">%s<a/>, el compromiso
                <a href="#action=mail.action_mail_redirect&model=grp.cotizaciones.compromiso.proveedor&res_id=%s">%s<a/> está comprometido""") % (
                      rec.cot_id.id, rec.cot_id.name,rec.pc_id.id, rec.pc_id.name,rec.id, rec.name)

            self.pool.get('mail.thread').message_post(self._cr, self._uid, self.id, type="notification",
                                                  subtype='mt_comment', body=msg,
                                                  partner_ids=partner_ids)
        return True

    @api.multi
    def compromiso_cot_desafectar_presupuesto(self):
        estructura_obj = self.env['presupuesto.estructura']
        for compromiso in self:
            for llave in compromiso.llpapg_ids:
                estructura = estructura_obj.obtener_estructura(compromiso.fiscalyear_id.id,
                                                               compromiso.inciso_siif_id.inciso,
                                                               compromiso.ue_siif_id.ue,
                                                               llave.programa, llave.proyecto, llave.mon, llave.tc,
                                                               llave.fin, llave.odg, llave.auxiliar)
                # Control 2: que no exista una estructura
                if estructura is None:
                    desc_error = '(%s - %s - %s - %s - %s - %s - %s - %s - %s - %s)' % \
                                 (compromiso.fiscalyear_siif_id.code, compromiso.inciso_siif_id.inciso, compromiso.ue_siif_id.ue,
                                  llave.odg, llave.auxiliar, llave.fin, llave.programa, llave.proyecto, llave.mon, llave.tc)
                    raise exceptions.ValidationError(
                        u'No se encontró estructura con la llave presupuestal asociada al Compromiso: ' + desc_error)

                res_comprometer = estructura_obj.comprometer(compromiso.id, TIPO_DOCUMENTO.COMPROMISO, -1 * llave.importe, estructura)
                if not res_comprometer or not res_comprometer['codigo'] == 1:
                    raise exceptions.ValidationError(res_comprometer['mensaje'])
        return True

    @api.multi
    def compromiso_cot_desafectar_siif(self):
        generador_xml = self.env['grp.siif.xml_generator']
        siif_proxy = self.env['siif.proxy']
        for compromiso in self:
            if compromiso.siif_tipo_ejecucion and compromiso.siif_tipo_ejecucion.codigo == 'P' and not compromiso.siif_nro_fondo_rot:
                raise exceptions.ValidationError(u'Si el tipo de ejecución es Fondo Rotatorio, se debe cargar Nro. de Fondo Rotatorio.')
            if compromiso.provider_id.tipo_doc_rupe == '' or compromiso.provider_id.nro_doc_rupe == '':
                raise exceptions.ValidationError(u'El proveedor debe tener configurado tipo y número de documento de RUPE.')

            # Control de no enviar campos de SICE si alguna de las llaves tiene exceptuado_sice = True
            enviar_datos_sice = False
            if compromiso.siif_financiamiento.exceptuado_sice or compromiso.siif_tipo_ejecucion.exceptuado_sice or compromiso.siif_concepto_gasto.exceptuado_sice:
                enviar_datos_sice = False
            else:
                objeto_gasto_obj = self.env['presupuesto.objeto.gasto']
                for llave_pres in compromiso.llpapg_ids:
                    objeto_gasto_ids = objeto_gasto_obj.search([('name', '=', llave_pres.odg),
                                                                ('auxiliar', '=', llave_pres.auxiliar)], limit=1)
                    if objeto_gasto_ids:
                        if not objeto_gasto_ids.exceptuado_sice:
                            enviar_datos_sice = True
                    else:
                        raise exceptions.ValidationError(
                            u'No se encontró objeto del gasto con ODG %s, y Auxiliar %s.' %
                            (llave_pres.odg, llave_pres.auxiliar))

            # se compromete contra el SIIF
            anio_fiscal = compromiso.fiscalyear_id and compromiso.fiscalyear_id.id or False
            nro_carga = self.env['ir.sequence'].with_context({'fiscalyear_id': anio_fiscal}).get('num_carga_siif')  # AÑO-INCISO-UE
            nro_carga = nro_carga[4:]

            nro_modif = compromiso.siif_ult_modif + 1

            xml_anular_cot_compromiso = generador_xml.gen_xml_cotizacion_compromiso(cotizacion_compromiso=compromiso,
                                                                         llaves_presupuestales=compromiso.llpapg_ids,
                                                                         importe=compromiso.total_llave*-1,
                                                                         nro_carga=nro_carga, tipo_doc_grp='02',
                                                                         nro_modif_grp=nro_modif,
                                                                         tipo_modificacion='N',
                                                                         es_modif=True,
                                                                         motivo="Anulacion de compromiso",
                                                                         enviar_datos_sice=enviar_datos_sice,
                                                                         nro_comp_sist_aux=compromiso.nro_comp_sist_aux)

            resultado_siif = siif_proxy.put_solic(xml_anular_cot_compromiso)

            # conversiones del xml resultado
            xml_root = etree.fromstring(resultado_siif)
            str_xml_list = xml_root.xpath("//*[local-name()='return']")
            str_xml = str_xml_list[0].text
            if str_xml.find('?>') != -1:
                str_xml = str_xml.split('?>')[1]
            xml_root = etree.fromstring(str_xml)

            dicc_modif = {}
            descr_error = ''
            for movimiento in xml_root.findall('movimiento'):
                if dicc_modif.get('nro_compromiso', None) is None and movimiento.find('nro_compromiso').text and movimiento.find('nro_compromiso').text.strip():
                    dicc_modif['nro_compromiso'] = movimiento.find('nro_compromiso').text
                if dicc_modif.get('resultado', None) is None and movimiento.find('resultado').text and movimiento.find('resultado').text.strip():
                    dicc_modif['resultado'] = movimiento.find('resultado').text
                if dicc_modif.get('siif_sec_compromiso', None) is None and movimiento.find('sec_compromiso').text and movimiento.find('sec_compromiso').text.strip():
                    dicc_modif['siif_sec_compromiso'] = movimiento.find('sec_compromiso').text
                if dicc_modif.get('siif_ult_modif', None) is None and movimiento.find('nro_modif_sist_aux').text and movimiento.find('nro_modif_sist_aux').text.strip():
                    dicc_modif['siif_ult_modif'] = movimiento.find('nro_modif_sist_aux').text
                if not descr_error and movimiento.find('comentario').text and len(movimiento.find('comentario').text) > 5:
                    descr_error = movimiento.find('comentario').text
                # MVARELA 07/01 Si viene E en alguno de los movimientos se larga el error
                if movimiento.find('resultado').text == 'E':
                    raise exceptions.ValidationError('Error al anular compromiso en SIIF: %s' %
                                                     (descr_error or u'Error no especificado por el SIIF'))
                if dicc_modif.get('nro_compromiso', False) and dicc_modif.get('nro_compromiso',False).strip() and dicc_modif.get('resultado', False):
                    break

            anulacion_cot_compromiso_log_obj = self.env['cot_compromiso.anulacion.siif.log']
            # anulacion_siif_log_ids
            vals_history = {
                'cotizacion_compromiso_id': compromiso.id,
                'nro_afectacion_siif': compromiso.apg_id.nro_afectacion_siif or 0,
                'nro_compromiso': compromiso.nro_compromiso or 0,
                'nro_comp_sist_aux': compromiso.nro_comp_sist_aux or False,
            }
            anulacion_cot_compromiso_log_obj.create(vals_history)

            # Borrando valores
            if compromiso.modif_compromiso_log_ids:
                compromiso.modif_compromiso_log_ids.unlink()
            # Pasa a Comprometido = True
            dicc_modif.update({'nro_comp_sist_aux': False, 'nro_compromiso': False, 'anulada_siif': True})
            compromiso.write(dicc_modif)
        return True

    @api.multi
    def button_anular(self):
        self.compromiso_cot_desafectar_presupuesto()
        integracion_siif = self.env.user.company_id.integracion_siif or False
        if integracion_siif:
            self.compromiso_cot_desafectar_siif()
        self.write({'state': 'recalled'})
        return True

    @api.multi
    def abrir_wizard_modif_cot_compromiso_siif(self):
        mod_obj = self.env['ir.model.data']
        res = mod_obj.get_object_reference('grp_factura_siif', 'view_wizard_modif_cot_compromiso_siif')
        res_id = res and res[1] or False

        new_context = dict(self._context)
        new_context.update({
            'default_cot_compromiso_id': self.id,
            'default_ue_id': self.ue_siif_id.id
        })
        return {
            'name': "Modificaciones",  # Name You want to display on wizard
            'view_mode': 'form',
            'view_id': res_id,
            'view_type': 'form',
            'res_model': 'wiz.modificacion_cot_compromiso_siif',
            'type': 'ir.actions.act_window',
            'target': 'new',
            'context': new_context,
        }

    @api.model
    def enviar_modificacion_siif(self, id):
        generador_xml = self.env['grp.siif.xml_generator']
        siif_proxy = self.env['siif.proxy']

        context = self._context
        programa = context['programa']
        proyecto = context['proyecto']
        moneda = context['moneda']
        tipo_credito = context['tipo_credito']
        tipo_modificacion = context['tipo_modificacion']
        financiamiento = context['financiamiento']
        objeto_gasto = context['objeto_gasto']
        auxiliar = context['auxiliar']
        importe = context['importe']
        fecha = context['fecha']
        motivo = context['motivo']
        auxiliar_id = context['auxiliar_id']
        fin_id = context['fin_id']
        mon_id = context['mon_id']
        odg_id = context['odg_id']
        programa_id = context['programa_id']
        proyecto_id = context['proyecto_id']
        tc_id = context['tc_id']

        cot_compromiso = self.browse(id)
        # MVARELA 15-09: Control de no enviar campos de SICE si alguna de las llaves tiene exceptuado_sice = True
        enviar_datos_sice = False
        if cot_compromiso.siif_financiamiento.exceptuado_sice or cot_compromiso.siif_tipo_ejecucion.exceptuado_sice or cot_compromiso.siif_concepto_gasto.exceptuado_sice:
            enviar_datos_sice = False
        else:
            objeto_gasto_obj = self.env['presupuesto.objeto.gasto']
            objeto_gasto_ids = objeto_gasto_obj.search([('name', '=', objeto_gasto),('auxiliar', '=', auxiliar)])
            if objeto_gasto_ids:
                if not objeto_gasto_ids[0].exceptuado_sice:
                    enviar_datos_sice = True
            else:
                raise exceptions.ValidationError(
                    u'No se encontró objeto del gasto con ODG %s, y Auxiliar %s.' % (objeto_gasto, auxiliar))

        lineas_llavep_obj = self.env['grp.cotizaciones.compromiso.proveedor.llavep']
        condicion = []
        condicion.append(('compromiso_id', '=', id))
        condicion.append(('programa', '=', programa))
        condicion.append(('proyecto', '=', proyecto))
        condicion.append(('odg', '=', objeto_gasto))
        condicion.append(('auxiliar', '=', auxiliar))
        condicion.append(('fin', '=', financiamiento))
        condicion.append(('mon', '=', moneda))
        condicion.append(('tc', '=', tipo_credito))
        llavep = lineas_llavep_obj.search(condicion, limit=1)
        if not llavep:
            if tipo_modificacion != 'A':
                raise exceptions.ValidationError(u'La llave presupuestal ingresada no se encuentra en el Compromiso.')
            else:
                vals = {
                    'compromiso_id': id,
                    'fin_id': fin_id,
                    'programa_id': programa_id,
                    'proyecto_id': proyecto_id,
                    'odg_id': odg_id,
                    'auxiliar_id': auxiliar_id,
                    'mon_id': mon_id,
                    'tc_id': tc_id,
                    'importe': 0,
                }
                llavep = lineas_llavep_obj.create(vals)

        if not cot_compromiso.nro_comp_sist_aux:
            raise exceptions.ValidationError(u'No puede enviar una modificación a SIIF sin Nro. de compromiso del sistema auxiliar.')

        # SE AFECTA CONTRA LA ESTRUCTURA LOCAL
        estructura_obj = self.env['presupuesto.estructura']
        estructura = estructura_obj.obtener_estructura(cot_compromiso.fiscalyear_id.id,
                                                       cot_compromiso.inciso_siif_id.inciso,
                                                       cot_compromiso.ue_siif_id.ue,
                                                       programa, proyecto, moneda, tipo_credito,
                                                       financiamiento, objeto_gasto, auxiliar)
        if estructura is None:
            desc_error = '(%s - %s - %s - %s - %s - %s - %s - %s - %s - %s)' % \
                         (cot_compromiso.fiscalyear_id.code, cot_compromiso.inciso_siif_id.inciso, cot_compromiso.ue_siif_id.ue,
                         objeto_gasto, auxiliar, financiamiento, programa, proyecto, moneda, tipo_credito)
            raise exceptions.ValidationError(u'No se encontró estructura con la llave presupuestal asociada al Compromiso: ' + desc_error)

        # ** Falta agregar controles **
        res = estructura_obj.comprometer(cot_compromiso.id, TIPO_DOCUMENTO.COMPROMISO, importe, estructura)

        if res['codigo'] == 1:
            # SE COMPROMETE CONTRA SIIF
            integracion_siif = self.env.user.company_id.integracion_siif or False
            if not integracion_siif:
                return True

            nro_carga = self.env['ir.sequence'].with_context(fiscalyear_id=cot_compromiso.fiscalyear_id.id).get('num_carga_siif')  # AÑO-INCISO-UE
            nro_carga = nro_carga[4:]
            nro_modif = cot_compromiso.siif_ult_modif + 1

            xml_modif_cot_compromiso = generador_xml.gen_xml_cotizacion_compromiso(cotizacion_compromiso=cot_compromiso,
                                                                    llaves_presupuestales=[llavep],
                                                                    importe=importe,
                                                                    nro_carga=nro_carga,
                                                                    tipo_doc_grp='02', nro_modif_grp=nro_modif,
                                                                    tipo_modificacion=tipo_modificacion, es_modif=True,
                                                                    motivo=motivo,
                                                                    nro_comp_sist_aux=cot_compromiso.nro_comp_sist_aux,
                                                                    enviar_datos_sice=enviar_datos_sice)

            resultado_siif = siif_proxy.put_solic(xml_modif_cot_compromiso)

            # conversiones del xml resultado
            xml_root = etree.fromstring(resultado_siif)
            str_xml_list = xml_root.xpath("//*[local-name()='return']")
            str_xml = str_xml_list[0].text
            if str_xml.find('?>') != -1:
                str_xml = str_xml.split('?>')[1]
            xml_root = etree.fromstring(str_xml)

            dicc_modif = {}
            descr_error = ''
            for movimiento in xml_root.findall('movimiento'):  # Es una lista si se afecta el mismo numero de carga una y otra vez
                if dicc_modif.get('nro_compromiso', None) is None:
                    dicc_modif['nro_compromiso'] = movimiento.find('nro_compromiso').text
                if dicc_modif.get('resultado', None) is None:
                    dicc_modif['resultado'] = movimiento.find('resultado').text
                if dicc_modif.get('siif_sec_compromiso', None) is None:
                    dicc_modif['siif_sec_compromiso'] = movimiento.find('sec_compromiso').text
                if dicc_modif.get('siif_ult_modif', None) is None:
                    dicc_modif['siif_ult_modif'] = movimiento.find('nro_modif_sist_aux').text
                if not descr_error and movimiento.find('comentario').text and len(movimiento.find('comentario').text) > 5:
                    descr_error = movimiento.find('comentario').text
                # MVARELA 07/01 Si viene E en alguno de los movimientos se larga el error
                if movimiento.find('resultado').text == 'E':
                    raise exceptions.ValidationError('Error al comprometer en SIIF: %s' % (descr_error or u'Error no especificado por el SIIF'))
                if dicc_modif.get('nro_compromiso', False) and dicc_modif.get('nro_compromiso',False).strip() and dicc_modif.get('resultado', False):
                    break

            cot_compromiso.write(dicc_modif)

            # Actualizar importe
            val_modif = {'importe': importe + llavep.importe}
            llavep.write(val_modif)

            modif_log_obj = self.env['modif.cot_compromiso.siif.log']
            vals = {
                'cotizacion_compromiso_id': cot_compromiso.id,
                'tipo': tipo_modificacion,
                'fecha': fecha,
                'programa': programa,
                'proyecto': proyecto,
                'moneda': moneda,
                'tipo_credito': tipo_credito,
                'financiamiento': financiamiento,
                'objeto_gasto': objeto_gasto,
                'auxiliar': auxiliar,
                'importe': importe,
                'siif_sec_compromiso': dicc_modif['siif_sec_compromiso'] if 'siif_sec_compromiso' in dicc_modif else False,
                'siif_ult_modif': dicc_modif['siif_ult_modif'] if 'siif_ult_modif' in dicc_modif else False,
            }
            modif_log_obj.create(vals)
        return True

class modifCotCompromisoSiifLog(models.Model):
    _name = 'modif.cot_compromiso.siif.log'
    _description = "Log de modificaciones de cotizaciones compromiso SIIF"

    cotizacion_compromiso_id = fields.Many2one('grp.cotizaciones.compromiso.proveedor', u'Cotización Compromiso', required=True)
    tipo = fields.Selection(
        (('A', u'A - Aumento'),
         ('R', u'R - Reducción')),
         # ('C', u'C - Corrección'),
         # ('N', u'N - Anulación'),
         # ('D', u'D - Devolución')),
         'Tipo')
    fecha = fields.Date('Fecha', required=True)
    importe = fields.Integer('Importe', required=True)
    programa = fields.Char('Programa', size=3, required=True)
    proyecto = fields.Char('Proyecto', size=3, required=True)
    moneda = fields.Char('MON', size=2, required=True)
    tipo_credito = fields.Char('TC', size=1, required=True)
    financiamiento = fields.Char('FF', size=2, required=True)
    objeto_gasto = fields.Char('ODG', size=3, required=True)
    auxiliar = fields.Char('AUX', size=3, required=True)
    siif_sec_compromiso = fields.Char(u'Secuencial compromiso')
    siif_ult_modif = fields.Integer(u'Última modificación')

class cotCompromisoAnulacionesSiifLog(models.Model):
    _name = 'cot_compromiso.anulacion.siif.log'
    _description = u"Log Cotización compromiso anulaciones"

    cotizacion_compromiso_id = fields.Many2one('grp.cotizaciones.compromiso.proveedor', u'Cotización Compromiso', required=True, ondelete='cascade')
    fecha = fields.Date('Fecha', default=lambda *a: fields.Date.today())
    nro_afectacion_siif = fields.Integer(u'Nro Afectación SIIF')
    nro_compromiso = fields.Char(u'Nro Compromiso')
    nro_comp_sist_aux = fields.Char(u'Nro Compromiso Sistema Aux')

class grpCoreCotizacionRefusedInherited(models.TransientModel):
    _inherit = 'grp.cotizaciones.refused.wizard'

    @api.multi
    def save(self):
        if 'active_id' in self._context:
            cotizacion_id = self._context.get('active_id')
            for record in self:
                cot_obj = self.env['grp.cotizaciones'].browse(cotizacion_id)
                for comp in cot_obj.provider_compromise_ids:
                    if comp.state not in ['anulado']:
                        raise exceptions.ValidationError(u'No puede cancelar la Adjudicación si tiene compromisos'
                                                         u' de proveedor sin anular.')
        return super(grpCoreCotizacionRefusedInherited, self).save()


from collections import defaultdict
from yaml import safe_load

import numpy as np

def gen_row(res_list):
    # Overall simulation time
    sim_time = max(elem['t_end'] for elem in res_list) - min(elem['t_start'] for elem in res_list)

    # Response time. Only count agents
    resp_time_list = [elem['t_end'] - elem['t_start'] for elem in res_list if elem['name'].startswith("Agent")]
    num_agents = len(resp_time_list)
    max_resp_time = max(resp_time_list)
    avg_resp_time = sum(resp_time_list) / len(resp_time_list)

    num_req = sum(elem.get('Req', 0) for elem in res_list)
    avg_req_sec = num_req / max_resp_time
    avg_req_region = sum(elem.get('R(Req)', 0) for elem in res_list) / num_req

    num_req_per_agent_sec = [elem.get('Req', 0) / (elem['t_end'] - elem['t_start']) for elem in res_list]
    max_num_req_per_agent_sec = max(num_req_per_agent_sec)
    avg_num_req_per_agent_sec = sum(num_req_per_agent_sec) / num_agents

    num_qm = sum(elem.get('Qm', 0) for elem in res_list)
    avg_qm_region = sum(elem.get('R(Qm)', 0) for elem in res_list) / num_qm

    agent_list = [elem for elem in res_list if elem['name'].startswith("Agent")]
    num_fails = sum(elem.get('fail', 0) for elem in agent_list)
    fail_percent_list = [elem.get('fail', 0) * elem['Req'] / elem['R(Req)'] for elem in agent_list]
    avg_fail_percent_per_agent = 100 * sum(fail_percent_list) / num_agents

    air_mgr = [elem for elem in res_list if elem['name'] == "AirspaceManager"][0]
    num_qe = air_mgr.get('Qe', 0)
    avg_qe_per_sec = num_qe / (air_mgr['t_end'] - air_mgr['t_start'])
    avg_qe_region_per_sec = air_mgr.get('R(Qe)', 0) / (air_mgr['t_end'] - air_mgr['t_start'])

    return (num_agents, sim_time, max_resp_time, avg_resp_time,
            num_req, max_num_req_per_agent_sec, avg_num_req_per_agent_sec,
            avg_fail_percent_per_agent,
            avg_qe_per_sec, avg_qe_region_per_sec)

if __name__ == "__main__":
    with open('aggressive/city_sim.yaml', 'r') as f:
        ret_dict = safe_load(f)
        sorted_res = sorted(ret_dict.values(), key=len)

        print(f.name)
        row_list = []
        for ret_list in sorted_res:
            row = gen_row(ret_list)
            row_list.append(row)

        agt_num_dict = defaultdict(list)
        for row in row_list:
            agt_num_dict[row[0]].append(np.array(row))

        print([(n, len(v)) for n, v in sorted(agt_num_dict.items())])
        for n, v in sorted(agt_num_dict.items()):
            row = np.mean(v, axis=0)
            # Gen columns for response time
            print(row[0], row[2], row[3], row[2] - row[3])
            # Gen columns for Qe
            print(row[0], row[-2], row[-1])
            # Gen columns for sim time, #rect, fail rate
            print(row[1], row[-1], row[-3])


from enum import Enum
from typing import Type

from .base_field import BaseField

class EnumField(BaseField):

    initial = ""

    default_error_messages = {
        'invalid_choice': '"{input}" is not a valid choice.'
    }

    def __init__(self, enum_class: Type, **kwargs):

        default = kwargs.get('default')
        if default:
            if isinstance(default, Enum):
                kwargs['default'] = default.value

        super().__init__(**kwargs)
        self.enum_class = enum_class

    def to_internal_value(self, data):
        try:
            return self.enum_class[data].value
        except KeyError:
            self.fail('invalid_choice', input=data)

    def to_representation(self, value):
        return self.enum_class(value).name

    def get_default_schema(self):
        return {
            'type': 'string',
            'default': list(self.enum_class)[0].name,
        }


import requests
import pandas as pd
from bs4 import BeautifulSoup
import matplotlib.pyplot as plt
from selenium import webdriver

r=requests.get('https://gjirafa50.com/kompjuter-laptop-server-1/kompjuter-1/?rel=1')

print(r)
#print(r.content)

url=('https://gjirafa50.com/kompjuter-laptop-server-1/kompjuter-1/?rel=1')

r=requests.get(url)
print(r.status_code)

soup=BeautifulSoup(r.text,'html.parser')

produktet=soup.find_all('div', class_="ty-grid-list__item-name")

prodi=[]
for produkti in produktet:
    prodi.append(produkti.find('a',{'class':'product-title'}).text)
print(prodi)

cmimet=soup.find_all('span',{'class':'ty-price-num'})

l=[span.get_text()for span in cmimet]
print(l)

cmimet_ok=[x for x in l if "€" not in x]

data=pd.DataFrame()

data['Produkti'] = prodi
data['Cmimi']= cmimet_ok
print(data)


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Fuente: OpenCV
@author: nacho
"""
import cv2
import numpy as np

def triangulation(x1, x2, orientation_1, pos_1, orientation_2, pos_2):

    #Matriz calibración
    mtx=np.array([[1.54272784e+03, 0, 9.57409444e+02],
    [0, 1.54656053e+03, 6.29269967e+02],
    [0, 0, 1]])
    dist=np.array([0.01737745, -0.36542463, 0.01312702, -0.00285169,
    0.80215804])

    #Matriz mejorada
    h,  w = 1080, 1920
    newcameramtx, roi = cv2.getOptimalNewCameraMatrix(mtx, dist, (w,h), 1, (w,h))
    intrinsic=np.array(newcameramtx)

    ############################################################################################

    #Parametros imagen 1
    roll_1 = orientation_1[0]
    pitch_1 = orientation_1[1]
    yaw_1 = orientation_1[2]
    x_1 = pos_1[0]
    y_1 = pos_1[1]
    z_1 = pos_1[2]

    #Matriz de rotación imagen 1
    rotx_1=np.array([[1, 0, 0], [0, np.cos(roll_1), -np.sin(roll_1)], [0, np.sin(roll_1), np.cos(roll_1)]])
    roty_1=np.array([[np.cos(pitch_1), 0, np.sin(pitch_1)], [0, 1, 0], [-np.sin(pitch_1), 0, np.cos(pitch_1)]])
    rotz_1=np.array([[np.cos(yaw_1), -np.sin(yaw_1), 0], [np.sin(yaw_1), np.cos(yaw_1), 0], [0, 0, 1]])
    rot_1=np.matmul(rotz_1,roty_1)
    rot_1=np.matmul(rot_1,rotx_1)

    #Matriz de translación imagen 1
    trans_1=np.array([[x_1, y_1, z_1]])

    #Matriz extrínseca imagen 1
    extrinsic_1=np.concatenate((rot_1, trans_1.T), axis=1)

    #Matriz resultante imagen 1
    mat_1=np.matmul(intrinsic,extrinsic_1)

    #########################################################################################

    #Parametros imagen 2
    roll_2 = orientation_2[0]
    pitch_2 = orientation_2[1]
    yaw_2 = orientation_2[2]
    x_2 = pos_2[0]
    y_2 = pos_2[1]
    z_2 = pos_2[2]

    #Matriz de rotación imagen 2
    rotx_2=np.array([[1, 0, 0], [0, np.cos(roll_2), -np.sin(roll_2)], [0, np.sin(roll_2), np.cos(roll_2)]])
    roty_2=np.array([[np.cos(pitch_2), 0, np.sin(pitch_2)], [0, 1, 0], [-np.sin(pitch_2), 0, np.cos(pitch_2)]])
    rotz_2=np.array([[np.cos(yaw_2), -np.sin(yaw_2), 0], [np.sin(yaw_2), np.cos(yaw_2), 0], [0, 0, 1]])
    rot_2=np.matmul(rotz_2,roty_2)
    rot_2=np.matmul(rot_2,rotx_2)

    #Matriz de translación imagen 2
    trans_2=np.array([[x_2, y_2, z_2]])

    #Matriz extrínseca imagen 2
    extrinsic_2=np.concatenate((rot_2, trans_2.T), axis=1)

    #Matriz resultante imagen 2
    mat_2=np.matmul(intrinsic,extrinsic_2)

    #Triangulación
    p_3d = cv2.triangulatePoints(mat_1, mat_2, x1, x2)
    p_3d/=p_3d[3]

    print('Punto 3D calculado:',  p_3d.T)

    return p_3d


# Plot the spectra for each galaxy

import matplotlib.pyplot as plt
import h5py
import numpy as np
import pygad as pg
from utils import read_h5_into_dict
from physics import wave_to_vel

plt.rc('text', usetex=True)
plt.rc('font', family='serif', size=13)

cb_blue = '#5289C7'

if __name__ == '__main__':

    model = 'm100n1024'
    wind = 's50'
    snap = 151

    orient = '0_deg'
    fr200 = 0.25
    vel_range = 600.
    redshift = 0

    chisq_lim_dict = {'snap_151': [4., 50., 15.8, 39.8, 8.9, 4.5],
                      'snap_137': [3.5, 28.2, 10., 35.5, 8.0, 4.5],
                      'snap_125': [3.5, 31.6, 15.8, 39.8, 10., 5.6],
                      'snap_105': [4.5, 25.1, 25.1, 34.5, 10., 7.1],}
    chisq_lim = chisq_lim_dict[f'snap_{snap}']

    lines = ["H1215", "MgII2796", "CII1334", "SiIII1206", "CIV1548", "OVI1031"]
    plot_lines = [r'${\rm HI}1215$', r'${\rm MgII}2796$', r'${\rm CII}1334$',
                  r'${\rm SiIII}1206$', r'${\rm CIV}1548$', r'${\rm OVI}1031$']
    sample_dir = f'/disk04/sapple/data/samples/'
    spectra_dir = f'/disk04/sapple/data/normal/{model}_{wind}_{snap}/'

    with h5py.File(f'{sample_dir}{model}_{wind}_{snap}_galaxy_sample.h5', 'r') as sf:
        gal_ids = sf['gal_ids'][:]

    for gal_id in gal_ids:

        fig, ax = plt.subplots(len(lines), 2, figsize=(10, 10), sharex='col')

        for i, line in enumerate(lines):

            spec_name = f'sample_galaxy_{gal_id}_{line}_{orient}_{fr200}r200'
            spectrum = read_h5_into_dict(f'{spectra_dir}{spec_name}.h5')
            spectrum['line_list'] = spectrum['line_list']

            ax[i][0].plot(spectrum['velocities'], spectrum['fluxes'], c=cb_blue, ls='-', lw=1)
            ax[i][0].annotate(plot_lines[i], xy=(0.75, 0.05), xycoords='axes fraction')
            ax[i][0].set_xlim(spectrum['gal_velocity_pos'] - vel_range, spectrum['gal_velocity_pos'] + vel_range)
            ax[i][0].set_ylim(0, 1.1)
            ax[i][0].set_ylabel('Flux')

            ax[i][1].plot(spectrum['velocities'], np.log10(spectrum['taus']), c=cb_blue, ls='-', lw=1)
            ax[i][1].set_xlim(spectrum['gal_velocity_pos'] - vel_range, spectrum['gal_velocity_pos'] + vel_range)
            ax[i][1].set_ylim(-6, 1)
            ax[i][1].set_ylabel(r'$\tau$')

            mask = spectrum['line_list']['Chisq'] < chisq_lim[lines.index(line)]
            vels = np.array(wave_to_vel(spectrum['line_list']['l'][mask], spectrum['lambda_rest'], redshift))

            for j in range(len(vels)):
                for k in range(2):
                    ax[i][k].axvline(vels[j], c='k', ls='-', lw=1)

        ax[i][0].set_xlabel('Velocity (km/s)')
        ax[i][1].set_xlabel('Velocity (km/s)')

        plt.tight_layout()
        fig.subplots_adjust(hspace=0.)
        plt.savefig(f'align_plots/sample_galaxy_{gal_id}_{orient}_{fr200}r200.png')
        plt.close()