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)


f=open("prob11.txt","r")
s=f.read()
l=s.split("+")
d=[]
for x in l:
    x=x.strip('"\n')
    poz=x.find(":")
    cuv=x[:poz]
    nr=0
    lung=len(cuv)
    for i in range(poz,len(x)-lung):
        if x[i:i+lung]==cuv and x[i-1].isalpha()==False and x[i+lung].isalpha()==False:
            nr+=1

    for a in x:
        if "~"==a:
            nr+=1

    d.append((cuv,nr))

print(d)

AN 1 SEM 1/Programarea algoritmilor/lab3/11.py


from collections import defaultdict

class Graph:
    def __init__(self, v_count):
        self.V = v_count
        self.graph = defaultdict(list)
        self.time = 0

    def add_edge(self, u, v):
        self.graph[u].append(v)
        self.graph[v].append(u)

    def ap_util(self, u, visited, disc, low, parent):
        # Perform normal dfs
        visited[u] = True
        disc[u] = self.time
        low[u] = self.time
        self.time += 1
        children = 0
        for v in self.graph[u]:
            if visited[v] == False:
                parent[v] = u
                children += 1
                if self.ap_util(v, visited, disc, low, parent):
                    return True
                # update low based on lowest in subtree
                low[u] = min(low[v], low[u])
                # if its a root node with 1+ childrens, its ap
                if parent[u] == -1 and children > 1:
                    return True
                # if its not a root node, with no backedge, its ap
                if parent[u] != -1 and low[v] >= disc[u]:
                    return True
            elif v != parent[u]:
                low[u] = min(low[u], disc[v])
        return False

    def is_bcg(self):
        visited = [False] * self.V
        disc = [float('inf')] * self.V
        low = [float('inf')] * self.V
        parent = [-1] * self.V

        # check for two conditions, if true its not biconnected
        # articulation point
        # connectivity
        if self.ap_util(0, visited, disc, low, parent):
            return False

        for i in range(self.V):
            if visited[i] == False:
                return False
        return True

if __name__ == "__main__":
    g1 = Graph(5)
    g1.add_edge(1, 0)
    g1.add_edge(0, 2)
    g1.add_edge(2, 1)
    g1.add_edge(0, 3)
    g1.add_edge(3, 4)
    g1.add_edge(2, 4)
    print(g1.is_bcg())
    g2 = Graph(3)
    g2.add_edge(0, 1)
    g2.add_edge(1, 2)
    print(g2.is_bcg())


from pbticket import PBLottoTicket
from matcher import TemplateMatch
from kenfetch import KensLottoPool

pool = KensLottoPool("https://kenslottopool.com/ticketpicturesnov7/")

for p in pool.img_arr:

  image_search = TemplateMatch(p, './images/template_pb.png')

  image_search.find_powerball_logos()

  image_search.adjust_ticket_rectangles()

  tickets = []

  for v in image_search.logo_locations:
    i = v.crop_image(image_search.tickets.original_image)
    t = PBLottoTicket(i)
    t.extract_numbers()

    tickets.append(t)


## ni.duman
import numpy as np
import matplotlib.pyplot as plt
import random
import math

# fonkisyonu tanımlama
def f(x):
    x1 = x[0]
    x2 = x[1]
    obj = (1 + (x1 + x2 + 1)**2 * (19 - 14*x1 + 3*(x1**2) - 14*x2 + 6*x1*x2 + 3*(x2**2))) * (30 + (2*x1 - 3*x2)**2 * (18 - 32*x1 + 12*(x1**2) + 48*x2 - 36*x1*x2 + 27*(x2**2)))
    return obj

# aralık
x_start = [0.8, -0.5]

# Simulated Kodu

# Düngü sayısı
n = 30
# Döngü başına deneme sayısı
m = 75

na = 0.0
# en kötü çözüm başlangıç
p1 = 0.7
# En kötü çözüm bitiş
p50 = 0.001
# başlangıç sıcaklığı
t1 = -1.0/math.log(p1)
# final sıcaklığı
t50 = -1.0/math.log(p50)

frac = (t50/t1)**(1.0/(n-1.0))

x = np.zeros((n+1,2))
x[0] = x_start
xi = np.zeros(2)
xi = x_start
na = na + 1.0
# Anlık sonuçlar
xc = np.zeros(2)
xc = x[0]
fc = f(xi)
fs = np.zeros(n+1)
fs[0] = fc
# Anlık sıcaklık
t = t1
# Ortalama Sıcaklık
DeltaE_avg = 0.0
for i in range(n):
    print('Döngü: ' + str(i) + ' nin sıcaklığı: ' + str(t))
    for j in range(m):
        # yeni noktalar
        xi[0] = xc[0] + random.random() - 0.5
        xi[1] = xc[1] + random.random() - 0.5
        # alt üst sıçrama
        xi[0] = max(min(xi[0],2.0),-2.0)
        xi[1] = max(min(xi[1],2.0),-2.0)
        DeltaE = abs(f(xi)-fc)
        if (f(xi)>fc):
            # ilk iterasyonda daha kötü bir ortalama bulduysa          #   on the first iteration
            if (i==0 and j==0): DeltaE_avg = DeltaE

            # kabul  fonksiyonu

            p = math.exp(-DeltaE/(DeltaE_avg * t))
            # kötü çözümü edip etmemeyi kararlaştırma
            if (random.random()<p):
                # kabu etme
                accept = True
            else:
                # kabul etmeme
                accept = False
        else:
            # otomatik kabul etme
            accept = True
        if (accept==True):
            # anlık durumu güncelleme
            xc[0] = xi[0]
            xc[1] = xi[1]
            fc = f(xc)
            # kabul edilen çözüm sayısını ve delta yı arttırma arttırma
            na = na + 1.0
            DeltaE_avg = (DeltaE_avg * (na-1.0) +  DeltaE) / na
    # En iyi x değerlerini saklama
    x[i+1][0] = xc[0]
    x[i+1][1] = xc[1]
    fs[i+1] = fc
    # Sıradaki döngü için sıcaklığı azalta
    t = frac * t

# ekrana yazdırma
print('En iyi çözüm: ' + str(xc))
print('En iyi hedef: ' + str(fc))

"""plt.plot(x[:,0],x[:,1],'y-o')
plt.savefig('contour.png')"""

fig = plt.figure()
ax1 = fig.add_subplot(211)
ax1.plot(fs,'r.-')
ax1.legend(['Objective'])
ax2 = fig.add_subplot(212)
ax2.plot(x[:,0],'b.-')
ax2.plot(x[:,1],'g--')
ax2.legend(['x1','x2'])

# PNG olarak saklama
plt.savefig('iterations.png')

plt.show()


"""
Module: Leap Year
Author: Sinku Kumar
Date: 6 June 2023

To determine whether a year is a leap year, follow these steps:
    1. If the year is evenly divisible by 4, go to step 2. Otherwise, go to step 5.
    2. If the year is evenly divisible by 100, go to step 3. Otherwise, go to step 4.
    3. If the year is evenly divisible by 400, go to step 4. Otherwise, go to step 5.
    4. The year is a leap year (it has 366 days).
    5. The year is not a leap year (it has 365 days).
"""

def is_leap_year(year):
    """
    Return True if year is leap year, else False

    :param year:
    :return: True when leap year, else False
    """
    # step 1
    if not year % 4:
        # step 2
        if not year % 100:
            # step 3
            if not year % 400:
                return True
        # step 4
        else:
            return True
    # step 5
    else:
        return False

#print(is_leap_year(2008))


#!/usr/bin/env python

"""Tests for `btnetutils` package."""

import pytest

from click.testing import CliRunner

from btnetutils import cli

def test_command_line_interface():
    """Test the CLI."""
    runner = CliRunner()
    result = runner.invoke(cli.btnetutils)
    assert 'Simple CLI for dealing with net configs' in result.output
    assert result.exit_code == 0
    help_result = runner.invoke(cli.btnetutils, ['--help'])
    assert help_result.exit_code == 0
    assert '--help  Show this message and exit.' in help_result.output


import cv2
import os
import shutil
import torch
from Save_result import Tool

filepath = r'C:\Users\GÜNERARDAIŞIK\Desktop\labeler\images'
destination = r'C:\Users\GÜNERARDAIŞIK\Desktop\labeler\dest'

model = torch.hub.load(r'C:\yolov5', 'custom', path=r'C:\Users\GÜNERARDAIŞIK\Desktop\labeler\model\KAAN.pt', source='local')

for filename in os.listdir(filepath):
    if "." not in filename:
        continue
    ending = filename.split(".")[-1]
    if ending not in ["jpg", "gif", "png","jfif","JPG", 'txt']:
        continue
    img = cv2.imread('images/'+filename)
    filename=filename.split('.jpg')[0]

    img1, img2 = Tool.divide(img)
    cv2.imwrite(destination+'\\'+ filename +'1.jpg', img1)
    cv2.imwrite(destination+'\\'+ filename +'2.jpg', img2)
    results1 = model(img1)
    results2 = model(img2)
    results1.display(render=True)
    results2.display(render=True)
    # Save_result.get_values(results)
    lines = Tool.get_values(results=results1)
    lines2 = Tool.get_values(results=results2)

    Tool.save_txt(lines,destination+'\\'+filename+'1.txt')
    Tool.save_txt(lines2,destination+'\\'+filename+'2.txt')

    cv2.imshow('img1', results1.imgs[0])
    cv2.imshow('img2', results2.imgs[0])

    cv2.waitKey(0)


import bge
import math
class Buttons():
	"""docstring for Buttons"""
	def __init__(self):
		self.cont = bge.logic.getCurrentController()
		self.scene = bge.logic.getCurrentScene()
		self.camera = self.scene.objects['Camera']

	def buttonHover(self):
		button = self.cont.owner
		absolute = math.fabs(self.camera.position[0] - button.position[0])
		if absolute <= 1:
			button.position[2] = .3 -(absolute*0.3)
		else:
			button.position[2] = .06

	def button01(self):
		button = self.cont.owner
		mouse = self.cont.sensors['mouseClick']
		scenePointer = button['scenePointer']
		if mouse.positive and math.fabs(self.camera.position[0] - button.position[0]) <= .8:
			self.scene.replace(scenePointer)

def hover():
	hov = Buttons()
	hov.buttonHover()

def butt():
	but = Buttons()
	but.button01()


from twilio.rest import TwilioRestClient
import send_text_config

config = send_text_config

client = TwilioRestClient(config.account_sid, config.auth_token)

message = client.messages.create(
    to= config.to_number,
    from_= config.from_number,
    body="Hello from Python!")

print(message.sid)


""" tools.py - cpfigure tools that do not depend on WX
"""

import io

import centrosome.cpmorphology
import imageio
import matplotlib
import matplotlib.figure
import matplotlib.transforms
import numpy

def figure_to_image(figure, *args, **kwargs):
    """Convert a figure to a numpy array"""
    #
    # Save the figure as a .PNG and then load it using imageio.imread
    #
    fd = io.BytesIO()
    kwargs = kwargs.copy()
    kwargs["format"] = "png"
    figure.savefig(fd, *args, **kwargs)
    image = imageio.imread(fd.getvalue())
    return image[:, :, :3]

def only_display_image(figure, shape):
    """Set up a figure so that the image occupies the entire figure

    figure - a matplotlib figure
    shape - i/j size of the image being displayed
    """
    assert isinstance(figure, matplotlib.figure.Figure)
    figure.set_frameon(False)
    ax = figure.axes[0]
    ax.set_axis_off()
    figure.subplots_adjust(0, 0, 1, 1, 0, 0)
    dpi = figure.dpi
    width = float(shape[1]) / dpi
    height = float(shape[0]) / dpi
    figure.set_figheight(height)
    figure.set_figwidth(width)
    bbox = matplotlib.transforms.Bbox(numpy.array([[0.0, 0.0], [width, height]]))
    transform = matplotlib.transforms.Affine2D(
        numpy.array([[dpi, 0, 0], [0, dpi, 0], [0, 0, 1]])
    )
    figure.bbox = matplotlib.transforms.TransformedBbox(bbox, transform)

def renumber_labels_for_display(labels):
    """Scramble the label numbers randomly to make the display more discernable

    The colors of adjacent indices in a color map are less discernable than
    those of far-apart indices. Nearby labels tend to be adjacent or close,
    so a random numbering has more color-distance between labels than a
    straightforward one
    """
    return centrosome.cpmorphology.distance_color_labels(labels)


from numpy import array, cross, sqrt, vstack
from numpy.linalg import norm
from typing import List, Tuple
from google.protobuf.wrappers_pb2 import StringValue
from orbdetpy.rpc.conversion_pb2_grpc import ConversionStub
from orbdetpy.rpc.messages_pb2 import AnglesInput, DoubleArray, IntegerArray, TransformFrameInput
from orbdetpy.rpc.server import RemoteServer

def transform_frame(src_frame: int, time: float, pva: List[float], dest_frame: int)->List[float]:
    """Transform a state vector from one frame to another.

    Parameters
    ----------
    src_frame : Source reference frame; a constant from Frame.
    time : Offset in TT from J2000 epoch [s]. Give a list for bulk transforms.
    pva : State vector to transform, can be pos or pos+vel or pos+vel+acc. Provide a
          list of lists for bulk frame transforms.
    dest_frame : Destination reference frame; a constant from Frame.

    Returns
    -------
    State vector transformed to the destination frame.
    """

    if (isinstance(time, float) or isinstance(time, str)):
        single, time, pva = True, [time], [pva]
    else:
        single = False

    if (isinstance(time[0], float)):
        resp = _conversion_stub.transformFrame(TransformFrameInput(
            src_frame=src_frame, time=time, pva=[DoubleArray(array=x) for x in pva], dest_frame=dest_frame))
    else:
        resp = _conversion_stub.transformFrame(TransformFrameInput(
            src_frame=src_frame, UTC_time=time, pva=[DoubleArray(array=x) for x in pva], dest_frame=dest_frame))
    return(resp.array[0].array if (single) else resp.array)

def get_lvlh_rotation(state: List[float])->array:
    """Construct the inertial->LVLH rotation matrix.

    Parameters
    ----------
    state : Inertial state vector.

    Returns
    -------
    Inertial->LVLH frame rotation matrix.
    """

    r = array(state[:3])
    r /= norm(r)
    v = array(state[3:6])
    v /= norm(v)
    h = cross(r, v)
    h /= norm(h)
    return(vstack((r, cross(h, r), h)))

def azel_to_radec(time: float, az: float, el: float, lat: float, lon: float, alt: float, frame: int)->Tuple[float, float]:
    """Convert Azimuth/Elevation to Right Ascension/Declination.

    Parameters
    ----------
    time : Offset in TT from J2000 epoch [s].
    az : Azimuth [rad].
    el : Elevation [rad].
    lat : Observer WGS-84 latitude [rad].
    lon : Observer WGS-84 longitude [rad].
    alt : Observer height above WGS-84 reference ellipsoid [m].
    frame : Destination reference frame; Frame.GCRF or Frame.EME2000.

    Returns
    -------
    Right Ascension and Declination.
    """

    return(_conversion_stub.convertAzElToRaDec(AnglesInput(time=[time], angle1=[az], angle2=[el],
                                                           latitude=lat, longitude=lon, altitude=alt, frame=frame)).array)

def radec_to_azel(frame: int, time: float, ra: float, dec: float, lat: float, lon: float, alt: float)->Tuple[float, float]:
    """Convert Right Ascension/Declination to Azimuth/Elevation.

    Parameters
    ----------
    frame : Source reference frame; Frame.GCRF or Frame.EME2000.
    time : Offset in TT from J2000 epoch [s].
    ra : Right Ascension [rad].
    dec : Declination [rad].
    lat : Observer WGS-84 latitude [rad].
    lon : Observer WGS-84 longitude [rad].
    alt : Observer height above WGS-84 reference ellipsoid [m].

    Returns
    -------
    Azimuth and Elevation.
    """

    return(_conversion_stub.convertRaDecToAzEl(AnglesInput(time=[time], angle1=[ra], angle2=[dec],
                                                           latitude=lat, longitude=lon, altitude=alt, frame=frame)).array)

def lla_to_pos(time: float, lla: List[float])->List[float]:
    """Convert WGS-84 lat/lon/alt to Cartesian position.

    Parameters
    ----------
    time : Offset in TT from J2000 epoch [s]. Give a list for bulk conversions.
    lla : WGS-84 latitude, longitude, altitude. Provide a list of lists for bulk conversions.

    Returns
    -------
    ITRF geocentric Cartesian position [m].
    """

    if (isinstance(time, float) or isinstance(time, str)):
        single, time, lla = True, [time], [lla]
    else:
        single = False

    if (isinstance(time[0], float)):
        resp = _conversion_stub.convertLLAToPos(TransformFrameInput(time=time, pva=[DoubleArray(array=x) for x in lla]))
    else:
        resp = _conversion_stub.convertLLAToPos(TransformFrameInput(UTC_time=time, pva=[DoubleArray(array=x) for x in lla]))
    return(resp.array[0].array if (single) else resp.array)

def pos_to_lla(frame: int, time: float, pos: List[float])->List[float]:
    """Convert a Cartesian position to WGS-84 lat/lon/alt.

    Parameters
    ----------
    frame : Position reference frame; a constant from Frame.
    time : Offset in TT from J2000 epoch [s]. Give a list for bulk conversions.
    pos : Position vector [m]. Provide a list of lists for bulk conversions.

    Returns
    -------
    WGS-84 latitude [rad], longitude [rad], altitude [m].
    """

    if (isinstance(time, float) or isinstance(time, str)):
        single, time, pos = True, [time], [pos]
    else:
        single = False

    if (isinstance(time[0], float)):
        resp = _conversion_stub.convertPosToLLA(TransformFrameInput(src_frame=frame, time=time, pva=[DoubleArray(array=x) for x in pos]))
    else:
        resp = _conversion_stub.convertPosToLLA(TransformFrameInput(src_frame=frame, UTC_time=time, pva=[DoubleArray(array=x) for x in pos]))
    return(resp.array[0].array if (single) else resp.array)

def elem_to_pv(frame: int, time: float, sma: float, ecc: float, inc: float,
               raan: float, argp: float, anom: float, anom_type: int)->List[float]:
    """Convert osculating orbital elements to Cartesian state vector.

    Parameters
    ----------
    frame : Inertial reference frame; a constant from Frame.
    time : Offset in TT from J2000 epoch [s]. Give a list for bulk conversions.
    sma : Semi-major axis [m]. Give a list for bulk conversions.
    ecc : Eccentricity. Give a list for bulk conversions.
    inc : Inclination [rad]. Give a list for bulk conversions.
    raan : RA of ascending node [rad]. Give a list for bulk conversions.
    argp : Argument of perigee [rad]. Give a list for bulk conversions.
    anom : Anomaly angle [rad]. Give a list for bulk conversions.
    anom_type : Anomaly angle type; a constant from PositionAngle. Give a list for bulk conversions.

    Returns
    -------
    Cartesian state vector.
    """

    if (isinstance(time, float) or isinstance(time, str)):
        single, time, sma, ecc, inc, raan, argp, anom, anom_type = True, [time], [sma], [ecc], [inc], [raan], [argp], [anom], [anom_type]
    else:
        single = False

    if (isinstance(time[0], float)):
        resp = _conversion_stub.convertElemToPv(TransformFrameInput(src_frame=frame, time=time, pva=[
            DoubleArray(array=[a,e,i,W,w,n,t]) for a,e,i,W,w,n,t in zip(sma, ecc, inc, raan, argp, anom, anom_type)]))
    else:
        resp = _conversion_stub.convertElemToPv(TransformFrameInput(src_frame=frame, UTC_time=time, pva=[
            DoubleArray(array=[a,e,i,W,w,n,t]) for a,e,i,W,w,n,t in zip(sma, ecc, inc, raan, argp, anom, anom_type)]))
    return(resp.array[0].array if (single) else resp.array)

def pv_to_elem(frame: int, time: float, pv: List[float])->List[float]:
    """Convert Cartesian state vector to osculating orbital elements.

    Parameters
    ----------
    frame : Inertial reference frame; a constant from Frame.
    time : Offset in TT from J2000 epoch [s]. Give a list for bulk conversions.
    pv : Inertial Cartesian state vector. Provide a list of lists for bulk conversions.

    Returns
    -------
    SMA, eccentricity, inclination, RAAN, perigee argument, mean anomaly, true anomaly, eccentric anomaly
    """

    if (isinstance(time, float) or isinstance(time, str)):
        single, time, pv = True, [time], [pv]
    else:
        single = False

    if (isinstance(time[0], float)):
        resp = _conversion_stub.convertPvToElem(TransformFrameInput(src_frame=frame, time=time, pva=[DoubleArray(array=x) for x in pv]))
    else:
        resp = _conversion_stub.convertPvToElem(TransformFrameInput(src_frame=frame, UTC_time=time, pva=[DoubleArray(array=x) for x in pv]))
    return(resp.array[0].array if (single) else resp.array)

def get_UTC_string(j2000_offset: float, precision: int=3)->str:
    """Get ISO-8601 formatted UTC string corresponding to TT offset.

    Parameters
    ----------
    j2000_offset : Offset in TT from J2000 epoch [s] or list of offsets.
    precision : Desired precision. Defaults to 3, i.e. milliseconds.

    Returns
    -------
    ISO-8601 formatted UTC string or list of strings.
    """

    if (isinstance(j2000_offset, float)):
        return(_conversion_stub.getUTCString(DoubleArray(array=[float(precision), j2000_offset])).value)
    return(_conversion_stub.getUTCString(DoubleArray(array=[float(precision), *j2000_offset])).value.split(" "))

def get_J2000_epoch_offset(utc: str)->float:
    """Get TT offset corresponding to ISO-8601 formatted UTC string.

    Parameters
    ----------
    utc : ISO-8601 formatted UTC string or list of strings.

    Returns
    -------
    Offset in TT from J2000 epoch [s] or list of offsets.
    """

    resp = _conversion_stub.getJ2000EpochOffset(StringValue(value=utc if isinstance(utc, str) else " ".join(utc)))
    return(resp.array[0] if (len(resp.array) == 1) else resp.array)

def get_epoch_difference(from_epoch: int, to_epoch: int)->str:
    """Get the constant time difference between two epochs.

    Parameters
    ----------
    from_epoch : From epoch; a value from the Epoch enumeration.
    to_epoch : To epoch; a value from the Epoch enumeration.

    Returns
    -------
    to_epoch - from_epoch in seconds.
    """

    return(_conversion_stub.getEpochDifference(IntegerArray(array=[from_epoch, to_epoch])).value)

def ltr_to_matrix(lower_triangle: List[float])->List[List[float]]:
    """Construct a symmetric matrix from its lower triangle.

    Parameters
    ----------
    lower_triangle : Lower triangle of a symmetric matrix in row-major order.

    Returns
    -------
    Symmetric matrix as a list of lists or None on error.
    """

    m = (sqrt(8*len(lower_triangle) + 1) - 1)/2
    n = int(m)
    if (m == n):
        k, matrix = 0, [[0]*n for _ in range(n)]
        for i in range(n):
            for j in range(i + 1):
                matrix[i][j], matrix[j][i] = lower_triangle[k], lower_triangle[k]
                k += 1
        return(matrix)
    return(None)

if (__name__ != "__main__"):
    _conversion_stub = ConversionStub(RemoteServer.channel())


from django.contrib.auth.decorators import login_required
from django.http import Http404
from django.shortcuts import render, get_object_or_404

from .models import Plan, Section, Activity
from cart.models import Order, CartItem

def list_plans(request):
    queryset = Plan.objects.all()
    context = {
        'queryset': queryset
    }
    return render(request, "plan-list.html", context)

@login_required
def plan_details(request, slug):
    plan = get_object_or_404(Plan, slug=slug)
    order_qs = Order.objects.filter(user=request.user)
    plan_in_cart = False
    if order_qs.exists():
        order = order_qs[0]
        order_item_qs = CartItem.objects.filter(plan=plan)
        if order_item_qs.exists():
            order_item = order_item_qs[0]
            if order_item in order.items.all():
                plan_in_cart = True
    context = {
        'plan': plan,
        'in_cart_item': plan_in_cart
    }
    return render(request, "plan-detail.html", context)

@login_required
def section_details(request, plan_slug, section_number):
    section_qs = Section.objects \
        .filter(plan__slug=plan_slug) \
        .filter(section_number=section_number)
    if section_qs.exists():
        context = {
            'section': section_qs[0],
        }
        return render(request, "section_detail.html", context)
    return Http404

@login_required
def activity_details(request, plan_slug, section_number, activity_number):
    activity_qs = Activity.objects \
        .filter(section__plan__slug=plan_slug) \
        .filter(section__section_number=section_number) \
        .filter(activity_number=activity_number)
    if activity_qs.exists():
        context = {
            'activity': activity_qs[0],
        }
        return render(request, "activity_detail.html", context)
    return Http404


import numpy as np
from numpy import pi
from gpkitmodels.GP.aircraft.mission.breguet_endurance import BreguetEndurance
from gpkitmodels.GP.aircraft.engine.df70 import DF70
from gpkitmodels.GP.aircraft.engine.gas_engine import Engine
from gpkitmodels.SP.aircraft.wing.wing import Wing
from gpkitmodels.GP.aircraft.fuselage.cylindrical_fuselage import Fuselage
from gpkitmodels.GP.aircraft.tail.empennage import Empennage
from gpkitmodels.GP.aircraft.tail.tail_boom import TailBoomState
from gpkitmodels.SP.aircraft.tail.tail_boom_flex import TailBoomFlexibility
from gpkitmodels.tools.summing_constraintset import summing_vars
from gpkit import Model, Variable, Vectorize, units
from gpkit.tools.autosweep import autosweep_1d
import matplotlib.pyplot as plt
from sens_chart import get_highestsens, plot_chart

# pylint: disable=invalid-name

class Aircraft(Model):
    "the JHO vehicle"
    def setup(self, Wfueltot, df70=True):

        self.fuselage = Fuselage(Wfueltot)
        self.wing = Wing(N=12)
        if df70:
            self.engine = DF70()
        else:
            self.engine = Engine()
        self.emp = Empennage()
        self.pylon = Pylon()

        components = [self.fuselage, self.wing, self.engine, self.emp,
                      self.pylon]
        self.smeared_loads = [self.fuselage, self.engine, self.pylon]
        # components = [self.fuselage, self.wing, self.engine, self.emp]
        # self.smeared_loads = [self.fuselage, self.engine]

        Wzfw = Variable("W_{zfw}", "lbf", "zero fuel weight")
        Wpay = Variable("W_{pay}", 10, "lbf", "payload weight")
        Ppay = Variable("P_{pay}", 10, "W", "payload power")
        Wavn = Variable("W_{avn}", 5.35, "lbf", "avionics weight")
        lantenna = Variable("l_{antenna}", 13.4, "in", "antenna length")
        wantenna = Variable("w_{antenna}", 10.2, "in", "antenna width")
        # propr = Variable("r", 11, "in", "propellor radius")
        Volpay = Variable("\\mathcal{V}_{pay}", 1.0, "ft**3", "payload volume")
        Volavn = Variable("\\mathcal{V}_{avn}", 0.125, "ft**3",
                          "avionics volume")

        self.wing.substitutions[self.wing.planform.tau] = 0.115
        self.emp.substitutions[self.emp.vtail.planform.tau] = 0.08
        self.emp.substitutions[self.emp.htail.planform.tau] = 0.08

        constraints = [
            Wzfw >= sum(summing_vars(components, "W")) + Wpay + Wavn,
            self.emp.htail.Vh <= (
                self.emp.htail["S"]
                * self.emp.htail.lh/self.wing["S"]**2
                * self.wing["b"]),
            self.emp.vtail.Vv == (
                self.emp.vtail["S"]
                * self.emp.vtail.lv/self.wing["S"]
                / self.wing["b"]),
            self.wing.planform.CLmax/self.wing.mw <= (
                self.emp.htail.planform.CLmax
                / self.emp.htail.mh),
            # enforce antenna sticking on the tail
            self.emp.vtail.planform.croot*self.emp.vtail.planform.lam >= (
                wantenna),
            self.emp.vtail["b"] >= lantenna,
            # enforce a cruciform with the htail infront of vertical tail
            self.emp.tailboom["l"] >= (
                self.emp.htail.lh
                + self.emp.htail.planform.croot),
            4./6*pi*self.fuselage["k_{nose}"]*self.fuselage["R"]**3 >= Volpay,
            self.fuselage["\\mathcal{V}_{body}"] >= (
                self.fuselage.fueltank["\\mathcal{V}"] + Volavn),
            ]

        if df70:
            constraints.extend([self.engine["h"] <= 2*self.fuselage["R"]])

        return components, constraints

    def flight_model(self, state):
        return AircraftPerf(self, state)

    def loading(self, Wcent, state):
        return AircraftLoading(self, Wcent, state)

class Pylon(Model):
    "attachment from fuselage to pylon"
    def setup(self):

        h = Variable("h", 7, "in", "pylon height")
        l = Variable("l", 32.8, "in", "pylon length")
        S = Variable("S", "ft**2", "pylon surface area")
        W = Variable("W", 1.83, "lbf", "pylon weight")

        constraints = [S >= 2*l*h]

        return constraints

    def flight_model(self, state):
        return PylonAero(self, state)

class PylonAero(Model):
    "pylon drag model"
    def setup(self, static, state):

        Cf = Variable("C_f", "-", "fuselage skin friction coefficient")
        Re = Variable("Re", "-", "fuselage reynolds number")

        constraints = [
            Re == state["V"]*state["\\rho"]*static["l"]/state["\\mu"],
            Cf >= 0.455/Re**0.3,
            ]

        return constraints

class AircraftLoading(Model):
    "aircraft loading model"
    def setup(self, aircraft, state, Wcent):

        hbend = aircraft.emp.tailboom.tailLoad(aircraft.emp.tailboom,
                                               aircraft.emp.htail, state)
        vbend = aircraft.emp.tailboom.tailLoad(aircraft.emp.tailboom,
                                               aircraft.emp.vtail, state)
        self.wingl = aircraft.wing.spar.loading(aircraft.wing, state)
        loading = [hbend, vbend, self.wingl]
        loading.append(aircraft.fuselage.loading(Wcent))
        loading.append(TailBoomFlexibility(aircraft.emp.htail, hbend,
                                           aircraft.wing))

        return loading

class AircraftPerf(Model):
    "performance model for aircraft"
    def setup(self, static, state, **kwargs):

        self.wing = static.wing.flight_model(static.wing, state)
        self.fuselage = static.fuselage.flight_model(state)
        self.engine = static.engine.flight_model(state)
        self.htail = static.emp.htail.flight_model(static.emp.htail, state)
        self.vtail = static.emp.vtail.flight_model(static.emp.vtail, state)
        self.tailboom = static.emp.tailboom.flight_model(static.emp.tailboom,
                                                         state)
        self.pylon = static.pylon.flight_model(state)

        self.dynamicmodels = [self.wing, self.fuselage, self.engine,
                              self.htail, self.vtail, self.tailboom, self.pylon]
        areadragmodel = [self.fuselage, self.htail, self.vtail, self.tailboom,
                         self.pylon]
        areadragcomps = [static.fuselage, static.emp.htail,
                         static.emp.vtail,
                         static.emp.tailboom, static.pylon]

        Wend = Variable("W_{end}", "lbf", "vector-end weight")
        Wstart = Variable("W_{start}", "lbf", "vector-begin weight")
        CD = Variable("C_D", "-", "drag coefficient")
        CDA = Variable("CDA", "-", "area drag coefficient")
        mfac = Variable("m_{fac}", 1.15, "-", "drag margin factor")

        dvars = []
        for dc, dm in zip(areadragcomps, areadragmodel):
            if "C_d" in dm.varkeys:
                dvars.append(dm["C_d"]*dc["S"]/static.wing["S"])
            if "Cd" in dm.varkeys:
                dvars.append(dm["Cd"]*dc["S"]/static.wing["S"])
            if "Cf" in dm.varkeys:
                dvars.append(dm["Cf"]*dc["S"]/static.wing["S"])
            if "C_f" in dm.varkeys:
                dvars.append(dm["C_f"]*dc["S"]/static.wing["S"])

        constraints = [CDA >= sum(dvars),
                       CD/mfac >= CDA + self.wing.Cd]

        return self.dynamicmodels, constraints

class FlightState(Model):
    "define environment state during a portion of an aircraft mission"
    def setup(self, alt, wind, **kwargs):

        rho = self.rho = Variable("\\rho", "kg/m^3", "air density")
        h = Variable("h", alt, "ft", "altitude")
        href = Variable("h_{ref}", 15000, "ft", "Reference altitude")
        psl = Variable("p_{sl}", 101325, "Pa", "Pressure at sea level")
        Latm = Variable("L_{atm}", 0.0065, "K/m", "Temperature lapse rate")
        Tsl = Variable("T_{sl}", 288.15, "K", "Temperature at sea level")
        temp = [(t.value - l.value*v.value).magnitude
                for t, v, l in zip(Tsl, h, Latm)]
        Tatm = Variable("t_{atm}", temp, "K", "Air temperature")
        mu = self.mu = Variable("\\mu", "N*s/m^2", "Dynamic viscosity")
        musl = Variable("\\mu_{sl}", 1.789*10**-5, "N*s/m^2",
                        "Dynamic viscosity at sea level")
        Rspec = Variable("R_{spec}", 287.058, "J/kg/K",
                         "Specific gas constant of air")
        qne = self.qne = Variable("qne", "kg/s^2/m",
                                  "never exceed dynamic pressure")
        Vne = Variable("Vne", 40, "m/s", "never exceed velocity")
        rhosl = Variable("rhosl", 1.225, "kg/m^3", "air density at sea level")

        # Atmospheric variation with altitude (valid from 0-7km of altitude)
        constraints = [rho == psl*Tatm**(5.257-1)/Rspec/(Tsl**5.257),
                       (mu/musl)**0.1 == 0.991*(h/href)**(-0.00529),
                       qne == 0.5*rhosl*Vne**2,
                       Latm == Latm]

        V = self.V = Variable("V", "m/s", "true airspeed")
        mfac = Variable("m_{fac}", 1.0, "-", "wind speed margin factor")

        if wind:

            V_wind = Variable("V_{wind}", 25, "m/s", "Wind speed")
            constraints.extend([V/mfac >= V_wind])

        else:

            V_wind = Variable("V_{wind}", "m/s", "Wind speed")
            V_ref = Variable("V_{ref}", 25, "m/s", "Reference wind speed")

            constraints.extend([(V_wind/V_ref) >= 0.6462*(h/href) + 0.3538,
                                V/mfac >= V_wind])
        return constraints

class FlightSegment(Model):
    "creates flight segment for aircraft"
    def setup(self, N, aircraft, alt=15000, wind=False, etap=0.7):

        self.aircraft = aircraft

        with Vectorize(N):
            self.fs = FlightState(alt, wind)
            self.aircraftPerf = self.aircraft.flight_model(self.fs)
            self.slf = SteadyLevelFlight(self.fs, self.aircraft,
                                         self.aircraftPerf, etap)
            self.be = BreguetEndurance(self.aircraftPerf)

        self.submodels = [self.fs, self.aircraftPerf, self.slf, self.be]

        Wfuelfs = Variable("W_{fuel-fs}", "lbf", "flight segment fuel weight")

        self.constraints = [Wfuelfs >= self.be["W_{fuel}"].sum()]

        if N > 1:
            self.constraints.extend([self.aircraftPerf["W_{end}"][:-1] >=
                                     self.aircraftPerf["W_{start}"][1:]])

        return self.aircraft, self.submodels, self.constraints

class Loiter(Model):
    "make a loiter flight segment"
    def setup(self, N, aircraft, alt=15000, wind=False, etap=0.7):
        self.fs = FlightSegment(N, aircraft, alt, wind, etap)

        t = Variable("t", "days", "time loitering")
        constraints = [self.fs.be["t"] >= t/N]

        return constraints, self.fs

class Cruise(Model):
    "make a cruise flight segment"
    def setup(self, N, aircraft, alt=15000, wind=False, etap=0.7, R=200):
        fs = FlightSegment(N, aircraft, alt, wind, etap)

        R = Variable("R", R, "nautical_miles", "Range to station")
        constraints = [R/N <= fs["V"]*fs.be["t"]]

        return fs, constraints

class Climb(Model):
    "make a climb flight segment"
    def setup(self, N, aircraft, alt=15000, wind=False, etap=0.7, dh=15000):
        fs = FlightSegment(N, aircraft, alt, wind, etap)

        with Vectorize(N):
            hdot = Variable("\\dot{h}", "ft/min", "Climb rate")

        deltah = Variable("\\Delta h", dh, "ft", "altitude difference")
        hdotmin = Variable("\\dot{h}_{min}", 100, "ft/min",
                           "minimum climb rate")

        constraints = [
            hdot*fs.be["t"] >= deltah/N,
            hdot >= hdotmin,
            fs.slf["T"] >= (0.5*fs["\\rho"]*fs["V"]**2*fs["C_D"]
                            * fs.aircraft.wing["S"] + fs["W_{start}"]*hdot
                            / fs["V"]),
            ]

        return fs, constraints

class SLFMaxSpeed(Model):
    "steady level flight model"
    def setup(self, state, aircraft, perf, etap):

        T = Variable("T", "N", "thrust")
        etaprop = Variable("\\eta_{prop}", etap, "-", "propulsive efficiency")

        constraints = [
            (perf["W_{end}"]*perf["W_{start}"])**0.5 <= (
                0.5*state["\\rho"]*state["V_{max}"]**2*perf.wing.CL
                * aircraft.wing["S"]),
            T >= (0.5*state["\\rho"]*state["V_{max}"]**2*perf["C_D"]
                  *aircraft.wing["S"]),
            perf["P_{shaft-max}"] >= T*state["V_{max}"]/etaprop]

        return constraints

class SteadyLevelFlight(Model):
    "steady level flight model"
    def setup(self, state, aircraft, perf, etap):

        T = Variable("T", "N", "thrust")
        etaprop = Variable("\\eta_{prop}", etap, "-", "propulsive efficiency")

        constraints = [
            (perf["W_{end}"]*perf["W_{start}"])**0.5 <= (
                0.5*state["\\rho"]*state["V"]**2*perf.wing.CL
                * aircraft.wing["S"]),
            T >= (0.5*state["\\rho"]*state["V"]**2*perf["C_D"]
                  *aircraft.wing["S"]),
            perf["P_{shaft}"] >= T*state["V"]/etaprop]

        return constraints

class Mission(Model):
    "creates flight profile"
    def setup(self, wind=False, DF70=True):

        mtow = Variable("MTOW", "lbf", "max-take off weight")
        Wcent = Variable("W_{cent}", "lbf", "center aircraft weight")
        Wfueltot = Variable("W_{fuel-tot}", "lbf", "total aircraft fuel weight")

        self.JHO = Aircraft(Wfueltot, df70=DF70)

        LS = Variable("(W/S)", "lbf/ft**2", "wing loading",
                      evalfn=lambda v: v[mtow]/v[self.JHO.wing.planform["S"]])

        climb1 = Climb(10, self.JHO, alt=np.linspace(0, 15000, 11)[1:], etap=0.508, wind=wind)
        cruise1 = Cruise(1, self.JHO, etap=0.684, R=180, wind=wind)
        loiter1 = Loiter(5, self.JHO, etap=0.647, wind=wind)
        cruise2 = Cruise(1, self.JHO, etap=0.684, wind=wind)
        mission = [climb1, cruise1, loiter1, cruise2]
        loading = self.JHO.loading(loiter1.fs.fs, Wcent)

        constraints = [
            mtow == climb1["W_{start}"][0],
            Wfueltot >= sum(fs["W_{fuel-fs}"] for fs in mission),
            mission[-1]["W_{end}"][-1] >= self.JHO["W_{zfw}"],
            Wcent >= Wfueltot + sum(summing_vars(self.JHO.smeared_loads, "W")),
            loiter1["P_{total}"] >= (loiter1["P_{shaft}"] + (
                loiter1["P_{avn}"] + self.JHO["P_{pay}"])
                                     / loiter1["\\eta_{alternator}"]),
            Wcent == loading.wingl["W"]
            ]

        for i, fs in enumerate(mission[1:]):
            constraints.extend([
                mission[i]["W_{end}"][-1] == fs["W_{start}"][0]
                ])

        return self.JHO, mission, loading, constraints

def test():
    "test method run by external CI"
    model = Mission()
    model.substitutions[model.JHO.emp.vtail.Vv] = 0.04
    model.cost = 1/model["Mission.Loiter.t"]
    model.localsolve()

if __name__ == "__main__":
    test()
    # M = Mission(DF70=False)
    # M.substitutions[M.JHO.emp.vtail.Vv] = 0.04
    # M.substitutions["Mission.Loiter.t"] = 6
    # M.substitutions["Mission.Aircraft.Engine.m_{fac}"] = 0.75
    # M.cost = M["MTOW"]
    # sol = M.localsolve()
    # sd = get_highestsens(M, sol, N=15)
    # f, a = plot_chart(sd)
    # f.savefig("sensbarfree.pdf", bbox_inches="tight")
    # M = Mission(DF70=False)
    # M.cost = 1/M["t.Mission.Loiter"]
    # lower = 50
    # upper = 1000
    # xmin_ = np.linspace(lower, upper, 100)
    # bst = autosweep_1d(M, 1e-2, M["MTOW"], [lower, upper], solver="mosek")

    # fig, ax = plt.subplots()
    # ax.plot(xmin_, 1/bst.sample_at(xmin_)["cost"])
    # ax.set_xlabel("Max Take Off Weight [lbf]")
    # ax.set_ylabel("Endurance [days]")
    # ax.grid()
    # fig.savefig("mtowtend.pdf")


import discord

from auth import setAuth
from discord.ext import commands
#https://gist.github.com/vbe0201/ade9b80f2d3b64643d854938d40a0a2d
from music import *

auth = setAuth()
token = auth[0]
prefix = auth[1]

banned_users = (0, 467518086262816769, 464930509101858826, 220250919093272576, 205557510256590848) #Trung has been banned.
debug = False

bot = commands.Bot(prefix, description='RoEW')
bot.add_cog(Music(bot))

#https://discordpy.readthedocs.io/en/latest/api.html#discord-models
#https://discordpy.readthedocs.io/en/latest/faq.html
#https://www.w3schools.com/python/python_ref_list.asp

@bot.event
async def on_ready():
    print(':mima:')
    print('Logged in as {0.user}'.format(bot))

@bot.event
async def on_message(message):
    if message.author == bot.user:
        return

    pieces = message.content.split()
    cmd = pieces[0]

    if message.content.startswith(prefix) and debug:
        log_channel = bot.get_channel(541002881688666133)
        await log_channel.send(message.author.name + "#" + message.author.discriminator + ' used the ' + cmd + ' command in ' + message.guild.name + '.')

    if banned_users.count(message.author.id) == 0:
        await bot.process_commands(message)
    else:
        if message.content.startswith(prefix):
            print('Banned user ' + message.author.name + "#" + message.author.discriminator + ' tried to use the ' + cmd + ' command in ' + message.guild.name + '.')

class Mima(commands.Cog):

    @bot.command(name='xfis')
    async def _xfis(ctx, *, arg: str):
        """
        Wish's personal mischief function.
        """
        if ctx.author.id == 123211683052257280:
            await ctx.send(arg)
            await ctx.message.delete()
        else:
            await ctx.send('denied')

    @bot.command(name='mine')
    async def _mine(ctx, diff: str="lunatic"):
        """
        Sets up a game of minesweeper. (Old Meema functions under reconstruction.)
        """
        await ctx.send('under construction')

    @bot.command(name='update')
    async def _update(ctx, *, arg: str):
        """
        Updates/refreshes the bot.  Only usable by Wish.
        """
        if ctx.author.id == 123211683052257280:
            await ctx.send('Rebooting...')
            bot.close()
        else:
            await ctx.send('denied')

#bot.add_cog(Mima(bot))

bot.run(token)


#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-

import graph_tool as gt
import graph_tool.stats
import graph_tool.draw
import numpy as np
import pylab
import matplotlib

if __name__ == "__main__":
    # We start with an empty, directed graph.
    g = gt.Graph()

    # We want also to keep the age information for each vertex and edge.
    # For that let's create some property maps.
    v_age = g.new_vertex_property("int")
    e_age = g.new_edge_property("int")

    # The final size of the network.
    N = 100000

    # We have to start with one vertex.
    v = g.add_vertex()
    v_age[v] = 0

    # We will keep a list of the vertices. The number of times a vertex is in this list
    # will give the probability of it being selected.
    vlist = [v]

    # let's now add the new edges and vertices
    for i in range(1, N):
        # create our new vertex
        v = g.add_vertex()
        v_age[v] = i

        # we need to sample a new vertex to be the target, based on its in-degree+1.
        # For that, we simply randomly sample it from vlist.
        i = np.random.randint(0, len(vlist))
        target = vlist[i]

        # add edge
        e = g.add_edge(v, target)
        e_age[e] = i

        # put v and target in the list
        vlist.append(target)
        vlist.append(v)

    # now we have a graph!

    # let's do a random walk on the graph and print the age of the vertices we find,
    # just for fun.
    v = g.vertex(np.random.randint(0, g.num_vertices()))
    while True:
        print("vertex:{}, in-degree:{}, out-degree:{}, age:{}".format(int(v), v.in_degree(), v.out_degree(), v_age[v]))

        if v.out_degree() == 0:
            print("Nowhere else to go... We found the main hub!")
            break

        n_list = []
        for w in v.out_neighbours():
            n_list.append(w)
        v = n_list[np.random.randint(0, len(n_list))]

    # let's save our graph for posterity. We want to save the age properties as well...
    # To do this, they must become "internal" properties:

    g.vp["age"] = v_age
    g.ep["age"] = e_age

    # now we can save it
    g.save("price.xml.gz")

    # let's plot its in-degree distribution
    in_hist = gt.stats.vertex_hist(g, "in")

    y = in_hist[0]
    x = in_hist[1]
    pylab.figure(figsize=(6, 4))
    pylab.hist(y, x)
    pylab.gca().set_yscale("log")
    pylab.gca().set_ylim(1e-1, 1e5)

    pylab.subplots_adjust(left=0.2, bottom=0.2)
    pylab.xlabel("$k_{in}$")
    pylab.ylabel("$NP(k_{in})$")
    pylab.tight_layout()
    pylab.savefig("price-in-deg-dist.png")

    # let's plot its in-degree distribution
#    out_hist = gt.stats.vertex_hist(g, "out")
#
#    y = out_hist[0]
#    x = out_hist[1]
#    pylab.figure(figsize=(6, 4))
#    pylab.hist(y, x)
#    pylab.gca().set_yscale("log")
#    pylab.gca().set_ylim(1e-1, 1e5)
#
#    pylab.subplots_adjust(left=0.2, bottom=0.2)
#    pylab.xlabel("$k_{out}$")
#    pylab.ylabel("$NP(k_{out})$")
#    pylab.tight_layout()
#    pylab.savefig("price-out-deg-dist.png")

    g = gt.load_graph("price.xml.gz")
    age = g.vp.age

    pos = graph_tool.draw.sfdp_layout(g)

    # It takes long long time to draw an image.
    gt.draw.graph_draw(
        g,
        pos,
        output_size=(1000, 1000),
        vertex_color=[1, 1, 1, 0],
        vertex_fill_color=age,
        vertex_size=1,
        edge_pen_width=1.2,
        vcmap=matplotlib.cm.gist_heat_r,
        output="price.png")