from django.views.generic import TemplateView
from django.conf import settings
from django.contrib import messages
from django.views.decorators.csrf import csrf_exempt
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth import logout
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, View
from django.shortcuts import redirect
from django.utils import timezone
from django.utils.timezone import make_aware
from django.db.models import Q
from django.contrib.sites.models import Site
from itertools import combinations
from .forms import CheckoutForm, CouponForm, RefundForm, PaymentForm, SearchFAQForm
from .models import *
from core.functions import *
from django.http.response import JsonResponse, HttpResponse

import stripe

stripe.api_key = settings.STRIPE_SECRET_KEY

def is_valid_form(values):
    valid = True
    for field in values:
        if field == '':
            valid = False
    return valid

class CheckoutView(View):
    def get(self, *args, **kwargs):
        try:
            # GDPR check
            gdpr_check = check_gdpr_cookies(self)
            path = self.request.get_full_path()
            is_post = False
            # get the content of the basket
            order = Order.objects.get(user=self.request.user, ordered=False)
            form = CheckoutForm()

            test = str(type(order.shipping_address))
            print("test")
            print(test)
            print(type(test))

            if test == "<class 'NoneType'>":
                # get the users preset adresses if there are some
                shipping_address_qs = Address.objects.get(
                    user=self.request.user,
                    address_type='S',
                    default=True
                )
            else:
                shipping_address_qs = order.shipping_address

            test2 = str(type(order.billing_address))

            if test2 == "<class 'NoneType'>":
                # get the users preset adresses if there are some
                billing_address_qs = Address.objects.get(
                    user=self.request.user,
                    address_type='B',
                    default=True
                )
            else:
                billing_address_qs = order.billing_address

            context = {
                'gdpr_check': gdpr_check,
                'form': form,
                'couponform': CouponForm(),
                'first_load': True,
                'form_not_complete': False,
                'order': order,
                'shipping_address': shipping_address_qs,
                'billing_address': billing_address_qs,
                'DISPLAY_COUPON_FORM': True
            }

            if order.freight:
                freights = Freight.objects.all()

                selectedFreights = []

                for f in freights:
                    if f.id == int(order.freight.id):
                        selectedFreights.append(
                            {"chosen": True, "choice": f})
                    else:
                        selectedFreights.append(
                            {"chosen": False, "choice": f})
                context.update({"chosen_freight": True})
                context.update({"selectedFreights": selectedFreights})

            return render(self.request, "checkout.html", context)
        except ObjectDoesNotExist:
            messages.info(self.request, "Varukorgen är tom.")
            return redirect("core:order-summary")

    def post(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        form = CheckoutForm(self.request.POST or None)
        try:
            order = Order.objects.get(user=self.request.user, ordered=False)
            form_not_complete = False
            if form.is_valid():

                use_default_shipping = form.cleaned_data.get(
                    'use_default_shipping')
                if use_default_shipping:
                    address_qs = Address.objects.filter(
                        user=self.request.user,
                        address_type='S',
                        default=True
                    )
                    if address_qs.exists():
                        shipping_address = address_qs[0]
                        order.shipping_address = shipping_address
                        order.save()
                    else:
                        messages.info(
                            self.request, "Ingen förinställd leveransadress funnen.")
                        return redirect('core:checkout')
                else:
                    shipping_address1 = form.cleaned_data.get(
                        'shipping_address')
                    shipping_address2 = form.cleaned_data.get(
                        'shipping_address2')
                    shipping_zip = form.cleaned_data.get('shipping_zip')
                    s_post_town = form.cleaned_data.get('s_post_town')
                    if shipping_address2 == "<input":
                        shipping_address2 = ""
                    if shipping_address1 == "<input":
                        shipping_address1 = ""

                    if is_valid_form([shipping_address1, shipping_zip, s_post_town]):
                        shipping_address = Address(
                            user=self.request.user,
                            street_address=shipping_address1,
                            apartment_address=shipping_address2,
                            zip=shipping_zip,
                            post_town=s_post_town,
                            address_type='S'
                        )
                        shipping_address.save()

                        order.shipping_address = shipping_address
                        order.save()

                        set_default_shipping = form.cleaned_data.get(
                            'set_default_shipping')
                        if set_default_shipping:
                            shipping_address.default = True
                            shipping_address.save()

                    else:
                        form_not_complete = True
                        messages.info(
                            self.request, "Vargod fyll i de obligatoriska fälten för leveransadressen.")

                use_default_billing = form.cleaned_data.get(
                    'use_default_billing')
                same_billing_address = form.cleaned_data.get(
                    'same_billing_address')

                if same_billing_address and not form_not_complete:
                    billing_address = shipping_address
                    order.billing_address = billing_address
                    order.save()

                elif same_billing_address and form_not_complete:
                    billing_address1 = shipping_address1
                    billing_address2 = shipping_address2
                    billing_zip = shipping_zip
                    b_post_town = s_post_town

                elif use_default_billing:
                    address_qs = Address.objects.filter(
                        user=self.request.user,
                        address_type='B',
                        default=True
                    )
                    if address_qs.exists():
                        billing_address = address_qs[0]
                        order.billing_address = billing_address
                        order.save()
                    else:
                        messages.info(
                            self.request, "Ingen förinställd faktureringsadress funnen.")
                        return redirect('core:checkout')
                else:
                    billing_address1 = form.cleaned_data.get(
                        'billing_address')
                    billing_address2 = form.cleaned_data.get(
                        'billing_address2')
                    billing_zip = form.cleaned_data.get('billing_zip')
                    b_post_town = form.cleaned_data.get(
                        'b_post_town')
                    if billing_address1 == "<input":
                        billing_address1 = ""
                    if billing_address2 == "<input":
                        billing_address2 = ""

                    if is_valid_form([billing_address1, billing_zip, b_post_town]):
                        billing_address = Address(
                            user=self.request.user,
                            street_address=billing_address1,
                            apartment_address=billing_address2,
                            zip=billing_zip,
                            post_town=b_post_town,
                            address_type='B'
                        )
                        billing_address.save()

                        order.billing_address = billing_address
                        order.save()

                        set_default_billing = form.cleaned_data.get(
                            'set_default_billing')
                        if set_default_billing:
                            billing_address.default = True
                            billing_address.save()

                    else:
                        form_not_complete = True
                        messages.info(
                            self.request, "Vargod fyll i de obligatoriska fälten under faktureringsadressen.")

                freight_option = form.cleaned_data.get('freight_option')
                freight = Freight.objects.filter(id=int(freight_option))
                order.freight = freight[0]
                order.freight_price = order.freight.amount

                # recalculate order total

                order.total_price = calculate_total_order(order)
                order.ordered_date = make_aware(datetime.now())
                order.save()

                payment_option = form.cleaned_data.get('payment_option')

                if(form_not_complete):

                    # get the content of the basket
                    order = Order.objects.get(
                        user=self.request.user, ordered=False)

                    # create freight choices to go through to preselect if it is selected

                    freights = Freight.objects.all()

                    selectedFreights = []

                    for f in freight:
                        if f.id == int(freight_option):
                            selectedFreights.append(
                                {"chosen": True, "choice": f})
                        else:
                            selectedFreights.append(
                                {"chosen": False, "choice": f})

                    # create payment choices to go through to preselect if it is selected

                    payments = PaymentTypes.objects.all()

                    selectedPayments = []

                    for p in payments:
                        if p.short == payment_option:
                            selectedPayments.append(
                                {"chosen": True, "choice": p})
                        else:
                            selectedPayments.append(
                                {"chosen": False, "choice": p})

                    context = {
                        'gdpr_check': gdpr_check,
                        'form': form,
                        'couponform': CouponForm(),
                        'order': order,
                        'DISPLAY_COUPON_FORM': True,
                        'first_load': False,
                        'form_not_complete': form_not_complete,
                        'shipping_address1': shipping_address1,
                        'shipping_address2': shipping_address2,
                        'shipping_zip': shipping_zip,
                        's_post_town': s_post_town,
                        'billing_address1': billing_address1,
                        'billing_address2': billing_address2,
                        'billing_zip': billing_zip,
                        'b_post_town': b_post_town,
                        'use_default_shipping': use_default_shipping,
                        'use_default_billing': use_default_billing,
                        'same_billing_address': same_billing_address,
                        'selectedPayments': selectedPayments,
                        'selectedFreights': selectedFreights,
                    }

                    # get the users preset adresses if there are some
                    shipping_address_qs = Address.objects.filter(
                        user=self.request.user,
                        address_type='S',
                        default=True
                    )
                    if shipping_address_qs.exists():
                        context.update(
                            {'default_shipping_address': shipping_address_qs[0]})

                    billing_address_qs = Address.objects.filter(
                        user=self.request.user,
                        address_type='B',
                        default=True
                    )
                    if billing_address_qs.exists():
                        context.update(
                            {'default_billing_address': billing_address_qs[0]})

                    return render(self.request, "checkout.html", context)
                else:
                    if payment_option == 'S':
                        return redirect('core:confirm')
                    else:
                        messages.warning(
                            self.request, "Ogiltig betalningsalternativ valt.")
                        return redirect('core:checkout')
        except ObjectDoesNotExist:
            messages.warning(self.request, "Varukorgen är tom.")
            return redirect("core:order-summary")

class NewHomeView(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = True  # check_gdpr_cookies(self)

        categories = Category.objects.all()
        aquire_index = default_pagination_values
        number_products = Item.objects.all().count()
        pagination = {}
        is_paginated = False
        start_extras = False
        end_extras = False
        if(number_products > aquire_index):

            page = which_page(self)

            max_page = number_products/aquire_index

            testM = int(max_page)
            if(testM != max_page):
                max_page = testM + 1
            page_list, where = get_list_of_pages(int(page), int(max_page))

            if page == 1:
                if(page_list[-1] == max_page):
                    hasNext = False
                else:
                    hasNext = True
                pagination = {
                    "has_previous": False,
                    "previous_page_number": 1,
                    "number": 1,
                    "has_next": hasNext,
                    "next_page_number": 2
                }
                is_paginated = True
                products = Item.objects.all()[:aquire_index]
                if where != "no extras":
                    end_extras = True

            else:
                page = int(page)
                # query[offset:offset + limit]
                start_point = (int(page) - 1) * aquire_index
                o_and_l = start_point + aquire_index
                products = Item.objects.all()[start_point:o_and_l]
                is_paginated = True
                if page < max_page:
                    next_page = page + 1
                    previous_page = page - 1
                    if(page == max_page):
                        hasNext = False
                    else:
                        hasNext = True

                    if(len(page_list) == max_page):
                        hasPreivous = False
                    else:
                        hasPreivous = True

                    pagination = {
                        "has_previous": hasPreivous,
                        "previous_page_number": previous_page,
                        "number": page,
                        "has_next": hasNext,
                        "next_page_number": next_page
                    }
                else:
                    previous_page = page - 1

                    if(len(page_list) == max_page):
                        hasPreivous = False
                    else:
                        hasPreivous = True

                    pagination = {
                        "has_previous": hasPreivous,
                        "previous_page_number": previous_page,
                        "number": page,
                        "has_next": False,
                        "next_page_number": page
                    }

                if where == "start":
                    end_extras = True
                elif where == "end":
                    start_extras = True
                elif where == "mid":
                    start_extras = True
                    end_extras = True
        else:
            products = Item.objects.all()[:aquire_index]

            is_paginated = False
            pagination = {
                "has_previous": False,
                "has_next": False,
            }

        GDPR = self.request.COOKIES.get("GDPR")
        gdpr_check = True
        if GDPR == "GDPR":
            gdpr_check = False

        context = {
            'gdpr_check': gdpr_check,
            "category_choices": categories,
            "object_list": products,
            "is_paginated": is_paginated,
            "page_obj": pagination,
            "page_list": page_list,
            "start_extras": start_extras,
            "end_extras": end_extras,
            "max_page": int(max_page),
        }
        response = render(self.request, 'home.html', context)

        if GDPR != "GDPR":
            response.set_cookie("GDPR", "GDPR")

        return response

    def post(self, *args, **kwargs):
        return redirect("core:home")

class OrderSummaryView(LoginRequiredMixin, View):
    def get(self, *args, **kwargs):
        login_url = '/accounts/login/'
        redirect_field_name = 'from'
        redirect_field_value = 'to'
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        try:
            # if the user has an old basket and are returning the prices may have changed. Same if there are changes coming into effect before the order has been payed for. We need to check, update and let the user know if there is a change
            order = Order.objects.get(
                user=self.request.user, ordered=False)
            orderItems = order.items.all()
            warning = ""
            info = ""
            recount = False

            for orderItem in orderItems:
                item = orderItem.item
                total_price = 0
                if item.discount_price != None:
                    total_price = item.discount_price * orderItem.quantity
                else:
                    total_price = item.price * orderItem.quantity

                if orderItem.total_price != total_price:
                    recount = True
                    # check if there is a discount
                    # set a warning to the user so they know that there are alterations to the order
                    warning = "Priser ändrade då de antingen är gamla eller inte längre giltiga."
                    if item.discount_price != None:
                        total_price = item.discount_price * orderItem.quantity
                        if orderItem.total_price != total_price:
                            # there is difference in prices this is most likely due to a change in price of the item or discount price no longer valid
                            if item.discount_price != None:
                                total = item.discount_price * orderItem.quantity
                                orderItem.price = item.price
                                orderItem.discount_price = item.discount_price
                                orderItem.total_price = total
                                orderItem.save()
                            else:
                                total = item.price * orderItem.quantity
                                orderItem.price = item.price
                                orderItem.discount_price = item.discount_price
                                orderItem.total_price = total
                                orderItem.save()
                    else:
                        # there is no discount but the price isnt right so correct the prices
                        total = item.price * orderItem.quantity
                        orderItem.price = item.price
                        orderItem.discount_price = item.discount_price
                        orderItem.total_price = total
                        orderItem.save()
                else:
                    # the price is correct towards the regular price but check that there isnt currently a discount
                    if item.discount_price != None and (item.discount_price * orderItem.quantity) != orderItem.total_price:
                        recount = True
                        # there is currently a discount recalculate the price
                        # set a warning to the user so they know that there are alterations to the order
                        info = "Priser ändrade då de för nuvarnde är på rea."
                        total = item.discount_price * orderItem.quantity
                        orderItem.total_price = total
                        orderItem.save()

            if warning != "":
                messages.warning(
                    self.request, warning)

            if info != "":
                messages.info(
                    self.request, info)

            if recount:
                print("recount")
                # prices have changed order needs to be updated
                newTotal = update_order_total(order)
                order.total_price = newTotal
                order.ordered_date = make_aware(datetime.now())
                order.updated_date = make_aware(datetime.now())
                order.save()
                freshOrder = Order.objects.get(id=order.id)
            else:
                # no update can pass order to view without anything
                freshOrder = order

            context = {
                'gdpr_check': gdpr_check,
                'object': freshOrder,
            }
            return render(self.request, 'order_summary.html', context)
        except ObjectDoesNotExist:
            messages.warning(self.request, "Varukorgen är tom.")
            return redirect("/")

class ItemDetailView(DetailView):
    model = Item
    template_name = "product.html"

    def get_context_data(self, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        context = super().get_context_data(**kwargs)
        categories = Category.objects.all()
        context['category_choices'] = categories
        context['gdpr_check'] = gdpr_check
        context['path'] = self.object.get_absolute_url()
        return context

@login_required
def add_to_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_item, created = OrderItem.objects.get_or_create(
        item=item,
        title=item.title,
        price=item.price,
        discount_price=item.discount_price,
        quantity=1,
        user=request.user,
        ordered=False
    )
    order_qs = Order.objects.filter(user=request.user, ordered=False)
    if order_qs.exists():
        order = order_qs[0]
        order.ordered_date = make_aware(datetime.now())
        order.updated_date = make_aware(datetime.now())
        # check if the order item is in the order
        if order.items.filter(item__slug=item.slug).exists():
            order_item.quantity += 1
            if item.discount_price != None:
                if item.discount_price > 0:
                    if order_item.discount_price != item.discount_price:
                        messages.info(request, "Varans pris har uppdaterats.")
                        order_item.discount_price = item.discount_price
                    order_item.total_price = order_item.quantity * order_item.discount_price
            else:
                order_item.total_price = order_item.quantity * order_item.price
            order_item.save()
            messages.info(request, "Varans mängd har uppdaterats.")
            return redirect("core:order-summary")
        else:
            if item.discount_price:
                order_item.total_price = order_item.discount_price * order_item.quantity
            else:
                order_item.total_price = order_item.price * order_item.quantity
            order_item.save()
            order.items.add(order_item)
            order.total_price = calculate_total_order(order)
            order.save()
            messages.info(request, "Varan lagd i varukorgen.")
            return redirect("core:order-summary")
    else:
        ordered_date = make_aware(datetime.now())
        updated_date = make_aware(datetime.now())
        refCode = create_ref_code()
        rcode = test_order_ref_code(refCode)
        order = Order.objects.create(
            user=request.user, ordered_date=ordered_date, updated_date=updated_date, ref_code=rcode)
        order_item.quantity = 1
        order_item.discount_price = item.discount_price
        order_item.price = item.price
        if item.discount_price != None and item.discount_price > 0:
            order_item.total_price = order_item.discount_price * order_item.quantity
        else:
            order_item.total_price = order_item.price * order_item.quantity
        order_item.save()
        order.items.add(order_item)
        order.total_price = calculate_total_order(order)
        order.save()
        messages.info(request, "Varan lagd i varukorgen.")
        return redirect("core:order-summary")

@login_required
def remove_from_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_qs = Order.objects.filter(
        user=request.user,
        ordered=False
    )
    if order_qs.exists():
        order = order_qs[0]
        order.ordered_date = make_aware(datetime.now())
        order.updated_date = make_aware(datetime.now())
        # check if the order item is in the order
        if order.items.filter(item__slug=item.slug).exists():
            order_item = OrderItem.objects.filter(
                item=item,
                user=request.user,
                ordered=False
            )[0]
            order.items.remove(order_item)
            order.save()
            order_item.delete()
            messages.info(request, "Varan borttagen ur varukorgen.")
            all_items = order.items.all()
            if len(all_items) == 0:
                order.delete()
            return redirect("core:order-summary")
        else:
            messages.info(request, "Denna vara fanns inte i din varukorg.")
            return redirect("core:product", slug=slug)
    else:
        messages.info(request, "Din varukorg är tom")
        return redirect("core:product", slug=slug)

@login_required
def remove_single_item_from_cart(request, slug):
    item = get_object_or_404(Item, slug=slug)
    order_qs = Order.objects.filter(
        user=request.user,
        ordered=False
    )
    if order_qs.exists():
        order = order_qs[0]
        order.ordered_date = make_aware(datetime.now())
        order.updated_date = make_aware(datetime.now())
        # check if the order item is in the order
        if order.items.filter(item__slug=item.slug).exists():
            order_item = OrderItem.objects.get(
                item=item,
                user=request.user,
                ordered=False
            )
            if order_item.quantity > 1:
                order_item.quantity -= 1
                if item.discount_price != None:
                    if item.discount_price > 0:
                        if order_item.discount_price != item.discount_price:
                            order_item.discount_price = item.discount_price
                        order_item.total_price = order_item.quantity * order_item.discount_price
                else:
                    order_item.total_price = order_item.quantity * order_item.price
                order_item.save()
            else:
                order.items.remove(order_item)
                order_item.delete()
                if len(order.items.all()) == 0:
                    order.delete()
            messages.info(request, "Varans mängd har uppdaterats.")
            return redirect("core:order-summary")
        else:
            messages.info(request, "Denna vara fanns inte i din varukorg.")
            return redirect("core:product", slug=slug)
    else:
        messages.info(request, "Varukorgen är tom.")
        return redirect("core:product", slug=slug)

def get_coupon(request, code):
    try:
        coupon = Coupon.objects.get(code=code)
        return coupon
    except ObjectDoesNotExist:
        messages.info(request, "Denna rabattkod är inte giltig.")
        return redirect("core:checkout")

class AddCouponView(View):
    def get(self, *args, **kwargs):
        # reroute
        message = get_message('error', 136)
        messages.warning(
            self.request, message)
        return redirect("core:home")

    def post(self, *args, **kwargs):
        form = CouponForm(self.request.POST or None)
        if form.is_valid():
            try:
                code = form.cleaned_data.get('code')
                order = Order.objects.get(
                    user=self.request.user, ordered=False)
                order.updated_date = make_aware(datetime.now())
                order.coupon = get_coupon(self.request, code)
                order.save()
                messages.success(self.request, "Rabattkod tillagd.")
                return redirect("core:checkout")
            except ObjectDoesNotExist:
                messages.info(self.request, "Din varukorg är tom.")
                return redirect("core:checkout")
        else:
            messages.info(self.request, "Denna rabattkod är ej giltig.")
            return redirect("core:checkout")

# Category views

class CategoryView(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        try:
            page, am_i = where_am_i_and_page(self)
            print(page)
            print(am_i)
            categoryquery = Category.objects.get(slug=am_i)

            # alter this to a set number of products and add pagination
            aquire_index = default_pagination_values
            number_products = Item.objects.filter(
                category=categoryquery).count()
            pagination = {}
            is_paginated = False
            start_extras = False
            end_extras = False

            if(number_products > aquire_index):

                max_page = number_products/aquire_index
                testM = int(max_page)
                if(testM != max_page):
                    max_page = testM + 1
                page_list, where = get_list_of_pages(int(page), int(max_page))
                if page == 1:
                    if(page == max_page):
                        hasNext = False
                    else:
                        hasNext = True
                    pagination = {
                        "has_previous": False,
                        "previous_page_number": 1,
                        "number": 1,
                        "has_next": hasNext,
                        "next_page_number": 2
                    }
                    is_paginated = True
                    products = Item.objects.filter(
                        category=categoryquery)[:aquire_index]
                    if where != "no extras":
                        end_extras = True
                else:

                    # query[offset:offset + limit]
                    start_point = (int(page) - 1) * aquire_index
                    o_and_l = start_point + aquire_index
                    products = Item.objects.filter(category=categoryquery)[
                        start_point:o_and_l]
                    is_paginated = True
                    number_of_pages = number_products / aquire_index
                    test = int(number_of_pages)
                    if number_of_pages > test:
                        number_of_pages += 1

                    if page < number_of_pages:
                        next_page = page + 1
                        previous_page = page - 1
                        hasNext = True
                    else:
                        next_page = page
                        previous_page = page - 1
                        hasNext = False
                    hasPreivous = True

                    pagination = {
                        "has_previous": hasPreivous,
                        "previous_page_number": previous_page,
                        "number": page,
                        "has_next": hasNext,
                        "next_page_number": next_page
                    }

                if where == "start":
                    end_extras = True
                elif where == "end":
                    start_extras = True
                elif where == "mid":
                    start_extras = True
                    end_extras = True

            else:
                products = Item.objects.filter(
                    category=categoryquery)[:aquire_index]

                is_paginated = False
                pagination = {
                    "has_previous": False,
                    "has_next": False,
                }

            # we need to create a list of objects to loop through to mark the apropriate category

            category_choices = Category.objects.all()

            new_list = []
            for cat in category_choices:
                if cat.title == categoryquery.title:
                    new_list.append({
                        'title': cat.title,
                        'url': cat.get_absolute_cat_url,
                        'selected': True
                    })
                else:
                    new_list.append({
                        'title': cat.title,
                        'url': cat.get_absolute_cat_url,
                        'selected': False
                    })

            context = {
                'gdpr_check': gdpr_check,
                'object_list': products,
                'category_list': new_list,
                'selected_cateogory': categoryquery,
                "is_paginated": is_paginated,
                "page_obj": pagination,                    "page_list": page_list,
                "start_extras": start_extras,
                "end_extras": end_extras,
                "max_page": max_page,
            }
            return render(self.request, "category.html", context)
        except ObjectDoesNotExist:
            messages.info(
                self.request, "Något har gått fel, vargod kontakta supporten.")
            return redirect("core:home")

# FAQ

class FAQView(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)

        try:
            # need to add language tests here at a later date
            theLanguage = LanguageChoices.objects.get(language_short="swe")
            aquire_index = default_pagination_values
            number_faqs = FAQ.objects.filter(language=theLanguage).count()
            pagination = {}
            page_list = []
            is_paginated = False
            start_extras = False
            end_extras = False
            max_page = 0
            if(number_faqs > aquire_index):
                # we only land here if we are on page one without a search and we have more FAQs than fit on one page
                max_page = number_faqs / aquire_index
                testM = int(max_page)
                if(testM != max_page):
                    max_page = testM + 1
                page_list, where = get_list_of_pages(1, int(max_page))

                if(1 != max_page):
                    hasNext = False
                else:
                    hasNext = True

                pagination = {
                    "has_previous": False,
                    "previous_page_number": 1,
                    "number": 1,
                    "has_next": hasNext,
                    "next_page_number": 2
                }
                is_paginated = True
                try:
                    faqs = FAQ.objects.filter(language=theLanguage)[
                        :aquire_index]
                except ObjectDoesNotExist:
                    message = get_message('error', 135)
                    faqs = [
                        {
                            "question": "Ett FAQ fel har uppstått:",
                            "answer": message,
                        }
                    ]

                if where != "no extras":
                    end_extras = True

            else:
                # we have less FAQs then we want from aquire index, so no pagination here and no need to do a specialised search
                try:
                    faqs = FAQ.objects.filter(language=theLanguage)
                except ObjectDoesNotExist:
                    message = get_message('error', 135)
                    faqs = [
                        {
                            "question": "Ett FAQ fel har uppstått:",
                            "answer": message,
                        }
                    ]

            try:
                searchForm = SearchFAQForm()
                aButtonType = ButtonType.objects.get(buttonType="search")
                searchButton = ButtonText.objects.filter(
                    language=theLanguage, theButtonType=aButtonType)
            except ObjectDoesNotExist:
                message = get_message('error', 135)
                # flag it support
                searchForm = SearchFAQForm()
                searchButton = {"buttonText": "Search"}

        except ObjectDoesNotExist:
            pagination = {}
            page_list = []
            is_paginated = False
            start_extras = False
            end_extras = False
            max_page = 0
            faqs = [
                {
                    "question": "Ett språk fel har uppstått:",
                    "answer": message,
                }
            ]
            searchForm = SearchFAQForm()
            searchButton = {"buttonText": "Search"}
        comment = ""

        context = {
            'gdpr_check': gdpr_check,
            'search': False,
            'faqs': faqs,
            "searchTerms": "",
            'searchForm': searchForm,
            "searchButton": searchButton,
            'is_paginated': is_paginated,
            'start_page': start_extras,
            'end_page': end_extras,
            'page_list': page_list,
            'max_page': max_page,
            'page_obj': pagination,
        }
        return render(self.request, "faq.html", context)

    def post(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        if "searchTerm" in self.request.POST.keys():
            # check that the search field isnt empty, if empty redirect to get section
            searchTest = self.request.POST["searchTerm"]

            if searchTest != "":
                # we just did a search, no matter what we are on page 1
                form = SearchFAQForm(self.request.POST)
                comment = ""
                if form.is_valid():
                    # need to add language tests here at a later date
                    theLanguage = LanguageChoices.objects.get(
                        language_short="swe")
                    search_terms = form.cleaned_data.get('searchTerm')
                    search_term_split = search_terms.split()
                    len_search_term = len(search_term_split)

                    # make all the combinations of the search

                    a = len_search_term
                    searchTermList = []
                    while a > 0:
                        searchCombinations = combinations(search_term_split, a)
                        for combination in searchCombinations:
                            term = ""
                            for word in combination:
                                if term == "":
                                    term = word
                                else:
                                    term = term + " " + word
                            searchTermList.append(term)
                        a -= 1
                    search = []
                    search_no_duplicates = []
                    aquire_index = default_pagination_values
                    pagination = {}
                    page_list = []
                    is_paginated = False
                    start_extras = False
                    end_extras = False
                    max_page = 1

                    # get all results

                    for term in searchTermList:
                        faqs = FAQ.objects.filter(
                            Q(subject__contains=term) | Q(content__contains=term))
                        search.append(faqs)

                    # place all query entries in a new array

                    for_sorting = []

                    for query in search:
                        for entry in query:
                            for_sorting.append(entry)

                    # remove all duplicates
                    for entry in for_sorting:
                        if(len(search_no_duplicates) == 0):
                            search_no_duplicates.append(entry)
                        else:
                            i = 0
                            same = False
                            while i < len(search_no_duplicates):
                                if search_no_duplicates[i].id == entry.id:
                                    i = len(search_no_duplicates)
                                    same = True
                                else:
                                    same = False
                                i += 1

                            if not same:
                                search_no_duplicates.append(entry)

                    # remove those not to be used

                    final_search_array = []

                    if len(search_no_duplicates) > aquire_index:
                        i = 0
                        while i < aquire_index:
                            final_search_array.append(search_no_duplicates[i])
                            i += 1
                    else:
                        final_search_array = search_no_duplicates

                    # create pagination

                    number_faqs = len(search_no_duplicates)
                    if(number_faqs > aquire_index):
                        max_page = number_faqs/aquire_index
                        testM = int(max_page)
                        if(testM != max_page):
                            max_page = testM + 1

                        if(max_page > 1):

                            page_list, where = get_list_of_pages(
                                1, int(max_page))

                            if(page_list[-1] == max_page):
                                hasNext = False
                            else:
                                hasNext = True
                            pagination = {
                                "has_previous": False,
                                "previous_page_number": 1,
                                "number": 1,
                                "has_next": hasNext,
                                "next_page_number": 2
                            }
                            if where != "no extras":
                                end_extras = True

                            is_paginated = True

                    try:
                        aButtonType = ButtonType.objects.get(
                            buttonType="search")
                        searchButton = ButtonText.objects.filter(
                            language=theLanguage, theButtonType=aButtonType)
                    except ObjectDoesNotExist:
                        searchButton = {"buttonText": "Search"}

                context = {
                    'gdpr_check': gdpr_check,
                    'search': True,
                    'faqs': final_search_array,
                    "searchTerms": searchTest,
                    'searchForm': form,
                    "searchButton": searchButton,
                    'is_paginated': is_paginated,
                    'start_page': start_extras,
                    'end_page': end_extras,
                    'page_list': page_list,
                    'max_page': max_page,
                    'page_obj': pagination,
                }
                return render(self.request, "faq.html", context)
            else:
                return redirect("core:faq")

        elif "SearchTerms" in self.request.POST.keys():
            # we are paginating a search this didnt start in the form
            search_terms = self.request.POST['SearchTerms']
            page = int(self.request.POST['page'])

            # need to add language tests here at a later date
            theLanguage = LanguageChoices.objects.get(
                language_short="swe")
            search_term_split1 = search_terms.split("\"")
            if len(search_term_split1) == 1:
                search_term_split = search_term_split1[0].split()
            elif len(search_term_split1) > 1:
                search_term_split = search_term_split1[1].split()
            else:
                search_term_split = search_term_split1
            len_search_term = len(search_term_split)

            # check if the search is empty

            if len_search_term > 0:

                # make all the combinations of the search

                a = len_search_term
                searchTermList = []
                while a > 0:
                    searchCombinations = combinations(search_term_split, a)
                    for combination in searchCombinations:
                        term = ""
                        for word in combination:
                            if term == "":
                                term = word
                            else:
                                term = term + " " + word
                        searchTermList.append(term)
                    a -= 1
                search = []
                search_no_duplicates = []
                aquire_index = default_pagination_values
                pagination = {}
                page_list = []
                is_paginated = False
                start_extras = False
                end_extras = False
                max_page = 1

                # get all results

                for term in searchTermList:
                    faqs = FAQ.objects.filter(
                        Q(subject__contains=term) | Q(content__contains=term))
                    search.append(faqs)

                # place all query entries in a new array

                for_sorting = []

                for query in search:
                    for entry in query:
                        for_sorting.append(entry)

                # remove all duplicates
                for entry in for_sorting:
                    if(len(search_no_duplicates) == 0):
                        search_no_duplicates.append(entry)
                    else:
                        i = 0
                        same = False
                        while i < len(search_no_duplicates):
                            if search_no_duplicates[i].id == entry.id:
                                i = len(search_no_duplicates)
                                same = True
                            else:
                                same = False
                            i += 1
                        if not same:
                            search_no_duplicates.append(entry)
                # remove those not to be used

                final_search_array = []

                finish = (int(page) * aquire_index)
                j = finish - aquire_index
                while j < finish:
                    if(j < len(search_no_duplicates)):
                        final_search_array.append(search_no_duplicates[j])
                    j += 1

                # create pagination

                number_faqs = len(search_no_duplicates)
                if(number_faqs > aquire_index):
                    max_page = number_faqs/aquire_index
                    testM = int(max_page)
                    if(testM != max_page):
                        max_page = testM + 1

                    if(max_page > 1):

                        page_list, where = get_list_of_pages(
                            int(page), int(max_page))

                        if(where == "no extras"):
                            start_extras = False
                            end_extras = False
                            hasNext = False
                            has_previous = False
                            previous_page_number = int(page)
                            next_page_number = int(page)
                        elif(where == "start"):
                            start_extras = False
                            end_extras = True
                            has_previous = False
                            hasNext = True
                            previous_page_number = int(page)
                            next_page_number = int(page) - 1
                        elif(where == "end"):
                            start_extras = True
                            end_extras = False
                            has_previous = True
                            hasNext = False
                            previous_page_number = int(page) - 1
                            next_page_number = int(page)
                        else:
                            start_extras = True
                            end_extras = True
                            has_previous = True
                            hasNext = True
                            previous_page_number = int(page) - 1
                            next_page_number = int(page) + 1

                        pagination = {
                            "has_previous": has_previous,
                            "previous_page_number": previous_page_number,
                            "number": int(page),
                            "has_next": hasNext,
                            "next_page_number": next_page_number
                        }

                        is_paginated = True

                try:
                    searchForm = SearchFAQForm()
                    aButtonType = ButtonType.objects.get(buttonType="search")
                    searchButton = ButtonText.objects.filter(
                        language=theLanguage, theButtonType=aButtonType)
                except ObjectDoesNotExist:
                    message = get_message('error', 135)
                    # flag it support
                    searchForm = SearchFAQForm()
                    searchButton = {"buttonText": "Search"}

                context = {
                    'gdpr_check': gdpr_check,
                    'search': True,
                    'faqs': final_search_array,
                    "searchTerms": search_terms,
                    'searchForm': searchForm,
                    "searchButton": searchButton,
                    'is_paginated': is_paginated,
                    'start_page': start_extras,
                    'end_page': end_extras,
                    'page_list': page_list,
                    'max_page': max_page,
                    'page_obj': pagination,
                }
                return render(self.request, "faq.html", context)
            else:
                # GDPR check
                gdpr_check = check_gdpr_cookies(self)

                try:
                    # need to add language tests here at a later date
                    theLanguage = LanguageChoices.objects.get(
                        language_short="swe")
                    aquire_index = default_pagination_values
                    number_faqs = FAQ.objects.filter(
                        language=theLanguage).count()
                    pagination = {}
                    page_list = []
                    is_paginated = False
                    start_extras = False
                    end_extras = False
                    max_page = 0
                    if(number_faqs > aquire_index):
                        # we only land here if we are on page one without a search and we have more FAQs than fit on one page
                        max_page = number_faqs / aquire_index
                        testM = int(max_page)
                        if(testM != max_page):
                            max_page = testM + 1
                        page_list, where = get_list_of_pages(1, int(max_page))

                        if(1 != max_page):
                            hasNext = False
                        else:
                            hasNext = True

                        if page - 1 >= 1:
                            previous = page - 1
                        else:
                            previous = page
                        if page > 1:
                            has_previous = True
                        else:
                            has_previous = False
                        if page + 1 <= max_page:
                            next = page + 1
                        else:
                            next = page
                        pagination = {
                            "has_previous": has_previous,
                            "previous_page_number": previous,
                            "number": page,
                            "has_next": hasNext,
                            "next_page_number": next
                        }
                        is_paginated = True
                        try:
                            if page - 1 < 1:
                                faqs = FAQ.objects.filter(language=theLanguage)[
                                    :aquire_index]
                            else:
                                offset = aquire_index * (page - 1)
                                o_l = offset + aquire_index
                                faqs = FAQ.objects.filter(language=theLanguage)[
                                    offset:o_l]
                        except ObjectDoesNotExist:
                            message = get_message('error', 135)
                            faqs = [
                                {
                                    "question": "Ett FAQ fel har uppstått:",
                                    "answer": message,
                                }
                            ]

                        if where != "no extras":
                            end_extras = True

                        if where == "start" or where == "mid":
                            start_extras = True

                        if max_page > 5 and where == "end":
                            start_extras = True

                    else:
                        # we have less FAQs then we want from aquire index, so no pagination here and no need to do a specialised search
                        try:
                            faqs = FAQ.objects.filter(language=theLanguage)
                        except ObjectDoesNotExist:
                            message = get_message('error', 135)
                            faqs = [
                                {
                                    "question": "Ett FAQ fel har uppstått:",
                                    "answer": message,
                                }
                            ]

                    try:
                        searchForm = SearchFAQForm()
                        aButtonType = ButtonType.objects.get(
                            buttonType="search")
                        searchButton = ButtonText.objects.filter(
                            language=theLanguage, theButtonType=aButtonType)
                    except ObjectDoesNotExist:
                        message = get_message('error', 135)
                        # flag it support
                        searchForm = SearchFAQForm()
                        searchButton = {"buttonText": "Search"}

                except ObjectDoesNotExist:
                    pagination = {}
                    page_list = []
                    is_paginated = False
                    start_extras = False
                    end_extras = False
                    max_page = 0
                    faqs = [
                        {
                            "question": "Ett språk fel har uppstått:",
                            "answer": message,
                        }
                    ]
                    searchForm = SearchFAQForm()
                    searchButton = {"buttonText": "Search"}
                comment = ""

                context = {
                    'gdpr_check': gdpr_check,
                    'search': False,
                    'faqs': faqs,
                    "searchTerms": "",
                    'searchForm': searchForm,
                    "searchButton": searchButton,
                    'is_paginated': is_paginated,
                    'start_page': start_extras,
                    'end_page': end_extras,
                    'page_list': page_list,
                    'max_page': max_page,
                    'page_obj': pagination,
                }
                return render(self.request, "faq.html", context)

        else:
            try:
                # need to add language tests here at a later date
                theLanguage = LanguageChoices.objects.get(language_short="swe")

                try:
                    faqs = FAQ.objects.filter(language=theLanguage)
                except ObjectDoesNotExist:
                    message = get_message('error', 135)
                    faqs = [
                        {
                            "question": "Ett fel har uppstått:",
                            "answer": message,
                        }
                    ]

                try:
                    searchForm = SearchFAQForm()
                    searchForm.language(theLanguage)
                    aButtonType = ButtonType.objects.get(buttonType="search")
                    searchButton = ButtonText.objects.filter(
                        language=theLanguage, theButtonType=aButtonType)
                except ObjectDoesNotExist:
                    message = get_message('error', 135)
                    # flag it support
                    searchForm = SearchFAQForm()
                    searchButton = {"buttonText": "Search"}

            except ObjectDoesNotExist:
                faqs = [
                    {
                        "question": "Ett fel har uppstått:",
                        "answer": message,
                    }
                ]
                searchForm = SearchFAQForm()
                searchButton = {"buttonText": "Search"}

            context = {
                'gdpr_check': gdpr_check,
                'search': False,
                'faqs': faqs,
                'searchForm': searchForm,
                "searchButton": searchButton,
            }
            return render(self.request, "faq.html", context)

# om_oss_view

class om_oss_view(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        context = {
            'gdpr_check': gdpr_check,
        }
        return render(self.request, "omoss.html", context)

    def post(self, *args, **kwargs):
        return redirect("core:omoss")

# teamet_view

class teamet_view(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)

        try:

            team_staff = TeamStaff.objects.all()
            people = []
            for ts in team_staff:
                if ts.active:
                    people.append(ts)

        except ObjectDoesNotExist:

            team_staff = [
                {
                    'image': "http://127.0.0.1:8000/media/media-root/89-896473_-strawberry-png-strawberry-clipart-strawberry-strawberry-clipart.png",
                    'name': "Mr Strawberry",
                    'position': "CEO",
                    'discription': "Dumtidumtidum",
                }
            ]

        context = {
            'gdpr_check': gdpr_check,
            "people": team_staff,
        }

        return render(self.request, "team.html", context)

    def post(self, *args, **kwargs):
        return redirect("core:team")

# vision_view

class vision_view(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        context = {
            'gdpr_check': gdpr_check,
        }
        return render(self.request, "vision.html", context)

    def post(self, *args, **kwargs):
        return redirect("core:vision")

# freight info

class freight_view(View):
    def get(self, *args, **kwargs):
        # GDPR check
        gdpr_check = check_gdpr_cookies(self)
        context = {
            'gdpr_check': gdpr_check,
        }
        return render(self.request, "freight.html", context)

    def post(self, *args, **kwargs):
        return redirect("core:freight")

class LogOutModView(LoginRequiredMixin, View):
    def get(self, *args, **kwargs):
        theUser = self.request.user
        orders = Order.objects.filter(who=theUser)
        for order in orders:
            order.who = None
            order.being_read = False
            order.save()
        logout(self.request)
        return redirect("core:home")

class SuccessView(View):
    def get(self, *args, **kwargs):
        gdpr_check = check_gdpr_cookies(self)
        theUser = self.request.user

        # get the content of the basket
        order = Order.objects.get(
            user=theUser, ordered=False)

        # update the order dates and set to ordered
        order.ordered = True
        order.ordered_date = make_aware(datetime.now())
        order.updated_date = make_aware(datetime.now())
        # to find this on the confirmation page set who to user
        order.who = theUser
        order.save()
        return redirect("core:confirmation")

class ConfirmationView(View):
    def get(self, *args, **kwargs):
        gdpr_check = check_gdpr_cookies(self)
        theUser = self.request.user

        # get the order

        order = Order.objects.get(who=theUser)
        # set who to null
        order.who = None
        order.save()

        # display confirmation

        context = {
            "gdpr_check": gdpr_check,
            "order": order,
        }

        return render(self.request, "success.html", context)

class CancelledView(View):
    def get(self, *args, **kwargs):
        # payment cancelled set message and redirect to basket
        message = "Betalning avbruten."
        messages.warning(
            self.request, message)
        return redirect("core:order-summary")

@csrf_exempt
def stripe_config(request):
    if request.method == 'GET':
        stripe_config = {'publicKey': settings.STRIPE_PUBLISHABLE_KEY}
        return JsonResponse(stripe_config, safe=False)

@csrf_exempt
def create_checkout_session(request):
    if request.method == 'GET':
        # FIX THIS ON UPLOAD
        domain_url = 'http://127.0.0.1:8000/'
        stripe.api_key = settings.STRIPE_SECRET_KEY
        # get the content of the basket
        theUser = request.user
        order = Order.objects.get(
            user=theUser, ordered=False)
        theUserInfo = UserInfo.objects.get(user=theUser)
        theName = "Orderreferens: " + order.ref_code
        # sent in öre
        theAmount = int(order.total_price * 100)
        try:
            # Create new Checkout Session for the order
            checkout_session = stripe.checkout.Session.create(

                client_reference_id=theUser.id if theUser.is_authenticated else None,
                customer_email=theUserInfo.email,
                success_url=domain_url +
                'success/',
                cancel_url=domain_url + 'cancelled/',
                payment_method_types=['card'],
                mode='payment',
                line_items=[
                    {
                        'name': theName,
                        'quantity': 1,
                        'currency': 'SEK',
                        'amount': theAmount,
                    }
                ]
            )
            return JsonResponse({'sessionId': checkout_session['id']})
        except Exception as e:
            return JsonResponse({'error': str(e)})

@csrf_exempt
def stripe_webhook(request):
    stripe.api_key = settings.STRIPE_SECRET_KEY
    endpoint_secret = settings.STRIPE_ENDPOINT_SECRET
    payload = request.body
    sig_header = request.META['HTTP_STRIPE_SIGNATURE']
    event = None

    try:
        event = stripe.Webhook.construct_event(
            payload, sig_header, endpoint_secret
        )
    except ValueError as e:
        # Invalid payload
        return HttpResponse(status=400)
    except stripe.error.SignatureVerificationError as e:
        # Invalid signature
        return HttpResponse(status=400)

    # Handle the checkout.session.completed event
    if event['type'] == 'checkout.session.completed':
        print("Payment was successful.")
        # TODO: run some custom code here

    return HttpResponse(status=200)

class ConfirmInfo(View):
    def get(self, *args, **kwargs):
        gdpr_check = check_gdpr_cookies(self)
        theUser = self.request.user

        # get the content of the basket
        order = Order.objects.get(
            user=self.request.user, ordered=False)

        context = {
            "gdpr_check": gdpr_check,
            "order": order,
        }

        return render(self.request, "confirmInfo.html", context)


from django.shortcuts import render
from django.http import HttpResponseRedirect, JsonResponse
from django.shortcuts import render_to_response
from django.core.urlresolvers import reverse

from CrawlerManagement.models import Company
from .forms import UploadFileForm
from business.data import CsvLoader
from business.web import WebsiteLocator

# Create your views here.

def index(request):
    companies = Company.objects.order_by('-Name')[:10]
    form = UploadFileForm()
    context = {'companies': companies, 'uploadForm': form}
    return render(request, 'index.html', context)

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            try:
                handle_uploaded_file(request.FILES['file'])
            except Exception as ex:
                return render_to_response('index.html', {'form': form, 'exception': ex.message})
            else:
                return HttpResponseRedirect(reverse('index'))
    else:
        form = UploadFileForm()
    return render_to_response('index.html', {'form': form})

def handle_uploaded_file(f):
    loader = CsvLoader()
    loader.handle_uploaded_file(f)

def find_company_website(request, company_ref):
    locator = WebsiteLocator()
    try:
        company_url_response = locator.find_website(company_ref)
        return JsonResponse(company_url_response)
    except Exception as ex:
        return JsonResponse({"success": False, "message": ex.message})

def find_company_links(request):
    company_url = request.GET.get('url')
    if not company_url:
        company_url = request.POST.get('url')
    locator = WebsiteLocator()
    try:
        company_url_response = locator.find_website_links(company_url)
        json_resp = company_url_response.to_json_dict()
        return JsonResponse(json_resp)
    except Exception as ex:
        return JsonResponse({"success": False, "message":ex.message})


from datetime import datetime
import os
import platform
import socket
from colorama import Back, Fore, Style
from .login import login

formatOptions = {
    "$T1": f"{Fore.RESET}",
    "$T2": f"{Fore.GREEN}",
    "$T3": f"{Fore.CYAN}",
    "$T4": f"{Fore.BLUE}",
    "$T5": f"{Fore.BLACK}",
    "$T6": f"{Fore.RED}",
    "$T7": f"{Fore.YELLOW}",
    "$T8": f"{Fore.MAGENTA}",
    "$T9": f"{Fore.WHITE}",
    "$R1": f"{Back.RESET}",
    "$R2": f"{Back.GREEN}",
    "$R3": f"{Back.CYAN}",
    "$R4": f"{Back.BLUE}",
    "$R5": f"{Back.BLACK}",
    "$R6": f"{Back.RED}",
    "$R7": f"{Back.YELLOW}",
    "$R8": f"{Back.MAGENTA}",
    "$R9": f"{Back.WHITE}",
    "$U1": f"{Style.NORMAL}",
    "$U2": f"{Style.BRIGHT}",
    "$U3": f"{Style.DIM}",
    "$U4": f"{Style.RESET_ALL}",
    "$_": "\n",
    "$$": "$",
    "$A": "&",
    "$B": "|",
    "$CH0": "(",
    "$D": datetime.now().strftime("%D"),
    "$F": ")",
    "$G": ">",
    "$H": "~",
    "$I": login(),
    "$J": socket.gethostname(),
    "$L": "<",
    "$N": f"{os.getcwd().split(':')[0]}",
    "$M": f"{os.getcwd()}",
    "$O": "/{0}/".format(os.getcwd().replace("\\", "/").split("/")[-1]),
    "$P": "=",
    "$Q": " ",
    "$S": datetime.now().strftime("%T"),
    "$V": f"{platform.version()}",
    "$CH1": "§",
    "$CH2": "✓",
    "$CH3": "✕",
    "$CH4": "⋆",
    "$CH5": "✶",
    "$CH6": "⌥",
    "$CH7": "⌘",
    "$CH8": "⏻",
    "$CH9": "⏼",
    "$CR1": "⎞",
    "$CR2": "⎜",
    "$CR3": "⎝",
    "$CR4": "⎛",
    "$CR5": "⎟",
    "$CR6": "⎠",
    "$CR7": "⭘",
    "$CR8": "⋯",
    "$CR9": "⊸",
}

def update():
    formatOptions.update({
        "$N": f"{os.getcwd().split(':')[0]}",
        "$M": f"{os.getcwd()}",
        "$O": "/{0}/".format(os.getcwd().replace("\\", "/").split("/")[-1]),
        "$S": datetime.now().strftime("%T"),
        "$V": f"{platform.version()}",
    })

def formatStr(string:str) -> str:
    for a,b in formatOptions.items():
        string=string.replace(a,b);
    return string;


from lxml import etree
import struct
import re
import hashlib
import base64

from .crypto import RSAHandler

from cryptography.hazmat.primitives.asymmetric import padding, utils
from cryptography.hazmat.primitives import hashes

BEGIN_ELEMENT=1
END_ATTRIBUTES=2
END_ELEMENT=3
TEXT_NODE=4
ATTRIBUTE=5

ADEPT_NS="http://ns.adobe.com/adept"
NSMAP = {None: ADEPT_NS}

def add_byte(o, i):
  o = o + struct.pack('B', i);
  return o

def add_str(o, s):
  es = s.encode("utf-8")
  o = o + struct.pack('>H', len(es))
  o = o + es
  return o

def parse_namespace(tag, default_ns):
  m = re.match("{(.*)}(.*)", tag)
  if m is not None:
    return m.group(2), m.group(1)
  else:
    return tag, default_ns

def serialize(node):
  out = bytes()
  name, ns = parse_namespace(node.tag, ADEPT_NS)
  if name in ["hmac", "signature"]:
    return b""
  out = add_byte(out, BEGIN_ELEMENT)
  out = add_str(out, ns)
  out = add_str(out, name)
  for attr_name in sorted(node.attrib.keys()):
    out = add_byte(out, ATTRIBUTE)
    out = add_str(out, "")
    out = add_str(out, attr_name)
    out = add_str(out, str(node.attrib[attr_name]))
  out = add_byte(out, END_ATTRIBUTES)
  for child in node:
    out = out + serialize(child)
  # In ActionScript, the text field is a child
  # Here it should work because the XML has either children or text
  if node.text is not None and node.text.strip() != "":
    out = add_byte(out, TEXT_NODE)
    out = add_str(out, node.text.strip())
  out = add_byte(out, END_ELEMENT)
  return out

def xml_hash(s):
  h = hashlib.sha1()
  h.update(s)
  d = h.hexdigest()
  # Force big endian
  return b"".join(struct.pack('>I', int(d[i*8:i*8+8], 16)) for i in range(5))

# key as byte array
def encrypt(hxml, key):
  rsa = RSAHandler(key)
  sig = rsa.encrypt(hxml)

  return sig

def generate_signature(xml_str, key):
  xml = etree.fromstring(xml_str)
  # First normalize and serialize the XML
  sxml = serialize(xml)
  # Compute the sha1
  hxml = xml_hash(sxml)
  # Encrypt it with private key
  sig = encrypt(hxml, key)
  return base64.b64encode(sig)

def sign_xml(element, pk):
  xml_str = etree.tostring(element)

  signature = etree.Element("signature")
  signature.text = generate_signature(xml_str, pk)
  element.append(signature)

  return element

def add_subelement(element, name, text):
  e = etree.Element(name)
  e.text = text
  element.append(e)
  return e

def get_error(xml):
  tree_root = etree.fromstring(xml)
  if 'error' in tree_root.tag:
    return tree_root.get('data')
  return None


# coding=utf-8
from django.test import TestCase

from core.tests.fixtures import UserFactory
from ..models import Client, Task
from .fixtures import ClientFactory, TaskFactory

class ClientModelTestCase(TestCase):
    def test_get_qs(self):
        client = ClientFactory()

        administrator_user = UserFactory()
        self.assertEqual(Client.objects.get_qs(administrator_user).count(), Client.objects.all().count())

        moderator_user = client.moderator.user
        client_qs = Client.objects.get_qs(moderator_user)
        for clnt in client_qs:
            self.assertEqual(clnt.moderator, client.moderator)

        manager_user = client.manager.user
        client_qs = Client.objects.get_qs(manager_user)
        for clnt in client_qs:
            self.assertEqual(clnt.manager, client.manager)

class TaskModelTestCase(TestCase):
    def test_get_qs(self):
        task = TaskFactory()

        administrator_user = UserFactory()
        self.assertEqual(Task.objects.get_qs(administrator_user).count(), Task.objects.all().count())

        moderator_user = task.client.moderator.user
        task_qs = Task.objects.get_qs(moderator_user)
        for tsk in task_qs:
            self.assertEqual(tsk.manager.moderator, moderator_user)

        manager_user = task.client.manager.user
        task_qs = Task.objects.get_qs(manager_user)
        for tsk in task_qs:
            self.assertEqual(tsk.manager, task.manager)

        manager_user.leader = True
        manager_user.save()
        task_qs = Task.objects.get_qs(manager_user)
        for tsk in task_qs:
            self.assertEqual(tsk.manager.moderator, task.manager.moderator)


import math
import random

from pygame.color import Color
from pygame.surface import Surface

from rectangle import Rectangle
from vector2 import Vector2

class Ball:
    bounds: Rectangle
    velocity: Vector2
    speed: float

    def __init__(self):
        self.bounds = Rectangle(width=25, height=25)
        self.velocity = Vector2()
        self.speed = 500

    def reset(self, width, height):
        self.bounds.x = (width * 0.5) - (self.bounds.width * 0.5)
        self.bounds.y = (height * 0.5) - (self.bounds.height * 0.5)
        radians = random.random() * (math.pi * 2)
        self.velocity.x = self.speed * math.cos(radians)
        self.velocity.y = self.speed * math.sin(radians)

    def update(self, screen_width, screen_height, delta_time):
        self.bounds.add_vector2_to_pos(self.velocity, delta_time)
        if self.bounds.y < 0:
            self.bounds.y = 0
            self.bounce_y()
        if self.bounds.y + self.bounds.height > screen_height:
            self.bounds.y = screen_height - self.bounds.height
            self.bounce_y()

    def bounce_x(self):
        self.velocity.x *= -1

    def bounce_y(self):
        self.velocity.y *= -1

    def collide_left(self, left_rect: Rectangle):
        if self.bounds.overlaps(left_rect):
            self.bounds.x = left_rect.x + left_rect.width
            self.bounce_x()

    def collide_right(self, right_rect: Rectangle):
        if self.bounds.overlaps(right_rect):
            self.bounds.x = right_rect.x - self.bounds.width
            self.bounce_x()

    def display(self, surface: Surface, color: Color):
        self.bounds.display(surface, color)


from __future__ import annotations

import pathlib
import typing as t

import attr
import pint
import pinttr
import xarray as xr

import eradiate

from ._core import RadProfile, make_dataset, rad_profile_factory
from .. import validators
from .._presolver import path_resolver
from ..attrs import documented, parse_docs
from ..exceptions import UnsupportedModeError
from ..units import to_quantity
from ..units import unit_context_config as ucc
from ..units import unit_registry as ureg

@rad_profile_factory.register(type_id="array")
@parse_docs
@attr.s
class ArrayRadProfile(RadProfile):
    """
    A flexible 1D radiative property profile whose level altitudes, albedo
    and extinction coefficient are specified as numpy arrays.
    """

    levels: pint.Quantity = documented(
        pinttr.ib(units=ucc.deferred("length")),
        doc="Level altitudes. **Required, no default**.\n"
        "\n"
        "Unit-enabled field (default: ucc['length']).",
        type="array",
    )

    albedo_values: pint.Quantity = documented(
        pinttr.ib(
            validator=[validators.all_positive, pinttr.validators.has_compatible_units],
            units=ureg.dimensionless,
        ),
        doc="An array specifying albedo values. **Required, no default**.\n"
        "\n"
        "Unit-enabled field (dimensionless).",
        type="array",
    )

    sigma_t_values: pint.Quantity = documented(
        pinttr.ib(
            validator=[validators.all_positive, pinttr.validators.has_compatible_units],
            units=ucc.deferred("collision_coefficient"),
        ),
        doc="An array specifying extinction coefficient values. **Required, no "
        "default**.\n"
        "\n"
        "Unit-enabled field (default: ucc['collision_coefficient']).",
        type="array",
    )

    @albedo_values.validator
    @sigma_t_values.validator
    def _validator_values(instance, attribute, value):
        if value.ndim != 1:
            raise ValueError(
                f"while setting {attribute.name}: "
                f"must have 1 dimension only "
                f"(got shape {value.shape})"
            )

        if instance.albedo_values.shape != instance.sigma_t_values.shape:
            raise ValueError(
                f"while setting {attribute.name}: "
                f"'albedo_values' and 'sigma_t_values' must have "
                f"the same length"
            )

    def __attrs_pre_init__(self):
        if not eradiate.mode().is_mono:
            raise UnsupportedModeError(supported="monochromatic")

    def eval_albedo_mono(self, w: pint.Quantity) -> pint.Quantity:
        return self.albedo_values

    def eval_sigma_t_mono(self, w: pint.Quantity) -> pint.Quantity:
        return self.sigma_t_values

    def eval_sigma_a_mono(self, w: pint.Quantity) -> pint.Quantity:
        return self.eval_sigma_t_mono(w) * (1.0 - self.eval_albedo_mono(w))

    def eval_sigma_s_mono(self, w: pint.Quantity) -> pint.Quantity:
        return self.eval_sigma_t_mono(w) * self.eval_albedo_mono(w)

    def eval_dataset_mono(self, w: pint.Quantity) -> xr.Dataset:
        return make_dataset(
            wavelength=w,
            z_level=self.levels,
            sigma_t=self.eval_sigma_t_mono(w),
            albedo=self.eval_albedo_mono(w),
        ).squeeze()

    @classmethod
    def from_dataset(cls, path: t.Union[str, pathlib.Path]) -> ArrayRadProfile:
        with xr.open_dataset(path_resolver.resolve(path)) as ds:
            z_level = to_quantity(ds.z_level)
            albedo = to_quantity(ds.albedo)
            sigma_t = to_quantity(ds.sigma_t)
        return cls(albedo_values=albedo, sigma_t_values=sigma_t, levels=z_level)


from setuptools import find_packages, setup

with open('README.md', 'r', encoding='utf-8') as fh:
    long_description = fh.read()

setup(
    name='py-mapper',
    version='1.1.0a',
    author='Felipe Endlich',
    author_email='endlichfelipe@gmail.com',
    description='Python mapper library',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='https://github.com/endlichfelipe/py-mapper',
    classifiers=[
        'Development Status :: 3 - Alpha',
        'Intended Audience :: Developers',
        'Topic :: Software Development :: Libraries',
        'Operating System :: OS Independent',
        'License :: OSI Approved :: MIT License',
        'Programming Language :: Python :: 3'
    ],
    package_dir={"": "src"},
    packages=find_packages(where='src'),
    python_requires='>=3.6',
    keywords=['MAPPER'],
    license='MIT',
    install_requires=[]
)


"""pixelsapi URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path, include
from rest_framework_simplejwt.views import (
    TokenRefreshView,
)

from pixelsapi.views import MyObtainTokenPairView, LogoutView, SignupViewSet

urlpatterns = [
    path('canvas/', include('canvas.urls')),
    path('contact/', include('contact.urls')),
    path('admin/', admin.site.urls),
    path('token/', MyObtainTokenPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
    path('logout/', LogoutView.as_view(), name='auth_logout'),
    path('register/', SignupViewSet.as_view({'post': 'create'}), name='register')
]


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Tue Jun 12 17:09:30 2018

@author: abauville
"""
#import sys
#sys.path.insert(0, '../../src/UserInput')
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
import numpy as np
import OutputDef as Output

def get_XYandPattern(dataFolder,lc=2.0e3,sampleRate=1, nLayersX = 0, nLayersY=7,minStrain=0.1,maxStrain=5.0,xmin = 'auto',xmax = 'auto',ymin='auto',ymax='auto', mainDir='x'):
    ## Load and subsample
    # ================================
    PartX  = Output.getParticleData(dataFolder + 'particles_x.bin',True).data[0::sampleRate]/lc
    PartY  = Output.getParticleData(dataFolder + 'particles_y.bin',True).data[0::sampleRate]/lc
    PartXIni  = Output.getParticleData(dataFolder + 'particles_xIni.bin',True).data[0::sampleRate]/lc
    PartYIni  = Output.getParticleData(dataFolder + 'particles_yIni.bin',True).data[0::sampleRate]/lc

    PartStrain  = Output.getParticleData(dataFolder + 'particles_strain.bin',True).data[0::sampleRate]

    if xmin=='auto':
        xmin = np.min(PartX)
    if xmax=='auto':
        xmax = np.max(PartX)
    if ymin=='auto':
        ymin = np.min(PartY)
    if ymax=='auto':
        ymax = np.max(PartY)

    ## Geometrical pattern
    # ================================
#    nLayersY = 7
#    nLayersX = 16
#    xmax = 0.0
#    xmin = -32.0#np.min(PartXIni)

    if mainDir == 'x':
        if nLayersX > 0:
            YPattern = PartYIni
            YPattern -= ymin
            YPattern /= ymax-ymin
    #        YPattern = np.cos(PartYIni*1.0*np.pi*nLayersY+np.pi/2.0)
            YPattern = np.cos(YPattern*1.0*np.pi*nLayersY+np.pi/2.0)
            maxVal= np.max(YPattern)
            YPattern = np.round((YPattern+maxVal)/(2.0*maxVal))

            nColors = nLayersX

            XPattern = PartXIni
#            XPattern -= xmin
            XPattern /= xmax-xmin

            PartPattern= 4.0*np.floor(-XPattern * (nLayersX) )
    #

#
            PartPattern+= 2.0*YPattern
            PartPattern = PartPattern%(4*nLayersX)

        else:
            PartPattern = np.zeros(PartStrain.shape)
            nColors = 1
    elif mainDir=='y':
        if nLayersY>0:
            PartPattern = np.ones(PartStrain.shape)
            nColors = nLayersY

            if nLayersX<=1:
                nLayersX=0

            XPattern = PartXIni
            XPattern -= xmin
            XPattern /= xmax-xmin
            XPattern = np.cos(PartXIni*1.0*np.pi*nLayersX+np.pi/2.0)
            maxVal= np.max(XPattern)

            if nLayersX>1:
                XPattern = np.round((XPattern+maxVal)/(2.0*maxVal))
            else:
                XPattern = np.round((XPattern)/(2.0*maxVal))
#            XPattern = np.round((XPattern)/(2.0*maxVal))
#

            YPattern = PartYIni
            YPattern /= ymax-ymin
#            YPattern = -YPattern

#            YPattern[YPattern>0.95] = 6.0
#            nColors = 6

            PartPattern= 4.0*np.floor(YPattern * (nLayersY) )
            PartPattern+= 2.0*XPattern
            PartPattern = PartPattern%(4*nLayersY)

        else:
            PartPattern = np.zeros(PartStrain.shape)
            nColors = 1
    else:
        raise ValueError("mainDir can take the values 'x' or 'y' only.")

    ## Strain pattern
    # ================================
    PartStrain -= minStrain
    PartStrain[PartStrain<0.0] = 0.0
    PartStrain /= maxStrain-minStrain

    PartStrainLogical = PartStrain>1.0
    PartStrain[PartStrainLogical] = 1.0

    PartPattern += PartStrain

    return (PartX, PartY, PartPattern, nColors)

def getColormap(nColors,name='KellyMod_Layers_Strain',renderer=0,CMAP=np.array([]),
                darknessFactor=[1.0,0.0,0.5,0.0],
                RGBShift = [[0.0,0.0,0.0], # Main color
                            [0.0,0.0,0.0], # Main Color strain
                            [0.0,0.0,0.0], # Minor Color
                            [0.0,0.0,0.0]], # Minor Color strain
                ):
    # Darkness Factor is applied before RGB shift

    ## Kenneth Kelly's 22 colour of maximum contrast
#    nColors  = 22

    if type(CMAP) is list:
        CMAP=np.array(CMAP)

    if (CMAP.size==0):
        if nColors>22:
            raise ValueError("error: nColors should not exceed 22")
        condensedCMAPtemp = np.zeros((nColors,4))
        for i in range (nColors):
            if i ==  0: condensedCMAPtemp[ i,:] = [242, 243, 244, 255]
            if i ==  1: condensedCMAPtemp[ i,:] = [ 34,  34,  34, 255]
            if i ==  2: condensedCMAPtemp[ i,:] = [243, 195,   0, 255]
            if i ==  3: condensedCMAPtemp[ i,:] = [135,  86, 146,255]
            if i ==  4: condensedCMAPtemp[ i,:] = [243, 132,   0,255]
            if i ==  5: condensedCMAPtemp[ i,:] = [161, 202, 241,255]
            if i ==  6: condensedCMAPtemp[ i,:] = [190,   0,  50,255]
    #        if i ==  7: condensedCMAPtemp[ i,:] = [194, 178, 128,255]
            if i ==  7: condensedCMAPtemp[ i,:] = [ 50, 178, 128,255]
    #        if i ==  8: condensedCMAPtemp[ i,:] = [132, 132, 130,255]
            if i ==  8: condensedCMAPtemp[ i,:] = [162,  80, 200,255]
            if i ==  9: condensedCMAPtemp[ i,:] = [  0, 136,  86,255]
            if i == 10: condensedCMAPtemp[ i,:] = [230, 143, 172,255]
            if i == 11: condensedCMAPtemp[ i,:] = [  0, 103, 165,255]
            if i == 12: condensedCMAPtemp[ i,:] = [249, 147, 121,255]
            if i == 13: condensedCMAPtemp[ i,:] = [ 96,  78, 151,255]
            if i == 14: condensedCMAPtemp[ i,:] = [246, 166,   0,255]
            if i == 15: condensedCMAPtemp[ i,:] = [179,  68, 108,255]
            if i == 16: condensedCMAPtemp[ i,:] = [220, 211,   0,255]
            if i == 17: condensedCMAPtemp[ i,:] = [136,  45,  23,255]
            if i == 18: condensedCMAPtemp[ i,:] = [141, 182,   0,255]
            if i == 19: condensedCMAPtemp[ i,:] = [101,  69,  34,255]
            if i == 20: condensedCMAPtemp[ i,:] = [226,  88,  34,255]
            if i == 21: condensedCMAPtemp[ i,:] = [ 43,  61,  38,255]

        condensedCMAPtemp /= 255.0
        #CMAP = LinearSegmentedColormap.from_list('Kelly',condensedCMAPtemp)
        #plt.register_cmap(cmap=CMAP)

        condensedCMAPtemp[:,0:2] *= .5
        condensedCMAPtemp[:,0:2] += .1
#        condensedCMAPtemp[:,0  ] += .4
#        condensedCMAPtemp[:,1  ] += .35

#        condensedCMAPtemp[:,0:3] *= 0
#        condensedCMAPtemp[:,0:3] += 1.0
#        condensedCMAPtemp = np.ones((nColors,4))
        condensedCMAPtemp[:,0  ] += .4
        condensedCMAPtemp[:,1  ] += .35

#

    else:
        try:
            if (CMAP.shape[1]!=4):
                raise ValueError("error in getColormap: CMAP must have dimensions nColors*4");
        except IndexError: # Occurs if CMAP contains only one color CMAP.shape = (4,)
            if (CMAP.shape[0]!=4):
                raise ValueError("error in getColormap: CMAP must have dimensions nColors*4");
        nColors = CMAP.shape[0]
        condensedCMAPtemp = CMAP

    condensedCMAPtemp[condensedCMAPtemp>1.0] = 1.0
    condensedCMAPtemp[condensedCMAPtemp<0.0] = 0.0

    condensedCMAP = np.zeros((4*nColors,4))
    for i in range(4):
        if i%2==0:
            condensedCMAP[i::4,:] = condensedCMAPtemp*darknessFactor[i] #* 0.4 + .3
        else:
            condensedCMAP[i::4,:] = condensedCMAP[i-1::4,:]*darknessFactor[i] #* 0.4 + .3

        condensedCMAP[i::4,0] += RGBShift[i][0]  # Shift Red
        condensedCMAP[i::4,1] += RGBShift[i][1]  # Shift Green
        condensedCMAP[i::4,2] += RGBShift[i][2]  # Shift Blue

    condensedCMAP[condensedCMAP>1.0] = 1.0
    condensedCMAP[condensedCMAP<0.0] = 0.0
    condensedCMAP[:,-1] = 1.0
#    nColors = condensedCMAP.shape[0]

    if renderer == 0: # renderer is Matplotlib
        res = 12
        CMAP = LinearSegmentedColormap.from_list(name,condensedCMAP,N=res*4*nColors-(res-1))
        return CMAP
        #plt.register_cmap(cmap=CMAP)

    if renderer == 1: # renderer is Mayavi
        CMAP = np.zeros((255,4))

        n = condensedCMAP.shape[0]
        for i in range(n-1):
            iS = int(round(255 *  i/(n-1) ))
            iE = int(round(255 * (i+1)/(n-1)))
            for j in range(4):
                CMAP[iS:iE,j] = np.linspace(condensedCMAP[i,j],condensedCMAP[i+1,j],int(iE-iS))

        CMAP = (CMAP*255.0).astype("uint8")
        return CMAP