import scrapy
from scrapy.exceptions import CloseSpider
from scrapy.crawler import CrawlerProcess

class PDFSpider(scrapy.Spider):
    name = "pdf_spider"
    start_urls = [
        # List of universities / websites to scrape
    ]

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.total_universities = len(self.start_urls)
        self.scraped_universities = 0

    custom_settings = {
        'DEPTH_LIMIT': 3,  # Set the depth limit of the spider
        'USER_AGENT': 'Mozilla/5.0 (Windows NT 10.0; Win64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36',
        'FEED_URI': 'output.json',  # Specify the output file
        'FEED_FORMAT': 'json',  # Output format
    }

    def parse(self, response):
        # Find and save all the PDF links on the current page
        for link in response.css('a::attr(href)').getall():
            if link.endswith('.pdf'):
                yield {
                    'pdf_link': response.urljoin(link)
                }

        # Follow all the links on the current page
        for href in response.css('a::attr(href)'):
            yield response.follow(href, self.parse)

        # Increment the scraped universities count
        self.scraped_universities += 1

        # Check if all universities have been scraped
        if self.scraped_universities == self.total_universities:
            raise CloseSpider('All universities scraped')

if __name__ == "__main__":
    process = CrawlerProcess()
    process.crawl(PDFSpider)
    process.start()
    input("Press Enter to exit...")


from math import gcd, atan2, sqrt, pi

IMS = (26, 29)   # calculated in 10_1.py

examples = {"simple1.txt": (3, 4, 8),
            "simple2.txt": (5, 8, 33),
            "simple3.txt": (1, 2, 35),
            "simple4.txt": (6, 3, 41),
            "simple5.txt": (11, 12, 210)}

infile = "input.txt"

# def vadd(v1, v2):
#     return((v1[0] + v2[0], v1[1] + v2[1]))
def dist(v1, v2):
    return sqrt((v2[0] - v1[0])**2 + (v2[1] - v1[1])**2)

raw_rows = []
f = open("/home/richard/python/advent-of-code/10/" + infile)
for r in f:
    raw_rows.append(list(r.strip()))
f.close()

height = len(raw_rows)
width = len(raw_rows[0])

asteroids = set()
for i in range(width):
    for j in range(height):
        if raw_rows[j][i] == "#":
            asteroids.add((i,j))
        elif raw_rows[j][i] == "X":
            IMS = (i,j)

angles = {}

# construct angles database
for a in asteroids:
    if a == IMS:
        continue
    angle = atan2(a[0] - IMS[0] , IMS[1] - a[1])     # this seems to be right
    if angle < 0:
        angle += 2*pi

    if angle not in angles:
        angles[angle] = [a]
    else:
        # insert asteroid a into angles[angle] reverse-sorted by distance
        d1 = dist(a, IMS)
        inserted = False
        for i in range(len(angles[angle])):
            if d1 > dist(IMS, angles[angle][i]):
                angles[angle].insert(i, a)
                inserted = True
                break
        if not inserted:
            angles[angle].append(a)

# delete asteroids cycling angles until 200 deleted
print(len(angles), "asteroids, IMS =", IMS)

anglelist = sorted(list(angles))
for a in anglelist:
    x = str(round(a,3))
    print (x + "00"[:5 - len(x)], ":", angles[a])

numdeleted = 0
i = 0

while numdeleted <= len(asteroids):
    angle = anglelist[i]

    if angles[angle] != []:
        cur = angles[angle].pop()
        numdeleted += 1
        if numdeleted == 200:
            print(f"Deletion {numdeleted}: {cur}")

    if i >= len(angles) - 1:
        i = 0
    else:
        i += 1


from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from apps.trayectos.models import Trayecto
from apps.trayectos.api.serializers import TrayectoListSerializer, TrayectoSerializer
from .permissions import IsAdminUserCustom

@api_view(['GET', 'POST'])
@permission_classes((IsAdminUserCustom, ))
def trayecto_api_view(request):
    if request.method == 'GET':
        # queryset
        trayectos = Trayecto.objects.all()
        trayectos_serializer = TrayectoListSerializer(trayectos, many=True)
        return Response(trayectos_serializer.data, status=status.HTTP_200_OK)

    elif request.method == 'POST':
        trayecto_serializer = TrayectoSerializer(data=request.data)
        if trayecto_serializer.is_valid():
            trayecto_serializer.save()
            return Response({'message': 'Trayecto creado correctamente!'}, status=status.HTTP_201_CREATED)
        return Response(trayecto_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET', 'PUT', 'DELETE'])
@permission_classes((IsAdminUserCustom, ))
def trayecto_detail_api_view(request, id=None):
    # queryset
    trayecto = Trayecto.objects.filter(id=id).first()

    # validation
    if trayecto:

        # retrieve
        if request.method == 'GET':
            trayecto_serializer = TrayectoListSerializer(trayecto)
            return Response(trayecto_serializer.data, status=status.HTTP_200_OK)

        # update
        elif request.method == 'PUT':
            trayecto_serializer = TrayectoSerializer(
                trayecto, data=request.data)
            if trayecto_serializer.is_valid():
                trayecto_serializer.save()
                return Response(trayecto_serializer.data, status=status.HTTP_200_OK)
            return Response(trayecto_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

        # delete
        elif request.method == 'DELETE':
            trayecto.delete()
            return Response({'message': 'Trayecto eliminado correctamente!'}, status=status.HTTP_200_OK)

    return Response({'message': 'No se ha encontrado un trayecto con estos datos'}, status=status.HTTP_400_BAD_REQUEST)


"""
Solution for Algorithms #38: Count and Say

Runtime: 40 ms, faster than 86.78% of Python3 online submissions for Count and Say.
Memory Usage: 13.2 MB, less than 42.67% of Python3 online submissions for Count and Say.
"""
class Solution:
    def count_and_say_seq(self, seq):
        new_seq = ''
        count = 0
        for i in range(len(seq)-1):
            if seq[i] == seq[i+1]:
                count += 1
            else:
                new_seq += '{}{}'.format(count + 1, seq[i])
                count = 0

        new_seq += '{}{}'.format(count + 1, seq[-1])

        return new_seq

    def countAndSay(self, n: int) -> str:
        seq = '1'
        for _ in range(n-1):
            seq = self.count_and_say_seq(seq)

        return seq