from green_wheels_app.models import *
from django.http import HttpResponse, JsonResponse
from rest_framework import viewsets
from green_wheels_app.serializers import *

from django.contrib.auth.models import Group
from django.db.models.signals import post_migrate, post_save
from django.dispatch import receiver
from green_wheels_app.permissions import HavePanelAccess, panel_permission
from rest_framework import permissions
from green_wheels_app.auth_views import UserRegister
from green_wheels_app.serializers import UserRegisterSerializer
from django.db.models import Q
import json
from datetime import date

#imports to send an email
from django.core.mail import EmailMessage
from django.template.loader import render_to_string
from django.conf import settings
from green_wheels_app.models import Gw_Employee, Gw_Associate_Headquarter
from rest_framework.response import Response

#imports to create a client from frontend
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from rest_framework import status
from rest_framework.renderers import JSONRenderer

# @name: create_users_groups
# @description: This function is executed when a migration is performed. It
# creates the user groups.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_migrate)
def create_users_groups(sender, **kwargs):
    groups = ['Clients', 'Sellers', 'WorkshopBoss', 'Managers', 'AppAdmin'];
    for group in groups:
        Group.objects.get_or_create(name=group);

# @name: create_default_panels
# @description: This function is executed when a migration is performed. It
# creates the default panels.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_migrate)
def create_default_panels(sender, **kwargs):
    panels = ['test_panel', 'prueba', 'create_seller', 'create_workshopboss', 'create_manager', 'create_vehicle_components',
              'request_sell_service', 'check_inventory', 'check_negotations', 'assign_negotation', 'create_edit_negotation',
              'create_locations', 'manage_users_as_manager', 'manage_users_as_admin', 'assign_repair', 'create_edit_repair_service',
              'assign_replacement_part'];
    for panel in panels:
        Gw_Panel.objects.get_or_create(panel_name=panel);

# @name: default_allowed_panels
# @description: This function is executed when a migration is performed. It
# creates the default relations among user groups and panels.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com
# Sets users groups permission to access panels
'''
id|name        |
--+------------+
 1|Clients     |
 2|Sellers     |
 3|WorkshopBoss|
 4|Manager     |
 5|AppAdmin    |
--------------------------------------
id|panel_name               |
--+-------------------------+
 1|test_panel               |
 2|prueba                   |
 3|create_seller            |
 4|create_workshopboss      |
 5|create_manager           |
 6|create_vehicle_components|
 7|request_sell_service     |
 8|check_inventory          |
 9|check_negotations        |
 10|assign_negotation       |
 11|create_edit_negotation  |
 12|create_locations        |
 13|manage_users_as_manager |
 14|manage_users_as_admin   |
 15|assign_repair           |
 16|create_edit_repair_service |
 17|assign_replacement_part    |

'''
# 1 -> test_panel, 2 -> prueba, 3 -> create_seller
@receiver(post_migrate)
def default_allowed_panels(sender, **kwargs):
    # relation : (panel_id, group_id)
    relations = [(1, 2), (1, 4), (3, 4), (4, 4), (5, 4), (6, 4), (7, 1), (8, 4), (9, 4), (10, 4), (11, 2),
                 (12, 4), (13,4),(14,5), (15,5), (16, 3), (17, 3)];
    for relation in relations:
        group_admin = Group.objects.get(id=5);
        try:
            panel = Gw_Panel.objects.get(id=relation[0]);
            group = Group.objects.get(id=relation[1]);
            Gw_Allowed_Panels.objects.get_or_create(panel_id=panel, group_id=group);
            Gw_Allowed_Panels.objects.get_or_create(panel_id=panel, group_id=group_admin);
        except Exception as e:
            print(e);
            print('It has ocurred an error when creating default allowed panels for users groups');

# @name: Add_Person_To_Clients
# @desc: This function associates the person instance to the group Clients when a
# client is created using the person's id.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_save, sender=Gw_Client)
def Add_Person_To_Clients(sender, instance, created, **kwargs):
    if created:
        person = instance.person_id;
        group, _ = Group.objects.get_or_create(name='Clients');
        person.groups.add(group);

# @name: Add_Person_To_Employees
# @desc: This function associates the person instance to a group related with the
# employees group when an Employees is created using the person's id.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_save, sender=Gw_Employee)
def Add_Person_To_Employees(sender, instance, created, **kwargs):
    if created:
        person = instance.person_id
        if instance.position == 1: # It's a seller
            group_name = 'Sellers';
        elif instance.position == 2: # It's a workshop boss
            group_name = 'WorkshopBoss';
        group, _ = Group.objects.get_or_create(name=group_name);
        person.groups.add(group);

# @name: Add_Person_To_Managers
# @desc: This function associates the person instance to the group Managers when a
# manager is created using the person's id.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_save, sender=Gw_Manager)
def Add_Person_To_Managers(sender, instance, created, **kwargs):
    if created:
        person = instance.person_id;
        group, _ = Group.objects.get_or_create(name='Managers');
        person.groups.add(group);

# @name: Add_Person_To_Admins
# @desc: This function associates the person instance to the group AppAdmin when an
# admin is created using the person's id.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_save, sender=Gw_Admin)
def Add_Person_To_Admins(sender, instance, created, **kwargs):
    if created:
        person = instance.person_id;
        group, _ = Group.objects.get_or_create(name='AppAdmin');
        person.groups.add(group);

# @name: Add_SuperUser_To_Admins
# @description: Add superusers to AppAdmin group.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

@receiver(post_save, sender=Gw_Person)
def Add_SuperUser_To_Admins(sender, instance, created, **kwargs):
    if created:
        is_superuser = instance.is_superuser;
        if (is_superuser):
            Gw_Admin.objects.create(person_id=instance);
            group, _ = Group.objects.get_or_create(name='AppAdmin');
            instance.groups.add(group);

# @name: get_person_data
# @description: This function extract the data from p person object and retrieve it a dictionary.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_person_data(p):
    data = {
            'person_id': p.person_id,
            'id_type': p.id_type,
            'names': p.names,
            'last_names':p.last_names,
            'living_address':p.living_address,
            'birth_date':str(p.birth_date),
            'phone1':p.phone1,
            'phone2':p.phone2,
            'email':p.email,
        }

    return data;

# @name: get_person
# @description: Get person data given an id.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_person(request, id):
    if request.method == 'GET':
        try:
            p = Gw_Person.objects.get(person_id=id);
        except Gw_Person.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a person with " + str(id) + " id",
                                status=404);

        data = get_person_data(p);

        return JsonResponse(data);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_persons_list
# @description: Get the data from all the person objects.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_persons_list(request):
    if request.method == 'GET':
        person_queryset = Gw_Person.objects.all();

        person_dict = [];

        for p in person_queryset:
            person_dict.append(
                get_person_data(p),
            )

        return JsonResponse(person_dict, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_manage_users_list_manager
# @description: Retrieves a list of the users which managers has the permissions to managers.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_manage_users_list_manager(request):
    if request.method == 'GET':
        sellers_list = get_employees_list(request).content.decode('utf-8');

        data = json.loads(sellers_list);

        print(data)

        return JsonResponse(data, status=200, safe=False);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_manage_users_list_admin
# @description: Retrieves a list of the users which managers has the permissions to the admin.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_manage_users_list_admin(request):
    if request.method == 'GET':
        managers_list = get_managers_list(request).content.decode('utf-8');

        data = json.loads(managers_list)

        return JsonResponse(data, status=200, safe=False);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_clients_list
# @description: Get the data from all the client objects
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_clients_list(request):
    if request.method == 'GET':
        client_queryset = Gw_Client.objects.all();

        client_dict = [];

        for c in client_queryset:
            client_obj = get_person_data(c.person_id);
            client_obj['client_id'] = c.client_id;
            client_dict.append(
                client_obj,
            )

        return JsonResponse(client_dict, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_client
# @description: Get client data given a client id
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com
def get_client(request, id):
    if request.method == 'GET':
        try:
            c = Gw_Client.objects.get(client_id=id);
        except Gw_Client.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a client with " + str(id) + " id",
                                status=404);

        data = get_person_data(c.person_id);

        data['client_id'] = c.client_id;

        return JsonResponse(data);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: post_create_seller
# @description: Creates Seller objects.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

#@panel_permission('create_seller')
def post_create_seller(request):
    #if request.method == 'POST':
    try:
        #id = int(json.loads(request.body)['id']);
        id = int(request['id']);
        person_exists = Gw_Person.objects.filter(person_id=id).exists();
        seller_exists = Gw_Employee.objects.filter(Q(person_id=id) & Q(position=1)).exists();
        if (not person_exists):
            return HttpResponse('Person object was not found', status=404);
        elif (seller_exists):
            print(id)
            return HttpResponse('Seller already exists', status=400);
        else:
            person = Gw_Person.objects.get(person_id=id);
            Gw_Employee.objects.create(person_id=person, position=1);
            return HttpResponse('The User has been created', status=200);
    except Exception as e:
        print(e);
        return HttpResponse('An error has ocurred', status=400);
    #else:
     #   return HttpResponse('Unsupported method', status=405);

# @name: create_new_seller
# @description: Allows to create persons instances and assign them automatically into employees group with
# seller position.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def create_new_seller(request):
    if request.method == 'POST':
        try:
            register_instance = UserRegister();

            data = json.loads(request.body.decode('utf-8'));

            register_instance.post(data);

            data_seller = {
                'id': data['person_id']
            }

            post_create_seller(data_seller);

            return HttpResponse('Correcto', status=200);
        except Exception as e:
            print(e);
            return HttpResponse('Error', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: create_new_workshopboss
# @description: Allows to create persons instances and assign them automatically into employees group with
# workshopboss position.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def create_new_workshopboss(request):
    if request.method == 'POST':
        try:
            register_instance = UserRegister();

            data = json.loads(request.body.decode('utf-8'));

            register_instance.post(data);

            data_workshopboss = {
                'id': data['person_id']
            }

            post_create_workshopboss(data_workshopboss);

            return HttpResponse('Correcto', status=200);
        except Exception as e:
            print(e);
            return HttpResponse('Error', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: create_new_manager
# @description: Allows to create persons instances and assign them automatically into managers group.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def create_new_manager(request):
    if request.method == 'POST':
        try:
            register_instance = UserRegister();

            data = json.loads(request.body.decode('utf-8'));

            register_instance.post(data);

            data_manager= {
                'id': data['person_id']
            }

            post_create_manager(data_manager);

            return HttpResponse('Correcto', status=200);
        except Exception as e:
            print(e);
            return HttpResponse('Error', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_group_id_person
# @description: Retrieves the group id for the person with the given person_id and
# given group id.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_group_id_person(request, id, group):
    if (request.method=='GET'):
        user_model = None;
        if group == 'client':
            user_model = Gw_Client;
        elif group == 'employee':
            user_model = Gw_Employee;
        elif group == 'manager':
            user_model = Gw_Manager;
        elif group == 'admin':
            user_model = Gw_Admin;
        else:
            return HttpResponse("Sorry, the specified group does not exist", status=404);

        try:
            group_id = user_model.objects.get(person_id=id).pk;
            print(group_id)
            data = {
                'id':group_id
            };

            return JsonResponse(data);
        except Exception as e:
            print(e);
            return HttpResponse('Sorry, an error has ocurred', status=500);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: post_create_workshopboss
# @description: Creates WorkshopBoss objects.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

#@panel_permission('create_workshopboss')
def post_create_workshopboss(request):
    #if request.method == 'POST':
    try:
        #id = int(json.loads(request.body)['id']);
        id = int(request['id']);
        person_exists = Gw_Person.objects.filter(person_id=id).exists();
        workshop_boss_exists = Gw_Employee.objects.filter(Q(person_id=id) & Q(position=2)).exists();
        if (not person_exists):
            return HttpResponse('Person object was not found', status=404);
        elif (workshop_boss_exists):
            print(id)
            return HttpResponse('workshop_boss already exists', status=400);
        else:
            person = Gw_Person.objects.get(person_id=id);
            Gw_Employee.objects.create(person_id=person, position=2);
            return HttpResponse('The User has been created', status=200);
    except Exception as e:
        print(e);
        return HttpResponse('An error has ocurred', status=400);
    #else:
     #   return HttpResponse('Unsupported method', status=405)

# @name: post_create_manager
# @description: Creates WorkshopBoss objects.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

#@panel_permission('create_manager')
def post_create_manager(request):
    #if request.method == 'POST':
    try:
        #id = int(json.loads(request.body)['id']);
        id = int(request['id']);
        person_exists = Gw_Person.objects.filter(person_id=id).exists();
        manager_exists = Gw_Manager.objects.filter(Q(person_id=id)).exists();
        if (not person_exists):
            return HttpResponse('Person object was not found', status=404);
        elif (manager_exists):
            print(id)
            return HttpResponse('manager already exists', status=400);
        else:
            person = Gw_Person.objects.get(person_id=id);
            Gw_Manager.objects.create(person_id=person);
            return HttpResponse('The User has been created', status=200);
    except Exception as e:
        print(e);
        return HttpResponse('An error has ocurred', status=400);
    #else:
     #   return HttpResponse('Unsupported method', status=405)

# @name: get_employees_list
# @description: Get the data from all the employee objects
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_employees_list(request):
    if request.method == 'GET':
        employee_queryset = Gw_Employee.objects.all();

        employee_dict = [];

        for c in employee_queryset:
            employee_obj = get_person_data(c.person_id);
            employee_obj['employee_id'] = c.employee_id;
            employee_dict.append(
                employee_obj,
            )

        return JsonResponse(employee_dict, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405)

def get_employees_type_list(request, position):
    if request.method == 'GET':
        employee_queryset = Gw_Employee.objects.all();

        employee_dict = [];

        for c in employee_queryset:
            employee_obj = get_person_data(c.person_id);
            if c.position == position:
                employee_obj['employee_id'] = c.employee_id;
                employee_dict.append(
                    employee_obj,
                )

        return JsonResponse(employee_dict, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405)

# @name: get_employee
# @description: Get employee data given a employee id
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_employee(request, id):
    if request.method == 'GET':
        try:
            c = Gw_Employee.objects.get(employee_id=id);
        except Gw_Employee.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a employee with " + str(id) + " id",
                                status=404);

        data = get_person_data(c.person_id);

        data['employee_id'] = c.employee_id;

        return JsonResponse(data);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_managers_list
# @description: Get the data from all the employee objects
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_managers_list(request):
    if request.method == 'GET':
        manager_queryset = Gw_Manager.objects.all();

        manager_dict = [];

        for c in manager_queryset:
            manager_obj = get_person_data(c.person_id);
            manager_obj['manager_id'] = c.manager_id;
            manager_dict.append(
                manager_obj,
            )

        return JsonResponse(manager_dict, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405)

# @name: get_manager
# @description: Get manager data given a manager id
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_manager(request, id):
    if request.method == 'GET':
        try:
            m = Gw_Manager.objects.get(manager_id=id);
        except Gw_Manager.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a manager with " + str(id) + " id",
                                status=404);

        data = get_person_data(m.person_id);

        data['manager_id'] = m.manager_id;

        return JsonResponse(data);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_admins_list
# @description: Get the data from all the employee objects
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_admins_list(request):
    if request.method == 'GET':
        admin_queryset = Gw_Admin.objects.all();

        admin_dict = [];

        for c in admin_queryset:
            admin_obj = get_person_data(c.person_id);
            admin_obj['admin_id'] = c.admin_id;
            admin_dict.append(
                admin_obj,
            )

        return JsonResponse(admin_dict, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_admin
# @description: Get admin data given a admin id
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_admin(request, id):
    if request.method == 'GET':
        try:
            a = Gw_Admin.objects.get(admin_id=id);
        except Gw_Admin.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a admin with " + str(id) + " id",
                                status=404);

        data = get_person_data(a.person_id);

        data['admin_id'] = a.admin_id;

        return JsonResponse(data);

    else:
        return HttpResponse('Unsupported method', status=405);

def get_user_groups(request, id):
    if request.method == 'GET':
        try:
            p = Gw_Person.objects.get(person_id=id);
        except Gw_Person.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a person with " + str(id) + " id",
                                    status=404);

        groups = p.groups.values();

        groups_list = [];

        for g in groups:
            groups_list.append(g['name']);

        # print(groups_list);

        data = {
            'groups':groups_list#groups_list
        };

        return JsonResponse(data);#JsonResponse(data);

    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_allowed_panels
# @description: Retrivies a list of the panels which the user has access.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_allowed_panels(request, id):
    if request.method == 'GET':
        try:
            person = Gw_Person.objects.get(person_id=id);

            groups_id = person.groups.values('id')

            groups_id_list = [];

            for g in groups_id:
                groups_id_list.append(g['id']);

            panels = Gw_Allowed_Panels.objects.filter(group_id__in=groups_id_list).values('panel_id__panel_name');

            panels_list = [];

            for panel in panels:
                panels_list.append(panel['panel_id__panel_name']);

            data = {
                'panels':panels_list
            }

            return JsonResponse(data);

        except Gw_Person.DoesNotExist:
            return HttpResponse("Sorry, it does not exist a person with " + str(id) + " id",
                                    status=404);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_workshopboss_assigned_repairs
# @description: Get all the repairs assigned to a workshopboss
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_workshopboss_assigned_repairs(request, id):
    if request.method == 'GET':

        list_repairs_services_id = list(Gw_Service_Diagnosis_Vehicle.objects.all().values_list('id', flat=True));

        query = Gw_Attended_Process.objects.filter(Q(employee_id=id) & Q(service_id__in=list_repairs_services_id)
                                                   ).values(
                                                                          'id',
                                                                          'employee_id',
                                                                          'attended_date',
                                                                          'finished_date',
                                                                          'service_id');

        data = [];

        for elem in query:
            if not elem['finished_date']:
                data.append({'id':elem['id'],
                    'employee_id':elem['employee_id'],
                                'attended_date':elem['attended_date'],
                                'finished_date':elem['finished_date'],
                                'service_id':elem['service_id']});

        return JsonResponse(data, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_seller_assigned_negotations
# @description: Get all the negotations assigned to a seller
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_seller_assigned_negotations(request, id):
    if request.method == 'GET':

        list_sell_services_id = list(Gw_Service_Sell_Vehicle.objects.all().values_list('id', flat=True));

        query = Gw_Attended_Process.objects.filter(Q(employee_id=id) & Q(service_id__in=list_sell_services_id)
                                                   ).values(
                                                                          'id',
                                                                          'employee_id',
                                                                          'attended_date',
                                                                          'finished_date',
                                                                          'service_id');

        data = [];

        for elem in query:
            if not elem['finished_date']:
                data.append({'id':elem['id'],
                    'employee_id':elem['employee_id'],
                                'attended_date':elem['attended_date'],
                                'finished_date':elem['finished_date'],
                                'service_id':elem['service_id']});

        return JsonResponse(data, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

def get_vehicles_components_headquarter(request, id):
    if request.method == 'GET':
        query_vehicles = Gw_Vehicle_Inventory.objects.filter(concessionaire_id__headquarter_id=id).values('model_id__name',
                                                                                'quantity');
        query_replacements = Gw_Replacement_Inventory.objects.filter(workshop_id__headquarter_id=id).values('replacement_id__name',
                                                                                'quantity');

        data = [];

        data_vehicles = [];

        data_replacements = [];

        for v in query_vehicles:
            data_vehicles.append({'model':v['model_id__name'], 'quantity':v['quantity']});

        for r in query_replacements:
            data_replacements.append({'replacement':r['replacement_id__name'], 'quantity':v['quantity']});

        data.append({'vehicles_inventory':data_vehicles});
        data.append({'replacement_inventory':data_replacements});

        return JsonResponse(data, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: create_request_sell_service
# @description: This endpoint allows to create requested_process instances assign to sell_service instances.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def create_request_sell_service(request):
    if request.method == 'POST':
        try:
            data = request.body.decode('utf-8');
            response = aux_create_sell_service_and_negotation(request.user, json.loads(data));
            new_data = response.content.decode('utf-8');

            service_instance_id = json.loads(new_data)['id'];

            service_instance = Gw_Service_Sell_Vehicle.objects.get(id=service_instance_id);

            Gw_Request_Process.objects.create(service_id=service_instance, requested_date=date.today(), attended=False);
        except Exception:
            return HttpResponse('Ha ocurrido une error', status=500);

        return HttpResponse('Exito', status=200);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: aux_create_diagnosis_repair_service
# @description: This method creates a sell_service that is already associated with an empty negotation
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def aux_create_diagnosis_repair_service(user, data):
    try:
        user = user;

        empty_diagnosis_data = {
            'vehicle_plate':data['vehicle_plate'],
            'client_id':data['client_id'],
            'description':'empty',
            'date':None,
            'price':0,
            'mechanic_id':0,
            'mechanic_name':'empty',

        }

        diagnosis_serializer = Gw_Diagnosis_Viewset.serializer_class(data=empty_diagnosis_data,
                                                                    context={'author':user});

        if diagnosis_serializer.is_valid():

            diagnosis_serializer.save();
            diagnosis_id = diagnosis_serializer.data['id'];
            print("Hola" + str(diagnosis_id))
            repair_service_data = {
                "mechanic_name":"empty",
                "mechanic_id":0,
                "diagnosis_id":diagnosis_id,
                "workshop_id":data['workshop_id']
                }

            repair_service_serializer = Gw_Repair_Vehicle_Service_Viewset.serializer_class(data=repair_service_data,
                                            context={'author': user})

            if repair_service_serializer.is_valid():
                repair_service_serializer.save()
                return JsonResponse(diagnosis_serializer.data, status=status.HTTP_201_CREATED);
            else:
                return JsonResponse(repair_service_serializer.errors, status=status.HTTP_400_BAD_REQUEST);
    except Exception as e:
        print(e);
        return HttpResponse("Ha ocurrido un error", status=500);
    else:
        return JsonResponse(diagnosis_serializer.errors, status=status.HTTP_400_BAD_REQUEST);

# @name: create_repair_vehicle_service
# @description: This endpoint allows to create requested_process instances assign to sell_service instances.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def create_repair_vehicle_service(request):
    if request.method == 'POST':
        try:
            data = request.body.decode('utf-8');

            response = aux_create_diagnosis_repair_service(request.user, json.loads(data));
            new_data = response.content.decode('utf-8');

            service_instance_id = json.loads(new_data)['id'];

            print(service_instance_id)

            service_instance = Gw_Service_Diagnosis_Vehicle.objects.get(id=service_instance_id);

            Gw_Request_Process.objects.create(service_id=service_instance, requested_date=date.today(), attended=False);
        except Exception as e:
            print(e);
            return HttpResponse('Ha ocurrido une error', status=500);

        return HttpResponse('Exito', status=200);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_negotation_details_by_seller
# @description: This endpoint retrieves in a list the data of the negotations that are assigned to an user
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_negotation_details_by_seller(request, id):
    if request.method == 'GET':
        try:
            employee_id = Gw_Employee.objects.get(person_id=id).employee_id;

            list_services_id = Gw_Attended_Process.objects.filter(employee_id=employee_id).values('service_id__id');

            repair_services_queryset = Gw_Service_Sell_Vehicle.objects.filter(Q(id__in=list_services_id)).values(
                'negotation_id__id',
                'negotation_id__final_sale_price',
                'negotation_id__last_modification_date',
                'negotation_id__pay_method',
                'negotation_id__description'
            );

            data = [];

            for e in repair_services_queryset:
                data.append({
                    'id':e['negotation_id__id'],
                    'last_modification_date':e['negotation_id__last_modification_date'],
                    'final_sale_price':e['negotation_id__final_sale_price'],
                    'pay_method':e['negotation_id__pay_method'],
                    'description':e['negotation_id__description']
                });

            print(repair_services_queryset[0])

            return JsonResponse(data, status=200, safe=False);

        except Exception as e:
            print(e);
            return HttpResponse('Ha ocurrido un error', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_repair_details_by_workshopboss
# @description: This endpoint retrieves in a list the data of the repairs that are assigned to an user
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_repair_details_by_workshopboss(request, id):
    if request.method == 'GET':
        try:
            employee_id = Gw_Employee.objects.get(person_id=id).employee_id;

            list_services_id = Gw_Attended_Process.objects.filter(employee_id=employee_id).values('service_id__id');

            repair_services_queryset = Gw_Repair_Vehicle.objects.filter(diagnosis_id__id__in=list_services_id).values(
                'id',
                'mechanic_name',
                'mechanic_id',
                'diagnosis_id',
                'workshop_id',
            );

            data = [];

            for e in repair_services_queryset:
                data.append({
                    'id':e['id'],
                    'mechanic_name':e['mechanic_name'],
                    'mechanic_id':e['mechanic_id'],
                    'diagnosis_id':e['diagnosis_id'],
                    'workshop_id':e['workshop_id'],
                });

            print(data);
            return JsonResponse(data, status=200, safe=False);
        except Exception as e:
            print(e);
            return HttpResponse('Ha ocurrido un error', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: set_finish_date_attended_process
# @description: This function sets an attended process's date to the current one indicating that
# the given process was finished or eliminated.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def set_finish_date_attended_process(request, id):
    if request.method == 'PUT':
        try:
            process = Gw_Attended_Process.objects.get(id=id);

            process.finished_date = date.today();

            process.save();

            return HttpResponse('Correcto', status=200);
        except Exception as e:
            print(e);
            return HttpResponse('An error has ocurred', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: Gw_Brand_Viewset
# @description: Viewset for brand model
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Brand_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Brand.objects.all();
    serializer_class = Gw_Brand_Serializer;
    def get_permissions(self):
        return [permissions.IsAuthenticated(), HavePanelAccess('create_vehicle_components')];

# @name: Gw_Vehicle_Model_Viewset
# @description: Viewset for vehicles models
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Vehicle_Model_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Vehicle_Model.objects.all();
    serializer_class = Gw_Vehicle_Model_Serializer;
    def get_permissions(self):
        return [permissions.IsAuthenticated(), HavePanelAccess('create_vehicle_components')];

# @name: Gw_Vehicle_Viewset
# @description: Viewset for vehicles
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Vehicle_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Vehicle.objects.all();
    serializer_class = Gw_Vehicle_Serializer;
    def get_permissions(self):
        return [permissions.IsAuthenticated(), HavePanelAccess('create_vehicle_components')];

# @name: check_attended_sell_request
# @description: Marks a sell request as attended
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def check_attended_sell_request(request):
    if request.method == 'POST':
        try:
            request_id = request.POST.data.request_id;

            sell_request = Gw_Request_Process.objects.get(id=request_id);

            sell_request.attended =  True;

            sell_request.save();

            return HttpResponse('Correcto', status=200);
        except Exception as e:
            print(e);
            return HttpResponse('Ha ocurrido un error', status=400);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: aux_create_sell_service_and_negotation
# @description: This method creates a sell_service that is already associated with an empty negotation
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def aux_create_sell_service_and_negotation(user, data):

    user = user;

    empty_negotation_data = {
        'last_modification_date':'2000-01-01',
        'final_sale_price':0,
        'pay_method':1,
        'description':'empty'
    }

    negotation_serializer = Gw_Negotations_Viewset.serializer_class(data=empty_negotation_data,
                                    context={'author':user});

    if negotation_serializer.is_valid():

        negotation_serializer.save();
        negotation_id = negotation_serializer.data['id'];

        sell_service_data = {
            "vehicle_plate": data['vehicle_plate'],
            "client_id": data['client_id'],
            "negotation_id": negotation_id,
            "concessionaire_id": data['concessionaire_id']
            }

        sell_service_serializer = Gw_Service_Sell_Vehicle_Viewset.serializer_class(data=sell_service_data,
                                        context={'author': user})

        if sell_service_serializer.is_valid():
            sell_service_serializer.save()
            return JsonResponse(sell_service_serializer.data, status=status.HTTP_201_CREATED);
        else:
            return JsonResponse(sell_service_serializer.errors, status=status.HTTP_400_BAD_REQUEST);

    else:
        return JsonResponse(negotation_serializer.errors, status=status.HTTP_400_BAD_REQUEST);

# @name: get_list_requested_sell_services
# @description: Get the list of sell services requests.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_list_requested_sell_services(request):
    if request.method == 'GET':
        queryset = Gw_Service_Sell_Vehicle.objects.all();

        queryset_list = [];

        for q in queryset:
            if Gw_Request_Process.objects.filter(service_id=q.id).exists():
                requested_process = Gw_Request_Process.objects.get(service_id=q.id);
                queryset_list.append({
                    'id':requested_process.id,
                    'requested_date':str(requested_process.requested_date),
                    'attended':requested_process.attended,
                    'service_id':requested_process.service_id.id
                });

        return JsonResponse(queryset_list, status=200, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: get_list_requested_repair_services
# @description: Get the list of repair services requests.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

def get_list_requested_repair_services(request):
    if request.method == 'GET':
        queryset = Gw_Service_Diagnosis_Vehicle.objects.all();

        queryset_list = [];

        for q in queryset:
            if Gw_Request_Process.objects.filter(service_id=q.id).exists():
                requested_process = Gw_Request_Process.objects.get(service_id=q.id);
                queryset_list.append({
                    'id':requested_process.id,
                    'requested_date':str(requested_process.requested_date),
                    'attended':requested_process.attended,
                    'service_id':requested_process.service_id.id
                });

        return JsonResponse(queryset_list, status=200, safe=False);
    else:
        return HttpResponse('Unsupported method', status=405);

# @name: Gw_Service_Sell_Vehicle_Viewset
# @description: Viewset for service sell vehicles model
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Service_Sell_Vehicle_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Service_Sell_Vehicle.objects.all();
    serializer_class = Gw_Service_Sell_Vehicle_Serializer;

    def create(self, request, *args, **kwargs):
        return aux_create_sell_service_and_negotation(request.user, request.data);

# @name: Gw_Negotation_Viewset
# @description: Viewset for negotations.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Negotations_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Negotation.objects.all();
    serializer_class = Gw_Negotations_Serializer;
    # def get_permissions(self):
    #     return [permissions.IsAuthenticated(), HavePanelAccess('create_negotiation_panel')];

# @name: Gw_Headquarter_Viewset
# @description: Viewset for Headquarters
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Headquarter_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Headquarter.objects.all();
    serializer_class = Gw_Headquarter_Serializer;

# @name: Gw_Concessionaire_Viewset
# @description: Viewset for Concessionaires
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Concessionaire_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Concessionaire.objects.all();
    serializer_class = Gw_Concessionaire_Serializer;

# @name: Gw_Workshop_Viewset
# @description: Viewset for workshop model
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Workshop_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Workshop.objects.all();
    serializer_class = Gw_Workshop_Serializer;

# @name: Gw_Replacement_Inventory_Viewset
# @description: Viewset for replacements inventory model.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Replacement_Inventory_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Replacement_Inventory.objects.all();
    serializer_class = Gw_Replacement_Inventory_Serializer;

# @name: Gw_Request_Process_Viewset
# @description: Viewset for request process models
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Request_Process_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Request_Process.objects.all();
    serializer_class = Gw_Request_Process_Serializer;

    # def create(self, request, *args, **kwargs):
    #     user = request.user;

    #     data = request.data;

    #     print(data)

    #     process_data = {
    #         'employee_id':data['employee_id'],
    #         'attended_date':data['attended_date'],
    #         'finished_date':data['finished_date'],
    #         'service_id':data['service_id']
    #     }

    #     process_serializer = self.serializer_class(data=process_data,
    #                                     context={'author':user});

    #     if process_serializer.is_valid():
    #         process_serializer.save();

    #         was_requested = Gw_Request_Process.objects.filter(
    #             service_id=process_data['service_id']).exists();

    #         if was_requested:
    #             requested_process = Gw_Request_Process.objects.get(service_id=process_data['service_id']);

    #             requested_process.attended = True;

    #             requested_process.save();

    #         return JsonResponse(process_serializer.data, status=status.HTTP_201_CREATED);
    #     else:
    #         return JsonResponse(process_serializer.errors, status=status.HTTP_400_BAD_REQUEST);

# @name: Gw_Attended_Process_Viewset
# @description: Viewset for attended process model.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Attended_Process_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Attended_Process.objects.all();
    serializer_class = Gw_Attended_Process_Serializer;

# @name: Gw_Repair_Vehicle_Service_Viewset
# @description: Viewset for repair vehicle service
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Repair_Vehicle_Service_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Repair_Vehicle.objects.all();
    serializer_class = Gw_Repair_Vehicle_Service_Serializer;

# @name: Gw_Diagnosis_Viewset
# @description: Viewset for diagnosis
# @author: Nicol Valeria Ortiz R.
# @email: nicol.ortiz@correounivalle.edu.co, nicolvaleria0919@gmail.com

class Gw_Diagnosis_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Service_Diagnosis_Vehicle.objects.all();
    serializer_class = Gw_Diagnosis_Serializer;

    def create(self, request, *args, **kwargs):
        return aux_create_diagnosis_repair_service(request.user, request.data);
    #def get_permissions(self):
     #   return [permissions.IsAuthenticated(), HavePanelAccess('create_diagnosis_panel')];

# @name: Gw_Replacement_Viewset
# @description: Viewset for replacement part
# @author: Nicol Valeria Ortiz R.
# @email: nicol.ortiz@correounivalle.edu.co, nicolvaleria0919@gmail.com

class Gw_Replacement_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Replacement_Part.objects.all();
    serializer_class = Gw_Replacement_Part_Serializer;
    #def get_permissions(self):
     #   return [permissions.IsAuthenticated(), HavePanelAccess('create_replacement_panel')];

# @name: Gw_Vehicle_Inventory_Viewset
# @description: Viewset for vehicle inventory viewset
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Vehicles_Inventory_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Vehicle_Inventory.objects.all();
    serializer_class = Gw_Vehicle_Inventory_Serializer;

# @name: Gw_Needed_Replacement_Part_Viewset
# @description: Viewset for needed replacements part model's instances.
# @author: Paul Rodrigo Rojas G.
# @email: paul.rojas@correounivalle.edu.co, PaulRodrigoRojasECL@gmail.com

class Gw_Needed_Replacement_Part_Viewset(viewsets.ModelViewSet):
    queryset = Gw_Needed_Replacement_Part.objects.all();
    serializer_class = Gw_Needed_Replacement_Part_Serializer;

# This endpoint is just for testing.
def index_render(request):
    print(Gw_Allowed_Panels)
    return HttpResponse("Welcome to Greeen Wheels!");

# @name: send_email
# @description: Receive the data from frontend and send email
# @author: Nicol Valeria Ortiz Rodríguez
# @email: nicol.ortiz@correounivalle.edu.co, nicolvaleria0919@gmail.com

@panel_permission('send_email')
def send_email(request):
    if request.method == 'POST':
        data = json.loads(request.body)  # Obtener los datos enviados por POST como JSON
        correo_destinatario = data['correo_destinatario']
        asunto = data['asunto']
        mensaje = data['mensaje']

        template = render_to_string('email_template.html', {
            'correo_destinatario': correo_destinatario,
            'asunto': asunto,
            'mensaje': mensaje
        })

        email = EmailMessage(
            asunto,
            template,
            settings.EMAIL_HOST_USER,
            correo_destinatario.split(',')
        )

        email.fail_silently = False
        email.send()

        return JsonResponse({'message': 'Exito'})

# @name: get_employees_email
# @description: Get all employees with same headquater as the manager
# @author: Nicol Valeria Ortiz Rodríguez
# @email: nicol.ortiz@correounivalle.edu.co, nicolvaleria0919@gmail.com

def get_employees_email(request):
    if request.method == 'GET':
        gw_manager_id = request.user.person_id
        gw_manager_headquarter_id = Gw_Associate_Headquarter.objects.get(person_id=gw_manager_id).headquarter_id_id
        headquarter_list_ass = Gw_Associate_Headquarter.objects.all()
        employee_emails = []

        for headq in headquarter_list_ass:
            if (headq.headquarter_id_id == gw_manager_headquarter_id):
                employee_email = headq.person_id.email
                person = Gw_Person.objects.get(person_id=headq.person_id.person_id);
                if (person.person_id != gw_manager_id):
                    groups = person.groups.values();
                    id_groups = []
                    for g in groups:
                        id_groups.append(g['id'])
                    employee_emails.append((employee_email,id_groups))

        return JsonResponse(employee_emails, safe=False)
    else:
        return HttpResponse('Unsupported method', status=405)

# @name: create_client
# @description: Get the data send by the frontend and store object client
# @author: Nicol Valeria Ortiz Rodríguez
# @email: nicol.ortiz@correounivalle.edu.co, nicolvaleria0919@gmail.com

@api_view(['POST'])
@permission_classes([AllowAny])
def create_client(request):
    user_register = UserRegister()
    response = user_register.post(request)

    if response.status_code == status.HTTP_201_CREATED:
        response.accepted_renderer = JSONRenderer()  # Establecer el renderizador aceptado como JSONRenderer
        response.accepted_media_type = 'application/json'  # Establecer el tipo de medio aceptado
        response.renderer_context = {}  # Establecer el contexto del renderizador como un diccionario vacío
        response.render()  # Renderizar la respuesta antes de acceder a su contenido

        data = json.loads(response.content)
        person_id = data.get('person_id')

        if person_id:
            gw_person = Gw_Person.objects.get(person_id=person_id)  # Obtener la instancia de Gw_Person correcta
            client = Gw_Client.objects.create(person_id=gw_person)
            client.save()
            print('esta es:', gw_person)
            return JsonResponse({'message': 'Éxito'})

    return JsonResponse({'message': 'Error'}, status=status.HTTP_400_BAD_REQUEST)


###-----satellite image to maps translation using pix2pix GAN--------###

### --------------------libraries--------------------###
##-----torch------##
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import DataLoader
from torch import randn

##---torchvision---##
import torchvision
from torchvision import models,transforms,datasets

#----torchsummary
from torchsummary import summary

#-----numpy
import numpy as np
from numpy.random import randint

#-----map=tplotlib
import matplotlib.pyplot as plt

#-----additional libraries
import os
import sys

### -------------GENERATOR MODEL -----------------###
class create_generator(nn.Module):
    def __init__(self):
        super().__init__()

        #channels=[3,64,128,256,512,512,512,512]
        ### bias don't need in large netowrks
        ### being inplace True in activation function create problem in some cases

        ###---------ENCODER----------###
        self.encoder_1=nn.Conv2d(3,64,4,2,1,bias=False)

        self.encoder_2=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(64,128,4,2,1,bias=False),
                nn.BatchNorm2d(128)
        )

        self.encoder_3=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(128,256,4,2,1,bias=False),
                nn.BatchNorm2d(256)
        )

        self.encoder_4=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(256,512,4,2,1,bias=False),
                nn.BatchNorm2d(512)
        )

        self.encoder_5=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(512,512,4,2,1,bias=False),
                nn.BatchNorm2d(512)
        )

        self.encoder_6=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(512,512,4,2,1,bias=False),
                nn.BatchNorm2d(512)
        )

        self.encoder_7=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(512,512,4,2,1,bias=False),
                nn.BatchNorm2d(512)
        )

        ### ----------BOTTLE_NECK--------------###

        self.bottleneck=nn.Sequential(
                nn.LeakyReLU(.2,False),
                nn.Conv2d(512,512,4,2,1,bias=False)

        )

        ### ------------DECODER--------------###

        self.decoder_1=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(512,512,4,2,1,bias=False),
            nn.BatchNorm2d(512),
            nn.Dropout(.5)
        )

        self.decoder_2=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(1024,512,4,2,1,bias=False),
            nn.BatchNorm2d(512),
            nn.Dropout(.5)
        )

        self.decoder_3=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(1024,512,4,2,1,bias=False),
            nn.BatchNorm2d(512),
            nn.Dropout(.5)
        )

        self.decoder_4=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(1024,512,4,2,1,bias=False),
            nn.BatchNorm2d(512),
        )

        self.decoder_5=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(1024,256,4,2,1,bias=False),
            nn.BatchNorm2d(256),
        )

        self.decoder_6=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(512,128,4,2,1,bias=False),
            nn.BatchNorm2d(128),
        )

        self.decoder_7=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(256,64,4,2,1,bias=False),
            nn.BatchNorm2d(64),
        )

        self.decoder_8=nn.Sequential(
            nn.ReLU(),
            nn.ConvTranspose2d(128,3,4,2,1,bias=False),
            nn.Tanh()
        )

    def forward(self,x):
        ##----------encoder------------##
        enc_1=self.encoder_1(x)
        enc_2=self.encoder_2(enc_1)
        enc_3=self.encoder_3(enc_2)
        enc_4=self.encoder_4(enc_3)
        enc_5=self.encoder_5(enc_4)
        enc_6=self.encoder_6(enc_5)
        enc_7=self.encoder_7(enc_6)

        # --------bottle neck---------##
        bottle_neck=self.bottleneck(enc_7)

        ## -------decoder ------------##

        dec_1= torch.cat([self.decoder_1(bottle_neck),enc_7],dim=1)
        dec_2=torch.cat([self.decoder_2(dec_1),enc_6],dim=1)
        dec_3=torch.cat([self.decoder_3(dec_2),enc_5],dim=1)
        dec_4=torch.cat([self.decoder_4(dec_3),enc_4],dim=1)
        dec_5=torch.cat([self.decoder_5(dec_4),enc_3],dim=1)
        dec_6=torch.cat([self.decoder_6(dec_5),enc_2],dim=1)
        dec_7=torch.cat([self.decoder_7(dec_6),enc_1],dim=1)

        output=self.decoder_8(dec_7)

        return output

## model checking
generator=create_generator()
data=randn((1,3,256,256))
print(generator(data))

class create_discriminator(nn.Module):
    def __init__(self):
        super().__init__()
        self.layer_1=nn.Sequential(
                nn.Conv2d(6,64,4,2,1,bias=False),
                nn.LeakyReLU(.2)

            )

        self.layer_2=nn.Sequential(
                nn.Conv2d(64,128,4,2,1,bias=False),
                nn.BatchNorm2d(128),
                nn.LeakyReLU(.2)

            )

        self.layer_3=nn.Sequential(
                nn.Conv2d(128,256,4,2,1,bias=False),
                nn.BatchNorm2d(256),
                nn.LeakyReLU(.2)

            )

        self.layer_4=nn.Sequential(
                nn.Conv2d(256,512,4,2,1,bias=False),
                nn.BatchNorm2d(512),
                nn.LeakyReLU(.2)

            )

        self.layer_5=nn.Sequential(
                nn.Conv2d(512,512,4,1,1,bias=False),
                nn.BatchNorm2d(512),
                nn.LeakyReLU(.2)

            )

        self.layer_6=nn.Sequential(
                nn.Conv2d(512,1,4,1,1,bias=False),
                nn.Sigmoid()

            )

    def forward(self,x):
        x=self.layer_1(x)
        x=self.layer_2(x)
        x=self.layer_3(x)
        x=self.layer_4(x)
        x=self.layer_5(x)
        x=self.layer_6(x)

        return x
## model checking
discriminator=create_discriminator()
data=randn((1,6,256,256))
print(discriminator(data))

def weights_init(m):
    name=m.__class__.__name__

    if (name.find('Conv')>-1):
        nn.init.normal_(m.weight.data,.0,.02)
    elif(name.find('BatchNorm')>-1):
        nn.init.normal_(m.weight.data,1.0,.02)
        nn.init.constant_(m.bias.data,.0)

####////////////--data import --////////////////////////////////////////////////////////////////////////////

path=os.getcwd()
data_dir = "maps_torch"

data_transform = transforms.Compose([
    transforms.Resize((256, 512)),
    transforms.CenterCrop((256, 512)),
    transforms.RandomVerticalFlip(p=0.5),
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])

dataset_train = datasets.ImageFolder(root=os.path.join(path,data_dir, "train"), transform=data_transform)
dataset_val = datasets.ImageFolder(root=os.path.join(path,data_dir, "val"), transform=data_transform)

dataloader_train=DataLoader(dataset_train,batch_size=1,shuffle=True)
dataloader_val=DataLoader(dataset_val,batch_size=len(dataset_val),shuffle=True)

print(f'data loader train len:{len(dataloader_train)}')
print(f'data loader val len:{len(dataloader_val)}')

def data_visualtion(image,samplenum):
    image=image.permute(0,2,3,1)

    index=randint(0,len(image),samplenum)

    for i in range(samplenum):
        img=image[index[i]].detach()

        img=np.asarray(img)
        img=(((img+1)/2)*255).astype('uint8')
        plt.imshow(img)
        plt.show()

images,_=next(iter(dataloader_train))
data_visualtion(images,1)

###//////////////////////////////////////////////////////////////////////////////////////###
             ### training process ###

def model_training(generator,discriminator,dataset,numepoch):

    generator.to(device)
    discriminator.to(device)

    optimizerGene=optim.Adam(generator.parameters(),lr=.0002,betas=(.5,.99))
    optimizerDis=optim.Adam(discriminator.parameters(),lr=.0002,betas=(.5,.99))

    loss_function_dis=nn.BCELoss()
    loss_function_genL1=nn.L1Loss()
    l1_loss_weight=100

    for epoch in range(numepoch):
        batch=0

        for data,_ in dataset:

            ####------------------discrimintor----------------------------####

            satellite=data[:,:,:,:256].to(device)
            google_map=data[:,:,:,256:].to(device)

            discriminator.zero_grad()

            ###/////////////////////////////////////////////////////////////////////////////
            real_data=torch.cat([satellite,google_map],dim=1)
            real_out=discriminator(real_data)
            real_labels=torch.ones(size=real_out.shape,dtype=torch.float,device=device)

            loss_dis_real=.5*loss_function_dis(real_out,real_labels)
            loss_dis_real.backward()

            ###//////////////////////////////////////////////////////////////////////////////
            generated_data=generator(satellite)
            fake_data=torch.cat([satellite,generated_data],dim=1)
            fake_out=discriminator(fake_data)
            fake_labels=torch.zeros(size=fake_out.shape,dtype=torch.float,device=device)

            loss_dis_fake=.5*loss_function_dis(fake_out,fake_labels)
            loss_dis_fake.backward()

            optimizerDis.step()

            ###------------------- generator -----------------------------####

            generator.zero_grad()

            generatedImg=generator(satellite)

            gene_data=torch.cat([satellite,generatedImg],dim=1)
            output=discriminator(gene_data)
            gene_labels=torch.ones(size=output.shape,dtype=torch.float,device=device)

            BinCrossLoss=loss_function_dis(output,gene_labels)
            L1_loss=loss_function_genL1(generatedImg,google_map)

            lossGene=BinCrossLoss+l1_loss_weight*L1_loss
            lossGene.backward()
            optimizerGene.step()

            ###////////////////// message ////////////////////////////////////////////////
            batch=batch+1

            msg=(f'epoch:{epoch+1},-- batch :{batch}')
            sys.stdout.write('\r'+msg)

    torch.save(generator,'torch_generator.pth')
    torch.save(discriminator,'torch_discriminator.pth')

    return generator,discriminator

device= torch.device('cuda' if torch.cuda.is_available() else 'cpu')
print(device)

GeneratorModel=create_generator()
Discriminator=create_discriminator()

GeneratorModel.apply(weights_init)
Discriminator.apply(weights_init)

GeneratorModel=torch.load('torch_generator.pth')
Discriminator=torch.load('torch_discriminator.pth')

GeneratorModel,Discriminator=model_training(GeneratorModel, Discriminator, dataloader_train, 5)

####////////////////////////////////////////////////////////////////////////////////////////////////////////////
                     #### GENERATOR MODEL TESTING ####
def data_visualtion_3part(generated,satellite,maps,samplenum):
    generated=generated.permute(0,2,3,1)
    satellite=satellite.permute(0,2,3,1)
    maps=maps.permute(0,2,3,1)

    index=randint(0,len(generated),samplenum)

    for i in range(samplenum):
        gene=generated[index[i]].detach()
        satel=satellite[index[i]].detach()
        mapimg=maps[index[i]].detach()

        gene=np.asarray(gene)
        gene=(((gene+1)/2)*255).astype('uint8')

        satel=np.asarray(satel)
        satel=(((satel+1)/2)*255).astype('uint8')

        mapimg=np.asarray(mapimg)
        mapimg=(((mapimg+1)/2)*255).astype('uint8')

        fig,ax=plt.subplots(1,3,figsize=(10,6))
        ax[0].imshow(satel)
        ax[1].imshow(mapimg)
        ax[1].set_title('orginal')
        ax[2].imshow(gene)
        ax[2].set_title('generated')
        plt.show()

data,_=next(iter(dataloader_val))
samplenum=1
index=randint(0,len(data),samplenum)

satellite=data[index,:,:,:256].to(device)
maps=data[index,:,:,256:].to(device)

model=torch.load('torch_generator.pth')
model.to(device)

generatedImg=model(satellite)

data_visualtion_3part(generatedImg.cpu(),satellite.cpu(),maps.cpu(),samplenum)


import hashlib
import requests
import time
import binascii
cookie={'PHPSESSID':'9fvoqsjb6c9unl6ju54odgd2d5'}
task ="14"

url = "https://ringzer0team.com/challenges/"+task

def hash512(data):
	return hashlib.sha512(data).hexdigest()

def decode_binary_string(s):
	return ''.join(chr(int(s[i*8:i*8+8],2)) for i in range(len(s)//8))

def submit_flag(data):
	r = requests.get("https://ringzer0team.com/challenges/"+task+"/"+data,cookies=cookie)
	return r.content

def text(data):
	htmlContent = data
	begin = htmlContent.find("BEGIN")+33
	end = htmlContent.find("END")-20
	recv = htmlContent[begin:end]
	return recv

def main(data):
	recv = text(str(data))
	print("recv : ",recv,decode_binary_string(recv))
	rec = decode_binary_string(recv)
	getHash = hash512(rec.encode())
	msg = submit_flag(str(getHash))
	if "FLAG" in str(msg):
		msg = str(msg)
		print(msg[msg.find("FLAG"):msg.find("FLAG")+33])

if __name__ == '__main__':
	r1 = requests.get(url, cookies=cookie)
	print("[+] Connect ")
	main(r1.content)

	#print(main(a))


from collections import deque
from heapq import heapify,heappop,heappush

import sys

readline = sys.stdin.readline
Q = int(readline())
S1 = deque()
S2 = []
heapify(S2)
for _ in range(Q):
    query = list(map(int, input().split()))
    q = query[0]
    if q == 1:
        x = query[1]
        S1.append(x)

    elif q == 2:
        if len(S2) == 0:
            print(S1.popleft())

        else:
            print(heappop(S2))
    else:  # q == 3
        while S1:
            heappush(S2,S1.popleft())


from typing import Optional

from sqlalchemy import insert, select, update
from sqlalchemy.ext.asyncio import AsyncSession

from .models import Message, Role, User

async def get_user(db: AsyncSession, user_id: int) -> Optional[User]:
    query = select(User).filter_by(id=user_id)
    result = await db.execute(query)
    return result.scalar_one_or_none()

async def create_user(
    db: AsyncSession,
    user_id: int,
    first_name: str,
    last_name: Optional[str] = None,
    username: Optional[str] = None,
):
    exist = await get_user(db, user_id)
    if not exist:
        stmt = (
            insert(User)
            .values(
                id=user_id,
                first_name=first_name,
                last_name=last_name,
                username=username,
            )
            .returning(User.id)
        )
        await db.execute(stmt)

async def add_message(
    db: AsyncSession,
    user_id: int,
    role: Role,
    content: Optional[str] = None,
) -> int:
    stmt = (
        insert(Message)
        .values(
            user_id=user_id,
            role=role,
            content=content,
        )
        .returning(Message.id)
    )
    insert_result = await db.execute(stmt)
    return insert_result.scalar_one()

async def get_context(db: AsyncSession, user_id: int):
    stmt = select(Message).filter_by(user_id=user_id, is_in_context=True)
    insert_result = await db.execute(stmt)
    return insert_result.scalars().all()

async def clear_context(db: AsyncSession, user_id: int) -> None:
    stmt = (
        update(Message)
        .where(
            Message.user_id == user_id,
            Message.is_in_context.is_(True),
        )
        .values(is_in_context=False)
    )
    await db.execute(stmt)


from tkinter import *
from tkinter import ttk
from tkinter import messagebox
from tkinter import filedialog
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg,NavigationToolbar2Tk
import matplotlib.pyplot as plt
import numpy as np
import math

#Inicializamos la ventana
main = Tk()

def infoAdicional():
	messagebox.showinfo("Programa para Modelo de Kuz Ram", "Bajo derechos de autor")

def infoLicencia():
	messagebox.showwarning("Licencia","Licencia activada hasta el 2020.")

def salirApp():
	valor = messagebox.askokcancel("Salir","¿Estas seguro que quieres salir?")
	if valor==True:
		main.destroy()

def cerrarDocumento():
	valor=messagebox.askretrycancel("Reintentar","No es posible cerrar el documento")
	if valor==False:
		main.destroy()

def abreArchivo():
	archivo=filedialog.askopenfilename(title="Abrir",initialdir="/")#,filetypes=("Todos los ficheros"))
	print(archivo)

# CREACION DE INTERFACE

barraMenu=Menu(main)
main.config(menu=barraMenu)

archivoMenu=Menu(barraMenu,tearoff=0)
archivoMenu.add_command(label="Nuevo")
archivoMenu.add_command(label="Abrir",command=abreArchivo)
archivoMenu.add_separator()
archivoMenu.add_command(label="Guardar")
archivoMenu.add_command(label="Guardar como")
archivoMenu.add_separator()
archivoMenu.add_command(label="Cerrar",command=cerrarDocumento)
archivoMenu.add_command(label="Salir",command=salirApp)

edicionMenu=Menu(barraMenu,tearoff=0)
edicionMenu.add_command(label="Copiar")
edicionMenu.add_command(label="Cortar")
edicionMenu.add_command(label="Pegar")

herramientaMenu=Menu(barraMenu,tearoff=0)
herramientaMenu.add_command(label="Reemplazar")

ayudaMenu=Menu(barraMenu,tearoff=0)
ayudaMenu.add_command(label="Licencia",command=infoLicencia)
ayudaMenu.add_command(label="Acerca de...",command=infoAdicional)

barraMenu.add_cascade(label="Archivo", menu=archivoMenu)
barraMenu.add_cascade(label="Edicion", menu=edicionMenu)
barraMenu.add_cascade(label="Herramienta", menu=herramientaMenu)
barraMenu.add_cascade(label="Ayuda", menu=ayudaMenu)

main.title("Predicción del tamaño de roca fragmentada")
main.geometry("1100x580")
main.resizable(0,0)

#Frame Izquierda
frame=Frame()
frame.pack(side="left",fill="y",padx=10,pady=10)
frame.config(width=550,height=750)
frame.config(bd=2)
frame.config(relief="sunken")
frame.config(bg="lightgray")
frame.config(cursor="question_arrow")

#Frame Derecha
frameLista=Frame()
frameLista.pack(side="left",fill="y",padx=10,pady=10)
frameLista.config(width=150,height=750)
frameLista.config(bd=2)
frameLista.config(bg="lightgray")
frameLista.config(relief="sunken")
frameLista.config(cursor="question_arrow")

#Frame Derecha
framePlot=Frame()
framePlot.pack(side="left",fill="y",padx=10,pady=10)
framePlot.config(width=550)
framePlot.config(bd=2)
framePlot.config(bg="lightgray")
framePlot.config(relief="sunken")
framePlot.config(cursor="question_arrow")

def roca():

	#Agregar componentes al frame

	#Roca
	contenedorRoca=LabelFrame(frame,text="Roca", fg="red",font=("Arial",10,"bold"))
	contenedorRoca.grid(row=0,column=0,sticky="w",padx=10,pady=5)
	contenedorRoca.config(bd=3,relief="ridge",bg="lightgray")
	#label de la roca
	labelRoca=Label(contenedorRoca,text="Factor de Roca:",bg="lightgray")
	labelRoca.grid(row=0,column=0,padx=5,pady=5,sticky="e")

	#Caja de la roca
	txtFactorRoca=Entry(contenedorRoca,justify="center",fg="red",width="15",textvariable=fr)
	txtFactorRoca.grid(row=0,column=1,padx=5,pady=5)

def malla():
	#Contenedor de Malla
	contenedorMalla=LabelFrame(frame,text="Malla", fg="red",font=("Arial",10,"bold"))
	contenedorMalla.grid(row=1,column=0,sticky="w",padx=10,pady=5)
	contenedorMalla.config(bd=3,relief="ridge",bg="lightgray")

	#Label de Burden
	labelBurden=Label(contenedorMalla,text="Burden [m]:",bg="lightgray")
	labelBurden.grid(row=0,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Burden
	txtBurden=Entry(contenedorMalla,justify="center",fg="red",width="12",textvariable=b)
	txtBurden.grid(row=0,column=1,padx=5,pady=5)

	#Label de Espaciamiento
	labelEspaciamiento=Label(contenedorMalla,text="Espaciamiento [m]:",bg="lightgray")
	labelEspaciamiento.grid(row=1,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Espaciamiento
	txtEspaciamiento=Entry(contenedorMalla,justify="center",fg="red",width="12",textvariable=s)
	txtEspaciamiento.grid(row=1,column=1,padx=5,pady=5)

	#Label de Altura
	labelAltura=Label(contenedorMalla,text="Altura [m]:",bg="lightgray")
	labelAltura.grid(row=2,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Altura
	txtAltura=Entry(contenedorMalla,justify="center",fg="red",width="12",textvariable=h)
	txtAltura.grid(row=2,column=1,padx=5,pady=5)

	#Label de Tipo
	labelTipo=Label(contenedorMalla,text="Tipo:",bg="lightgray")
	labelTipo.grid(row=3,column=0,padx=5,pady=5,sticky="e")

	#Caja de Tipo
	Tipo=ttk.Combobox(contenedorMalla,width="9",textvariable=pater)
	Tipo.grid(row=3,column=1)
	Tipo['values']=("Triangular","Cuadrada")

	#Label de Desviacion
	labelDesviacion=Label(contenedorMalla,text="Desviación [m]:",bg="lightgray")
	labelDesviacion.grid(row=4,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Desviacion
	txtDesviacion=Entry(contenedorMalla,justify="center",fg="red",width="12",textvariable=desv)
	txtDesviacion.grid(row=4,column=1,padx=5,pady=5)

def taladro():
	#Contenedor de Taladro
	contenedorTaladro=LabelFrame(frame,text="Taladro", fg="red",font=("Arial",10,"bold"))
	contenedorTaladro.grid(row=2,column=0,sticky="w",padx=10,pady=5)
	contenedorTaladro.config(bd=3,relief="ridge",bg="lightgray")

	#Label de Taco
	labelTaco=Label(contenedorTaladro,text="Taco [m]:",bg="lightgray")
	labelTaco.grid(row=0,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Taco
	txtTaco=Entry(contenedorTaladro,justify="center",fg="red",width="8",textvariable=taco)
	txtTaco.grid(row=0,column=1,padx=5,pady=5)

	#Label de Diámetro
	labelDiametro=Label(contenedorTaladro,text="Diámetro [mm]:",bg="lightgray")
	labelDiametro.grid(row=1,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Diámetro
	txtDiametro=Entry(contenedorTaladro,justify="center",fg="red",width="8",textvariable=d)
	txtDiametro.grid(row=1,column=1,padx=5,pady=5)

	#Label de Sobreperforación
	labelSobreperforacion=Label(contenedorTaladro,text="Sobreperforación [mm]:",bg="lightgray")
	labelSobreperforacion.grid(row=2,column=0,padx=5,pady=5,sticky="e")

	#Caja de Sobreperforación
	txtSobreperforacion=Entry(contenedorTaladro,justify="center",fg="red",width="8",textvariable=sp)
	txtSobreperforacion.grid(row=2,column=1,padx=5,pady=5)

def Explosivo():
	#Contenedor de Explosivo
	contenedorExplosivo=LabelFrame(frame,text="Explosivo", fg="red",font=("Arial",10,"bold"))
	contenedorExplosivo.grid(row=3,column=0,sticky="w",padx=10,pady=5)
	contenedorExplosivo.config(bd=3,relief="ridge",bg="lightgray")

	#Label de Densidad
	labelDensidad=Label(contenedorExplosivo,text="Densidad [g/CC]:",bg="lightgray")
	labelDensidad.grid(row=0,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Densidad
	txtDensidad=Entry(contenedorExplosivo,justify="center",fg="red",width="14",textvariable=de)
	txtDensidad.grid(row=0,column=1,padx=5,pady=5)

	#Label de Energía
	labelEnergia=Label(contenedorExplosivo,text="Energía [Kj/kg]:",bg="lightgray")
	labelEnergia.grid(row=1,column=0,padx=5,pady=5,sticky="e")

	#Caja de la Energía
	txtEnergia=Entry(contenedorExplosivo,justify="center",fg="red",width="14",textvariable=e)
	txtEnergia.grid(row=1,column=1,padx=5,pady=5)

	#Label de RWS
	labelRWS=Label(contenedorExplosivo,text="RWS [%]:",bg="lightgray")
	labelRWS.grid(row=2,column=0,padx=5,pady=5,sticky="e")

	#Caja de RWS
	txtRWS=Entry(contenedorExplosivo,justify="center",fg="red",width="14",textvariable=rws)
	txtRWS.grid(row=2,column=1,padx=5,pady=5)

# DECLARACION DE VARIBALES
fr= DoubleVar() # Factor de Roca
b= DoubleVar() # Burden [m]
s= DoubleVar() # Espaciamiento [m]
h= DoubleVar() # Altura [m]
pater= StringVar() # Patron de Perforación
desv= DoubleVar() # Desviación de Perforación [m]
taco= DoubleVar() # Taco [m]
d = DoubleVar() # Diametro [mm]
sp = DoubleVar() # Sobreperforacion [m]
de= DoubleVar() # Densidad de explosivo [g/cc]
e= DoubleVar() # energia del explosivo [kcal/kg]
rws = DoubleVar() # potencia relativa del explosivo [%]

# Variables de Entrada
paso=5
p=np.arange(5,95+paso,paso)/100 # Lista , (Valor inicial , final , paso)
listaX=[];listaY=[]

# Variables de Resultados
Xprom=0;n=0;x80=0;result=[];listaCurva=[];

fig,ax= plt.subplots()
#grafica= fig.add_subplot(221)

ax.set_xlabel('Tamaño de Fragmento [cm]',color="r")
ax.set_ylabel('Porcentaje Pasante [%]',color="r")
ax.grid(True,color="lightgray")
plt.title("Curva Granulométrica")

canvas = FigureCanvasTkAgg(fig,framePlot)  # CREAR AREA DE DIBUJO DE TKINTER.
canvas.get_tk_widget().pack(side="top", fill="both", expand=1)
canvas.draw()

toolbar = NavigationToolbar2Tk(canvas, framePlot)# barra de iconos
toolbar.update()
canvas.get_tk_widget().pack(side="top",fill="both",expand=True)

def calcular():
	global listaCurva,listaX,listaY,p,result,ax,Xprom,n,canvas

	valor = messagebox.askyesno(message="¿Desea Agregar Gráfica?", title="Agregar")

	if valor==True:

		# OBTENER VALORES --------------------------------------------------------------
		_fr = fr.get()
		_b = b.get()
		_s = s.get()
		_h = h.get()
		_pater= pater.get()

		# Asignar valor al pater si es que es triangular o cuadrada (1 / 1.1)
		if _pater == "Triangular":
			_pater= 1.1
		else:
			_pater=1

		_t = taco.get()
		_d = d.get()/1000
		_sp = sp.get()
		_de = de.get()*1000
		_e = e.get()
		_rws = rws.get()
		Desv = desv.get()

		#------------------------------------------------------------------------------------------------

		# Longitud de carga
		lc = _h+_sp-_t
		print("Longitud de carga: ", lc)
		# Kg de explosivo
		w = _de * lc * math.pi*_d**2/4
		print("cantidad de êxplosivo [kg]: ", w)

		# CALCULAR TAMAÑO PROMEDIO ----------------------------------------------------------------------

		tamañomedio(_b,_s,_h,_fr,w,_rws)

		# CALCULAR INDICE DE UNIFORMIDAD ----------------------------------------------------------------
		indice(_b,_d*1000,_s,Desv,lc,_h,_pater)

		# CALCULAR CURVA --------------------------------------------------------------------------------
		curva(Xprom,p,n,result,listaCurva)

		xmin= round(min(listaCurva))
		xmax= round(max(listaCurva))
		pasox=5
		pasoy=10
		listaX= np.arange(xmin,xmax+pasox,pasox)
		listaY= np.arange(0,100+pasoy,pasoy)

		ax.set_xticks(listaX)
		ax.set_yticks(listaY)

		#Actualizar Gráfica
		canvas.draw()

def tamañomedio(b,s,h,a,w,rws):
	global Xprom
	V= b*s*h
	print("V",V)
	try:
		Xprom = a*((V/w)**0.8)*(w**(1/6))*(115/rws)**(19/30) # cm
		print("xprom: ", Xprom)
		print("RWS", rws)
	except Exception as e:
		print(e)

def indice(b,d,s,Desv,lc,h,pater):
	global n
	try:
		n = (2.2-14*(b/d))*(((1+s/b)/2)**0.5)*(1-Desv/b)*(lc/h)*pater
		print("n",n)
	except Exception as m:
		print(m)

def curva(Xprom,p,n,result,listaCurva):
	global ax
	valores = Xprom*(-(np.log(1-p)/0.693))**(1/n) # --> X80
	# agrego nuevos valores
	result.append({"res":valores,"n":n})
	agregarCurva()
	#x80= Xprom*(-(np.log(1-0.8)/0.693))**(1/n)

def agregarCurva():
	global result,listavalores,ax,canvas
	# LIMPIO grafica
	ax.clear()
	print(len(result))
	listavalores.delete(0,len(result))

	## PROPIEDADES DE LA GRAFICA
	ax.set_xlabel('Tamaño de Fragmento [cm]',color="r")
	ax.set_ylabel('Porcentaje Pasante [%]',color="r")
	ax.grid(True,color="lightgray")
	plt.title("Curva Granulométrica")

	i=0

	for res in result:
		#x80 = Xprom*(-(np.log(1-0.8)/0.693))**(1/n)
		titulo = "n :"+str(round(res['n'],3))#+" X80:"+str(round(x80,2))
		ax.plot(res['res'],p*100,label=titulo)
		listavalores.insert(i,titulo)
		for x in res['res']:
			listaCurva.append(x)
		i=i+1

	ax.legend(loc="lower right",shadow=True,fontsize=9)
	canvas.draw()

def limpiar():
	global ax,canvas
	valor = messagebox.askyesno(message="¿Desea Limpiar Gráfica?", title="Limpiar")
	if valor==True:
		ax.clear()
		## PROPIEDADES DE LA GRAFICA
		ax.set_xlabel('Tamaño de Fragmento [cm]',color="r")
		ax.set_ylabel('Porcentaje Pasante [%]',color="r")
		ax.grid(True,color="lightgray")
		plt.title("Curva Granulométrica")
		canvas.draw()

def eliminar():
	global listavalores
	if len(listavalores.curselection())!=0:
		val = listavalores.curselection()[0]
		result.pop(val)
		agregarCurva()

def ejemplo1():
	fr.set(8.421)
	b.set(10)
	s.set(10)
	h.set(15)
	pater.set("cuadrada")
	desv.set(0.58)
	taco.set(7)
	d.set(250.8)
	sp.set(1.5)
	de.set(1.20)
	rws.set(125)

botonEliminar = Button(frameLista,text="-- Eliminar --",command=eliminar)
botonEliminar.grid(row=0,column=0,sticky="w",padx=10,pady=5)
listavalores = Listbox(frameLista,height=25)
listavalores.grid(row=1,column=0,sticky="w",padx=10,pady=5)
######....................

botonCalcular = Button(main,text="-- CALCULAR --", command=calcular).place(x=25,y=535)

botonLimpiar = Button(main,text="-- LIMPIAR --", command=limpiar).place(x=150,y=535)

## LLAMAR FUNCIONES
Explosivo()
taladro()
malla()
roca()
ejemplo1()

# CREAR FIGURA DEL MATPLOTLIB

#fig= Figure(figsize=(5.5, 5), dpi=100)

main.mainloop()