#!/usr/bin/python
# -*- coding: utf-8 -*-
# Задание класса комната, где атрибутами являютс: имя комнаты,
# и ее координаты на карте x и y.

# Что такое аргумент self?
# Классам нужен способ, что ссылаться на самих себя.
# Это способ сообщения между экземплярами. Слово self это способ
# описания любого объекта, буквально

class Room(object):
    def __init__(self, name, x, y):
        self.name = name
        self.x = x
        self.y = y

# Pass - оператор-заглушка, равноценный отсутствию операции.
# В ходе исполнения данного оператора ничего не происходит,
# поэтому он может использоваться в качестве заглушки в тех
# местах, где это синтаксически необходимо, например:
# в инструкциях, где тело является обязательным, таких
# как def, except и пр.
#
# Зачастую pass используется там, где код пока ещё не появился,
# но планируется. Кроме этого, иногда, его используют при
# отладке, разместив на строчке с ним точку остановки.

class Ant(Room):
    pass

# Создание класса фермы. В квадратных скобках (списки - в
# Python отсутствуют массивы в традиционном понимании этого
# термина. Вместо них для хранения однородных (и не только)
# объектов используются списки)
# В фигурных скобках (Словарь – изменяемая структура данных,
# предназначенная для хранения пары -> ключ: значение)
# a = {'cat': 'кошка', 'dog': 'собака'}
# a['cat'] -> 'кошка'

class Farm:
    def __init__(self):
        #количество муравьев с карты
        self.ant_num = 0
        self.ants = []
        self.ants_copy = []
        self.rooms = []
        self.start_room = None
        self.end_room = None
        self.i = 0
        self.room_index = {}
        self.links = []

# Метод добавления комнаты
#
# Метод Python split() разбивает строку на части, используя
# специальный разделитель, и возвращает эти части в виде списка
#
# В методе split() используется не более двух параметров:
# разделитель (необязательный параметр) – строка разбивается
# на части с помощью указанного символа. Если разделитель не
# задан, то любая пробельная строка (пробел, новая строка и
# т.д.) считается разделителем;
# maxsplit (необязательный параметр) определяет максимальное
# количество частей.

    def add_room(self, line, status):
        name, x, y = line.split(' ')

# Добавление элемента в список осуществляется с помощью
# метода append().
        self.rooms.append(Room(name, int(x), int(y)))

# Задаем ключи для имён комнаты (соответстиве name <-> i)
        self.room_index[name] = self.i
# Если start записано в status, то записываем в start_room
# текущий индекс
        if (status == "start"):
            self.start_room = self.i
# Если end записано в status, то записываем в end_room
# текущий индекс
        if (status == "end"):
            self.end_room = self.i
        self.i += 1

# Добавление связей между комнатами. Делим линию с помощью
# метода split с разделителем '-' и добавляем полученные
# элементы в список c помощью метода append()

    def add_link(self, line):
        temp = line.split('-')
        self.links.append((temp[0], temp[1]))

# Получаем значения координат х и у комнат, по их именам

    def get_xy_by_name(self, name):
        index = self.room_index[name]
        x = self.rooms[index].x
        y = self.rooms[index].y
        return (x, y)

# Создаем муравьев с помощью функции range(начало, конец, шаг)
# Различные типы могут быть приведены к строке при
# помощи конструктора str(): str(10) -> '10'
# Добавляем в списовк муравьев с помощью метода append()

    def create_ants(self):
        for i in range(1, self.ant_num + 1):
            ant = Ant(str(i), self.rooms[self.start_room].x,
                      self.rooms[self.start_room].y)
            self.ants.append(ant)

# Движение муравьев

    def move_ants(self, steps):
        for step in steps:
            i = step[0]
            x = step[1]
            y = step[2]
            self.ants[i].x = x
            self.ants[i].y = y

    def __get_substeps(self, move):
        move = move.strip('L')
        move = move.split('-')
        i = int(move[0]) - 1
        curr_room = (self.ants_copy[i].x, self.ants_copy[i].y)
        next_room = self.get_xy_by_name(move[1])
        temp = []
        s = 10
        dx = (next_room[0] - curr_room[0]) / float(s)
        dy = (next_room[1] - curr_room[1]) / float(s)
        for x in range(s + 1):
            step = []
            step.append(i)
            step.append(curr_room[0] + dx * x)
            step.append(curr_room[1] + dy * x)
            temp.append(step)
        self.ants_copy[i].x, self.ants_copy[i].y = next_room
        return (temp)

# Вычисление шагов. Создается пустой список steps. Движения
# записываются из с помощью метода split() с пробелом в
# качестве разделдителя. Шаги

    def compute_steps(self, moves):
        steps = []
        moves = moves.split(' ')
        steps = [self.__get_substeps(move) for move in moves]
        res = []
        for i in range(len(steps[0])):
            temp = []
            for step in steps:
                temp.append(step[i])
            res.append(tuple(temp))
        return (res)


from django.urls import path
from . import views
app_name='toolapp'
urlpatterns = [
   path('',views.index,name='index'),
   path('tool/<int:tools_id>/',views.detail,name='detail'),
   path('add/',views.add_tool,name='add_tool'),
   path('update/<int:id>/',views.update,name='update'),
   path('delete/<int:id>/', views.delete, name='delete'),
]


from __future__ import absolute_import
from collections import OrderedDict
import six
from django.http import HttpResponse

from .constants import *  # noqa
from .route_decorators import *  # noqa
from ..api import ResourceApiCommon
from ..exceptions import ImmediateErrorHttpResponse

class ResourceApiBase(type):
    def __new__(mcs, name, bases, attrs):
        super_new = super(ResourceApiBase, mcs).__new__

        # attrs will never be empty for classes declared in the standard way
        # (ie. with the `class` keyword). This is quite robust.
        if name == 'NewBase' and attrs == {}:
            return super_new(mcs, name, bases, attrs)

        parents = [
            b for b in bases
            if isinstance(b, ResourceApiBase) and not (b.__name__ == 'NewBase' and b.__mro__ == (b, object))
        ]
        if not parents:
            # If this isn't a subclass of don't do anything special.
            return super_new(mcs, name, bases, attrs)

        routes = []

        # Get local routes and sort them by route number
        for view, obj in attrs.items():
            if callable(obj) and hasattr(obj, 'route'):
                route_number, path_type, method, action_name = obj.route
                routes.append((route_number, path_type, method, action_name, view))
                delattr(obj, 'route')
        routes = sorted(routes, key=lambda o: o[0])

        # Get routes from parent objects
        for parent in parents:
            if hasattr(parent, 'routes'):
                routes.extend(parent.routes)

        attrs['routes'] = routes

        return super_new(mcs, name, bases, attrs)

@six.add_metaclass(ResourceApiBase)
class ResourceApi(ResourceApiCommon):
    """
    Base class for version 2 of the Resource API.

    The API now uses a meta class to extract routes from methods that have
    been decorated with route information.

    """
    # Table containing lookup information to simplify dispatch of incoming
    # requests to the appropriate views
    route_table = None

    # Respond to the options method.
    respond_to_options = True

    def base_urls(self):
        url_table = OrderedDict()
        route_table = {}
        for route_ in self.routes:
            route_number, path_type, methods, action_name, view = route_
            route_key = "%s-%s" % (path_type, action_name) if action_name else path_type

            # Populate url_table
            if route_key not in url_table:
                if path_type == PATH_TYPE_COLLECTION:
                    regex = action_name or r''
                else:
                    if action_name:
                        regex = r'(?P<resource_id>%s)/%s' % (self.resource_id_regex, action_name)
                    else:
                        regex = r'(?P<resource_id>%s)' % self.resource_id_regex

                url_table[route_key] = self.url(regex, self.wrap_view(route_key))

            # Populate route table
            method_map = route_table.setdefault(route_key, {})
            for method in methods:
                method_map[method] = view

            # Add options
            if self.respond_to_options:
                method_map.setdefault(constants.OPTIONS, 'options_response')

        # Store the route table at the same time
        self.route_table = dict(route_table)
        return list(url_table.values())

    def dispatch_to_view(self, route_key, request, *args, **kwargs):
        """
        Primary method used to dispatch incoming requests to the appropriate method.
        """
        routes = self.route_table[route_key]
        try:
            request_method = routes[request.method]
        except KeyError:
            allow = ','.join(routes.keys())
            raise ImmediateErrorHttpResponse(405, 40500, "Method not allowed", headers={'Allow': allow},
                                             meta={'allow': allow})
        else:
            method = getattr(self, request_method, None)

        # Authorisation hook
        if hasattr(self, 'handle_authorisation'):
            self.handle_authorisation(request)

        # Allow for a pre_dispatch hook, a response from pre_dispatch would indicate an override of kwargs
        if hasattr(self, 'pre_dispatch'):
            response = self.pre_dispatch(request, **kwargs)
            if response is not None:
                kwargs = response

        # Apply route key to kwargs on OPTIONS requests
        if request.method == constants.OPTIONS:
            kwargs['route_key'] = route_key

        result = method(request, **kwargs)

        # Allow for a post_dispatch hook, the response of which is returned
        if hasattr(self, 'post_dispatch'):
            return self.post_dispatch(request, result)
        else:
            return result

    def options_response(self, request, route_key, **kwargs):
        routes = self.route_table[route_key]
        response = HttpResponse(status=204)
        response['Allow'] = ','.join(method for method, route in routes.items() if route != 'options_response')
        return response


#
# @lc app=leetcode id=914 lang=python3
#
# [914] X of a Kind in a Deck of Cards
#
# https://leetcode.com/problems/x-of-a-kind-in-a-deck-of-cards/description/
#
# algorithms
# Easy (33.61%)
# Total Accepted:    9.7K
# Total Submissions: 28.9K
# Testcase Example:  '[1,2,3,4,4,3,2,1]'
#
# In a deck of cards, each card has an integer written on it.
#
# Return true if and only if you can choose X >= 2 such that it is possible to
# split the entire deck into 1 or more groups of cards, where:
#
#
# Each group has exactly X cards.
# All the cards in each group have the same integer.
#
#
#
#
# Example 1:
#
#
# Input: [1,2,3,4,4,3,2,1]
# Output: true
# Explanation: Possible partition [1,1],[2,2],[3,3],[4,4]
#
#
#
# Example 2:
#
#
# Input: [1,1,1,2,2,2,3,3]
# Output: false
# Explanation: No possible partition.
#
#
#
# Example 3:
#
#
# Input: [1]
# Output: false
# Explanation: No possible partition.
#
#
#
# Example 4:
#
#
# Input: [1,1]
# Output: true
# Explanation: Possible partition [1,1]
#
#
#
# Example 5:
#
#
# Input: [1,1,2,2,2,2]
# Output: true
# Explanation: Possible partition [1,1],[2,2],[2,2]
#
#
#
#
#
#
#
# Note:
#
#
# 1 <= deck.length <= 10000
# 0 <= deck[i] < 10000
#
#
#
#
#
#
#
#
#
#
#
#
#
class Solution:
    def hasGroupsSizeX(self, deck):
        """
        :type deck: List[int]
        :rtype: bool
        """
        if not deck or len(deck) < 2:
            return False

        def mcd(a, b):
            if a % b == 0:
                return b
            else:
                return mcd(b, a % b)

        hm = collections.defaultdict(int)
        for n in deck:
            hm[n] += 1
        minc = sys.maxsize
        for key in hm:
            minc = min(minc, hm[key])
            if minc < 2:
                return False
        for key in hm:
            if mcd(hm[key], minc) < 2:
                return False
        return True


import datetime, pytz, re, helper

def grab(channel, timespan):
	tz = pytz.timezone("Europe/Berlin")
	now = datetime.datetime.now(tz)
	shows = []
	a = 0
	if now.time().hour < 7:
		a = -1
	for i in range(a, 14):
		date = now + datetime.timedelta(days=i)
		datestring = "%s.%s.%s" % (date.day, date.month, date.year)
		text = helper.download("http://programm.ard.de/TV/Programm/Sender?datum=" + date.strftime("%d.%m.%Y") + "&hour=0&sender=" + channel)
		if text is None:
			continue

		sections = helper.split(text, "<li class=\"eid", "
")
		laststart = datetime.datetime.min.replace(tzinfo=tz)
		for section in sections:
			show = {}
			temp = re.search("<span class=\"date[\s\S]*?(\d\d):(\d\d)", section)
			show["start"] = date.replace(hour=int(temp.group(1)), minute=int(temp.group(2)), second=0, microsecond=0)
			if show["start"] < laststart:
				date += datetime.timedelta(days=1)
				show["start"] += datetime.timedelta(days=1)

			if (show["start"] - now).total_seconds() / 3600 > timespan:
				lastshow = True
			else:
				lastshow = False

			laststart = show["start"]

			show["title"] = helper.cleanup(re.search("\s*([^<]*?)[\t\n]", section).group(1))
			temp = re.search("\s*([^<]*?)[\t\n]", section)
			if temp is not None:
				subtitle = temp.group(1)
				if subtitle:
					show["sub-title"] = helper.cleanup(subtitle)

			temp = re.search("<a class=\"sendungslink[\s\S]*?href=\"(.*?)\"", section)
			if temp is not None:
				show["details-url"] = "http://programm.ard.de" + temp.group(1)
			shows.append(show)
			if lastshow:
				return shows
	return shows

def grabdetails(url):
	text = helper.download(url)
	if text is None:
		return None
	show = {}
	description = helper.cut(text, "<meta name=\"description\" content=\"", "\" />")
	if description is not None:
		show["desc"] = helper.cleanup(description)
	return show

def channellist():
	text = helper.download("http://programm.ard.de/")
	channels = helper.split(text, "Tagesprogramm::", "")
	result = []
	for channel in channels:
		temp = re.search("Tagesprogramm::(.*?)\".*\?sender\=-?(.*?)\&", channel)
		result.append((temp.group(2), temp.group(1), temp.group(1)))
	return result


import constants
from lib.epd2in13_V2 import EPD, EPD_WIDTH, EPD_HEIGHT
from PIL import Image, ImageDraw, ImageFont

class DisplayManager:
    def __init__(self):
        self.epd = EPD()
        self.epd.init(self.epd.FULL_UPDATE)
        print("Clearing display ...")
        self.epd.Clear(0xFF)

    def printQuote(self, quote):

        font_size, char_per_line, max_line = self.__getFontSize(len(quote))
        print("   font_size:", font_size, "char_line:", char_per_line, "max_line:", max_line, "quote_size:", len(quote))
        if (font_size == None):
            return False

        lines = self.__splitQuoteInLines(quote, char_per_line)
        self.__printQuote(font_size, max_line, char_per_line, lines)
        return True

    def __splitQuoteInLines(self, quote, char_per_line):
        # max 25 char per line
        count = 0
        lines_count = 0
        lines = []
        lines.append("")
        words = quote.split(" ")
        for word in words:
            if (count + len(word) <= char_per_line):
                count = count + len(word) + 1
                lines[lines_count] = lines[lines_count] + word + " "
            else:
                count = len(word) + 1
                lines_count += 1
                lines.append(word + " ")
        return lines

    def __getFontSize(self, quote_length):
        if (quote_length <= 210 and quote_length > 180):
            return 12, 35, 6
        elif (quote_length <= 180 and quote_length > 144):
            return 14, 30, 6
        elif (quote_length <= 144 and quote_length > 132):
            return 16, 24, 6
        elif (quote_length <= 132 and quote_length > 100):
            return 18, 22, 6
        elif (quote_length <= 100 and quote_length > 90):
            return 20, 20, 5
        elif (quote_length <= 90 and quote_length > 70):
            return 22, 18, 5
        elif (quote_length <= 70):
            return 24, 17, 5
        return None, None, None
        #font -> char per lines*number of lines = total possible chars
        #12 -> 35*6=210
        #14 -> 30*6=180
        #16 -> 24*6=144
        #18 -> 22*6=132
        #20 -> 20*5=100
        #22 -> 18*5=90
        #24 -> 17*5=85

    def __printQuote(self, font_size, max_line, char_per_line, lines):
        X_MARGIN = 5
        Y_MARGIN = 5
        Y_INTERLIGN = 20

        font24 = ImageFont.truetype('/home/pi/CheesyQuotes/fonts/SourceCodePro-SemiBoldItalic.ttf', font_size)
        image = Image.new('1', (self.epd.height, self.epd.width), 255)  # 255: clear the frame
        draw = ImageDraw.Draw(image)

        line_skip = (max_line - len(lines)) / 2
        for i, line in enumerate(lines):
            x = X_MARGIN
            y = Y_INTERLIGN * i + line_skip * Y_INTERLIGN + Y_MARGIN
            char_skip = int((char_per_line - len(line)) / 2)
            line = " " * char_skip + line
            draw.text((x, y), line, font = font24, fill = 0)

        self.epd.display(self.epd.getbuffer(image))