import logging
import os
import re

import bs4
from bs4 import BeautifulSoup as bs
import typing
from typing import List, Dict
from datetime import datetime

class DataFormatter:
    """
    Абстрактный класс для задания соответствий между
        получаемыми из html свойствами
        свойствами в БД
        колонками экспортного файла
    """
    pass

class BookDataFormatter(DataFormatter):
    """
    Класс содержит таблицу соответствий между свойствами книги в БД (db), колонок экспортного файла (csv, xlsx)
    и методами парсера класса ParserFromHTML (parser), вынимающими это свойство из html.
    {
    'название_свойства': {
           'parser': 'метод_для_вынимания_свойства_из_html_кода',
           'db': { 'name': 'название_колонки_в_бд',
                    'type': 'тип_колонки_в_бд'
                    },
           'csv': { 'name': 'Название_колонки_в_csv',
                    'method': 'метод_для_форматирования_значения_для_csv'
                    },
            'xlsx': {   'name': 'Название_колонки_в_xlsx',
                        'method': 'метод_для_форматирования_значения_для_xlsx',
                        'order': 'порядок следования в таблице в формате integer'
                    }
           },
    ...
    }
          свойства date, month, year не вынимаются из html стандартным способом,
          поэтому его parser не задан. Они будут вынуты в методе ParserFromHTML.all_books_from_page()

          На ЛЛ есть книги со ссылкой вида /book/book_id и произведения со ссылкой вида /work/work_id.
    """

    common = {
        'author_id': {'parser': 'get_author_id',
                      'db': {'name': 'author_id', 'type': 'INTEGER'},
                      'csv': {'name': 'Cсылка на автора', 'method': 'create_author_link'},
                      'xlsx': {'name': 'Cсылка на автора', 'method': 'create_author_link', 'order' :7, 'column_width':30},
                      },
        'author_name': {'parser': 'get_author_name',
                        'db': {'name': 'author_name', 'type': 'TEXT'},
                        'csv': {'name': 'Автор', },
                        'xlsx': {'name': 'Автор', 'order':2, 'column_width':30 }
                        },
        'book_id': {'parser': 'get_book_id',
                    'db': {'name': 'book_id', 'type': 'INTEGER'},
                    'csv': {'name': 'Ссылка на  книгу', 'method': 'create_book_link'},
                    'xlsx': {'name': 'Ссылка на  книгу', 'method': 'create_book_link', 'order':8, 'column_width':30}
                    },
        'work_id': {'parser': 'get_work_id',
                    'db': {'name': 'work_id', 'type': 'INTEGER'},
                    'csv': {'name': 'Ссылка на произведение', 'method': 'create_work_link'},
                    'xlsx': {'name': 'Ссылка на произведение', 'method': 'create_work_link','order':9, 'column_width':30}
                    },
        'book_name': {'parser': 'get_book_name',
                      'db': {'name': 'book_name', 'type': 'TEXT'},
                      'csv': {'name': 'Название', },
                      'xlsx': {'name': 'Название', 'order':1, 'column_width':30}
                      },
        'common_rating': {'parser': 'get_common_rating',
                          'db': {'name': 'common_rating', 'type': 'REAL'},
                          'csv': {'name': 'Общая оценка', },
                          'xlsx': {'name': 'Общая оценка', 'order':10, 'column_width':5}
                          },
        'picture_url': {'parser': 'get_picture_url',
                        'db': {'name': 'picture_url', 'type': 'TEXT'},
                        'csv': {'name': 'Обложка', 'method': 'create_picture_url'},
                        'xlsx': {'name': 'Обложка', 'method': 'create_picture_url', 'order':12, 'column_width':30}
                        },
        'reader_rating': {'parser': 'get_reader_rating',
                          'db': {'name': 'reader_rating', 'type': 'REAL'},
                          'csv': {'name': 'Моя оценка', },
                          'xlsx': {'name': 'Моя оценка', 'order':3, 'column_width':5}
                          },
        'tags': {'parser': 'get_tags',
                 'db': {'name': 'tags', 'type': 'TEXT'},
                 'csv': {'name': 'Теги', },
                 'xlsx': {'name': 'Теги', 'order':5, 'column_width':20}
                 },
        'review_id': {'parser': 'get_review_id',
                      'db': {'name': 'review_id', 'type': 'INTEGER'},
                      'csv': {'name': 'Ссылка на рецензию', 'method': 'create_review_link'},
                      'xlsx': {'name': 'Ссылка на рецензию', 'method': 'create_review_link', 'order':11, 'column_width':30},
                      },
        'review_text': {'parser': 'get_review_text',
                        'db': {'name': 'review_text', 'type': 'TEXT'},
                        'csv': {'name': 'Рецензия', 'method': 'create_review_text'},
                        'xlsx': {'name': 'Рецензия', 'method': 'create_review_text', 'order':4, 'column_width':100}
                        },
        'date': {'parser': 'not_implemented',
                 'csv': {'name': 'Дата прочтения', },
                 'xlsx': {'name': 'Дата прочтения', 'order':6, 'column_width':15}
                 },
        'month': {'parser': 'not_implemented',
                  'db': {'name': 'month', 'type': 'INTEGER'},
                  },
        'year': {'parser': 'not_implemented',
                 'db': {'name': 'year', 'type': 'INTEGER'},
                 },
        'livelib_id': {'parser': 'not_implemented',
                       'db': {'name': 'livelib_id', 'type': 'INTEGER'},
                       },
        'login': {'parser': 'not_implemented',
                  'db': {'name': 'login', 'type': 'TEXT'},
                  },
        'update_time': {'parser': 'not_implemented',
                        'db': {'name': 'update_time', 'type': 'TEXT'},
                        },
    }

    book_properties_db = ['book_id', 'work_id', 'book_name', 'author_name', 'author_id', 'common_rating', 'picture_url']
    reader_properties_db = ['livelib_id', 'login', 'update_time']
    readbook_properties_db = ['review_text', 'review_id', 'tags', 'reader_rating', 'month', 'year']

    @classmethod
    def all_properties_parser(cls):
        """
        Преобразует таблицу в удобный для ParserFromHTML словарь.
        :return: словарь вида {название_поля1: метод_обработки_поля1, название_поля2: метод_обработки_поля2, }
        :rtype: Dict
        """
        return {i: j['parser'] for i, j in cls.common.items()}

    @classmethod
    def all_properties_db(cls):
        """
        Преобразует таблицу в удобный для DBConnection словарь.
        :return: словарь вида {'название_поля1':'тип_поля1', 'название_поля2':'тип_поля1', ...}
        :rtype: Dict
        """
        result = {}
        for i in cls.common.values():
            if i.get('db'):
                result[i['db']['name']] = i['db']['type']
        return result

    @classmethod
    def all_properties_csv(cls):
        """
        Преобразует таблицу в удобный для CSVConnection словарь
        :return: словарь вида {'author_id': {'name': 'Cсылка на автора', 'method': 'create_author_link'}, {}, ...}
        :rtype: Dict
        """
        result = {}
        for i, j in cls.common.items():
            if j.get('csv'):
                result[i] = j['csv']
        return result

    @classmethod
    def all_properties_xlsx(cls):
        """
        Преобразует таблицу в удобный для XLSXConnection словарь, упорядоченный по заданному порядку
        :return: Словарь вида {'author_id': {'name': 'Cсылка на автора', 'method': 'create_author_link'}, {}, ...}
        :rtype: Dict
        """
        result = {}
        for i, j in cls.common.items():
            if j.get('xlsx'):
                result[i] = j['xlsx']
        sorted_result ={i[0]:i[1] for i in sorted(result.items(), key=lambda x: x[1]['order'])}
        return sorted_result

class Parser:

    @staticmethod
    def _clear_name(s: str) -> str:
        """
        Служебная функция для очистки названий от переносов и лишних пробелов
        """
        s = re.sub(" +", " ", s)
        s = re.sub("\n", "", s)
        return s

class ParserFromHTML(Parser):
    """
    Класс парсинга страниц сайта. Здесь задаются адресация страниц сайта и поиск данных в его верстке.
    """

    @staticmethod
    def reader_prefix(login: str) -> str:
        """
        Возвращает префикс страниц сайта для конкретного читателя.
        :param login: логин читателя
        :type login: str
        :return: префикс страниц сайта для конкретного читателя
        :rtype: str
        """
        return '/reader/' + login

    @staticmethod
    def reader_read_books_page(login: str) -> str:
        """
        Возвращает начальную страницу с книгами, прочитанными читателем
        :param login: логин читателя
        :type login: str
        :return: страница с прочитанными книгами
        :rtype: str
        """
        return ParserFromHTML.reader_read_books_page_by_number(login=login, number=0)

    @staticmethod
    def reader_read_books_page_by_number(login: str, number: int = 0) -> str:
        """
        Возвращает страницу с заданным номером с книгами, прочитанными читателем
        :param login: логин читателя
        :type login: str
        :param number: номер страницы
        :type number: int
        :return: страница с прочитанными книгами
        :rtype: str
        """
        return ParserFromHTML.reader_prefix(login) + '/read/~' + str(number)

    @staticmethod
    def check_404(bsoup: bs4.BeautifulSoup) -> bool:
        """
        Проверяет, не возвращает ли страница штатные 404.
        :param bsoup: текст страницы
        :type bsoup:  bs4.BeautifulSoup
        :return: True, если 404, False иначе
        :rtype: Boolean
        """
        if bsoup.find('title', string='404 @ LiveLib'):
            return True
        else:
            return False

    @staticmethod
    def check_captcha(bsoup: bs4.BeautifulSoup) -> bool:
        """
        Проверяет, не возвращает ли страница капчу на проверку ботов.
        :param bsoup: текст страницы
        :type bsoup:  bs4.BeautifulSoup
        :return: True, если капча, False иначе
        :rtype: Boolean
        """
        if bsoup.find(string='Please confirm that you and not a robot are sending requests'):
            return True
        else:
            return False

    @staticmethod
    def all_books_from_page(bsoup: bs4.BeautifulSoup, formatter: BookDataFormatter = BookDataFormatter) -> List[Dict]:
        """
        Возвращает ифнормацию о всех книгах на данной странице в виде списка словарей.
        Словарь формируется с ключами из BookDataFormatter, соответствующие значения вычисляются
        с помощью функций, указанных там же.
        Исключение - месяц и год прочтения книги формируются в этом методе, это обусловлено версткой.
        :param bsoup: код страницы
        :type bsoup: bs4.BeautifulSoup
        :param formatter:  словарь с перечислением нужных свойств
        :type formatter: BookDataFormatter
        :return: список словарей по каждой книге вида {'property_name': 'property_value'}
        :rtype: List[Dict]
        """
        # в коде страницы внутри блока

        # чередуются блоки
Месяц Год
 и
КНИГА

        # последовательно пойдем по этим блокам, присваивая книгам, следующим за датой, эту дату прочтения
        result = []
        month = None
        year = None
        for block in bsoup.find('div', id='booklist').children:
            # если это блок с месяцем и годом, запоминаем его для добавления в информацию по последующим книгам
            if 'brow-h2' in block['class']:
                date = block.text
                # вытащим месяц (если он есть, для старых книг его может не быть), переведем его в цифру
                month = re.search(r'\D+(?= )', date)
                if month != None:
                    month = month.group()
                    month_numbers = {'январь': 1, 'февраль': 2, 'март': 3, 'апрель': 4, 'май': 5, 'июнь': 6,
                                     'июль': 7, 'август': 8, 'сентябрь': 9, 'октябрь': 10, 'ноябрь': 11, 'декабрь': 12}
                    month = month_numbers.get(month.lower(), None)
                # вытащим год
                year = re.search(r'\d+', date)
                if year != None: year = int(year.group())
            # если это блок с книгой, парсим ее как книгу и вносим месяц и год прочтения в результат
            elif 'book-item-manage' in block['class']:
                book = ParserFromHTML.book(block, formatter)
                book['month'] = month
                book['year'] = year
                result.append(book)
        return result

    @staticmethod
    def book(bsoup: bs4.BeautifulSoup, formatter: BookDataFormatter = BookDataFormatter) -> Dict[str, str]:
        """
        Возвращает словарь с информацией о книге, представленной в заданном коде.
        Словарь формируется с ключами из BookDataFormatter, соответствующие значения вычисляются
        с помощью функций, указанных там же.
        Исключение - месяц и год прочтения книги формируются в методе all_books_from_page, это обусловлено версткой.
        :param bsoup: код с информацией о книге
        :type bsoup: bs4.BeautifulSoup
        :param formatter: словарь с перечислением нужных свойств
        :type formatter: BookDataFormatter
        :return: словарь типа {'property_name': 'property_value'}
        :rtype: Dict[str,str]
        """
        result = {}
        for property_name, parser_function in formatter.all_properties_parser().items():
            try:
                if hasattr(ParserFromHTML, parser_function):
                    result[property_name] = getattr(ParserFromHTML, parser_function)(bsoup)
            except AttributeError:
                logging.exception(f'No parser function {parser_function} is found!', exc_info=True)
        return result

    @staticmethod
    def get_author_name(bsoup: bs4.BeautifulSoup) -> str:
        result = bsoup.find('a', class_='brow-book-author')
        if result and bool(result.text):
            return ParserFromHTML._clear_name(result.text)
        else:
            return None

    @staticmethod
    def get_author_id(bsoup: bs4.BeautifulSoup) -> str:
        author_id = re.compile(r'(?<=/author/)\d+(?=-)')
        link = bsoup.find('a', class_='brow-book-author')
        if link:
            result = re.search(author_id, link.get('href'))
            return int(result.group()) if result else None
        else:
            return None

    @staticmethod
    def get_book_name(bsoup: bs4.BeautifulSoup) -> str:
        result = bsoup.find('a', class_='brow-book-name')
        if result and bool(result.text):
            return Parser._clear_name(result.text)
        else:
            return None

    @staticmethod
    def get_book_id(bsoup: bs4.BeautifulSoup) -> str:
        book_id = re.compile(r'(?<=/book/)\d+(?=-)')
        link = bsoup.find('a', class_='brow-book-name')
        if link:
            result = re.search(book_id, link.get('href'))
            return int(result.group()) if result else None
        else:
            return None

    @staticmethod
    def get_work_id(bsoup: bs4.BeautifulSoup) -> str:
        book_id = re.compile(r'(?<=/work/)\d+(?=-)')
        link = bsoup.find('a', class_='brow-book-name')
        if link:
            result = re.search(book_id, link.get('href'))
            return int(result.group()) if result else None
        else:
            return None

    @staticmethod
    def get_common_rating(bsoup: bs4.BeautifulSoup) -> float:
        """
        Возвращает общую оценку книги.
        :param bsoup: код, вмещающий информацию о книге
        :type bsoup: bs4.BeautifulSoup
        :return: число
        :rtype: float
        """
        result = bsoup.find('div', class_='brow-ratings').find_all('span', class_='rating-book')[1]
        if result and bool(result.text):
            return float(result.text)
        else:
            return None

    @staticmethod
    def get_picture_url(bsoup: bs4.BeautifulSoup) -> str:
        """
        Возвращает ссылку на картинку с обложкой книги.
        :param bsoup: код, вмещающий информацию о книге
        :type bsoup: bs4.BeautifulSoup
        :return: абсолютную ссылку
        :rtype: str
        """
        result = bsoup.find('div', class_='cover-wrapper').find('img').get('data-pagespeed-lazy-src')
        if result:
            return result
        else:
            result = bsoup.find('div', class_='cover-wrapper').find('img').get('src')
            return result if result else None

    @staticmethod
    def get_reader_rating(bsoup: bs4.BeautifulSoup) -> float:
        """
        Возвращает оценку книги читателем.
        :param bsoup: код, вмещающий информацию о книге
        :type bsoup: bs4.BeautifulSoup
        :return: число
        :rtype: float
        """
        result = bsoup.find('div', class_='brow-ratings').find_all('span', class_='rating-book')[0]
        if result and bool(result.text):
            return float(result.text)
        else:
            return None

    @staticmethod
    def get_tags(bsoup: bs4.BeautifulSoup):
        tags = bsoup.find('div', class_='brow-tags')
        result = []
        if tags != None:
            # необходимо проверить, не является ли тег ссылкой на расширенный список тегов (вида 'Еще NN тегов')
            # Если он - ссылка, то пропускаем его.
            # даже если теги скрыты, мы все равно их вытащим из кода страницы.
            more = re.compile(r'^Ещё \d+')
            for i in tags.find_all('a', class_='label-tag'):
                if re.match(more, i.text) == None:
                    result.append(i.text)
        return ';'.join(result)

    @staticmethod
    def get_review_id(bsoup: bs4.BeautifulSoup) -> int:
        result = None
        review_id = re.compile(r'(?<=review-)\d+(?=-full)')
        div = bsoup.find(id=review_id)
        if div != None:
            result = int(re.search(review_id, div['id']).group())
        return result

    @staticmethod
    def get_review_text(bsoup: bs4.BeautifulSoup) -> str:
        result = None
        review_id = re.compile(r'(?<=review-)\d+(?=-full)')
        div = bsoup.find(id=review_id)
        if div != None:
            # сохраняем текст рецензии
            body = ''.join([str(p) for p in div.find('div', itemprop='reviewBody').contents])
            # ищем и сохраняем
            events = div.find('div', class_='event-pad')
            extra = ''.join([str(p) for p in events.contents]) if events != None else ''
            result = body + extra
        return result

    @staticmethod
    def get_paginator(bsoup: bs4.BeautifulSoup) -> List[int]:
        """
        Возвращает список номеров страниц из паджинатора в низу страницы. Если страница единственная, и паджинатора нет,
        то возвращает пустой список.
        :param bsoup: код страницы
        :type bsoup: bs4.BeautifulSoup
        :return: список номеров страниц либо пустой список
        :rtype: List[int]
        """
        paginator = bsoup.find('div', id='booklist-pagination')
        result = []
        # если страница единственная, она же текущая, то возвращаем пустой список ссылок
        if paginator == None:
            return result
        # если страницы есть
        else:
            last_page = paginator.find('a', title='Последняя страница')
            # если не все страницы представлены, но есть ссылка на самую последнюю страницу
            if last_page:
                last_number = int(re.search(r'(?<=~)\d+', last_page['href']).group())
                result = [i for i in range(1, last_number + 1)]
            # если все страницы умещаются в низу страницы (их мало, до пяти штук)
            else:
                result = [int(i) for i in paginator.text.split()]
            return result

class ParserForDB(Parser):
    @staticmethod
    def _prepare_book_for_db(book: Dict, formatter=BookDataFormatter) -> List:
        """
        Преобразует книгу для сохранения в БД в соответствии с BookDataFormatter.
        Нужен в случае, если название колонки в БД отличается от названия свойства парсера или
        требуется предварительная обработка значения свойства.
        :param book: словарь с информацией про книгу вида {'parser_field_name1':'field_value1','parser_field_name2':'field_value2'}
        :type book: Dict
        :param formatter: класс форматтера
        :type formatter: Class
        :return: словарь для сохранения  в БД вида {'db_field_name1':'field_value1', 'db_field_name2':'field_value2', ... }
        :rtype: Dict
        """
        new_book = {}
        for property in formatter.all_properties_db().keys():
            value = book.get(property, None)
            if value == None: value = ''
            new_book[formatter.common[property]['db']['name']] = value
        return new_book

    @staticmethod
    def prepare_books_for_db(books: List[Dict], formatter=BookDataFormatter) -> List:
        """
        Преобразует список книг для сохранения в БД в соответствии с BookDataFormatter.
        Нужен в случае, если название колонки в БД отличается от названия свойства парсера или
        требуется предварительная обработка значения свойства.
        :param books: список книг вида [{'parser_field_name1':'field_value1','parser_field_name2':'field_value2'},{}]
        :type books: List[Dict]
        :param formatter: класс форматтера
        :type formatter: Class
        :return: список для сохранения  в БД вида [{'db_field_name1':'field_value1', 'db_field_name2':'field_value2'}, {}]
        :rtype: List[Dict]
        """
        result = []
        for book in books:
            result.append(ParserForDB._prepare_book_for_db(book, formatter=formatter))
        return result

class ParserForCSV(Parser):
    @staticmethod
    def create_filepath_csv(login: str) -> str:
        """
        Возвращает путь и безопасное имя файла CSV формата 'login-YYYY-MM-DD--HH-MM-SS.csv'.
        Из логина читателя будут удалены небезопасные символы.
        :param login: логин читателя
        :type login: str
        :return:
        :rtype: str
        """
        login = login.translate(str.maketrans('', '', '\/:*?"<>|'))
        filename = login + "-" + datetime.now().strftime("%Y-%m-%d--%H-%M-%S") + '.csv'
        # @todo тут должна задаваться папка для сохранения csv
        return (os.path.join('csv', filename))

class ParserForXLSX(Parser):
    @staticmethod
    def prepare_book_for_xlsx(book: Dict, formatter=BookDataFormatter) -> List:
        """
        Преобразует книгу для сохранения в XLSX в соответствии с BookDataFormatter.
        Нужен в случае, если название колонки в XLSX отличается от названия свойства парсера или
        требуется предварительная обработка значения свойства.
        :param book: словарь с информацией про книгу вида {'parser_field_name1':'field_value1','parser_field_name2':'field_value2'}
        :type book: Dict
        :param formatter: класс форматтера
        :type formatter: Class
        :return: словарь для сохранения  в XLSX вида {'db_field_name1':'field_value1', 'db_field_name2':'field_value2', ... }
        :rtype: Dict
        """
        new_book = {}
        for property in formatter.all_properties_xlsx().keys():
            method = formatter.all_properties_xlsx()[property].get('method', None)
            value = book.get(property, None)
            if value == None:
                value = ''
            elif method and hasattr(ParserForXLSX, method):
                value = getattr(ParserForXLSX,method)(value)
            new_book[property] = value
        # отдельно формируем дату из свойств month и year
        month_numbers = {1:'январь', 2:'февраль', 3:'март', 4:'апрель', 5:'май', 6:'июнь',
                         7:'июль',8: 'август', 9:'сентябрь',10: 'октябрь',11: 'ноябрь', 12: 'декабрь'}
        month = "" if not book['month'] else month_numbers.get(book['month'], '')
        new_book['date'] = " ".join((str(book['year']), month ))
        return new_book

    @staticmethod
    def create_author_link(id):
        return 'https://livelib.ru/author/'+str(id)

    @staticmethod
    def create_book_link(id):
        return 'https://livelib.ru/book/'+str(id)

    @staticmethod
    def create_work_link(id):
        return 'https://livelib.ru/work/'+str(id)

    @staticmethod
    def create_review_link(id):
        return 'https://livelib.ru/review/'+str(id)

    @staticmethod
    def create_review_text(text):
        bsoup = bs4.BeautifulSoup(text,features='lxml')
        result = bsoup.get_text("\n")
        result = result.replace("\n\n", "\n")
        return result


from django.urls import path
from . import views

app_name = 'items'

urlpatterns = [
    path('', views.list_items, name='list_items'),
    path('adicionar/', views.add_item, name='add_item'),
    path('editar/<int:id_item>/', views.edit_item, name='edit_item'),
    path('excluir/<int:id_item>/', views.delete_item, name='delete_item'),
]


import xml.etree.ElementTree as ET
import numpy as np
import os.path
import pickle

# XML wird geladen
positionsRAW = ET.parse(os.path.dirname(__file__) + '/../Data_STS/DFL_04_02_positions_raw_DFL-COM-000001_DFL-MAT-X03BWS.xml')
matchInformation = ET.parse(os.path.dirname(__file__) + '/../Data_STS/DFL_02_01_matchinformation_DFL-COM-000001_DFL-MAT-X03BWS.xml')
root = positionsRAW.getroot()
rootMatchInfo = matchInformation.getroot()

#<FrameSet GameSection="firstHalf" MatchId="DFL-MAT-X03BWS" TeamId="DFL-CLU-000N9A" PersonId="DFL-OBJ-002G6R">
#<Object ObjectId="DFL-OBJ-002G6N" Type="player" Name="Frenkie de Jong" FirstName="Frenkie" LastName="de Jong" BirthDate="12.05.1997" CountryOfBirthGerman="Niederlande" CountryOfBirthEnglish="Netherlands" CountryOfBirthSpanish="Holanda" NationalityGerman="Niederländisch" NationalityEnglish="Dutch" NationalitySpanish="neerlandés" Height="180" Weight="74" ShirtNumber="21" PlayingPositionGerman="Mittelfeld" PlayingPositionEnglish="midField" PlayingPositionSpanish="medio campo" ClubId="DFL-CLU-000N9A" ClubName="Niederlande Nationalmannschaft"/>
#<Objects FeedType="player">
#<Object ObjectId="DFL-OBJ-0000O3" Type="player" Name="Marco Reus" FirstName="Marco" LastName="Reus" BirthDate="31.05.1989" BirthPlace="Dortmund" CountryOfBirthGerman="Deutschland" CountryOfBirthEnglish="Germany" CountryOfBirthSpanish="Alemania" NationalityGerman="Deutsch" NationalityEnglish="German" NationalitySpanish="alemán" Height="180" Weight="71" ShirtNumber="11" PlayingPositionGerman="Mittelfeld" PlayingPositionEnglish="midField" PlayingPositionSpanish="medio campo" ClubId="DFL-CLU-000N99" ClubName="Deutschland Nationalmannschaft"/>

playerPositionsFH = {}
playerPositionsSH = {}

for frameset in root.iter('FrameSet'):
    positionsX, positionsY = [], []
    for frame in frameset:
        positionsX.append(frame.get('X'))
        positionsY.append(frame.get('Y'))

    # String in Float umwandeln
    positionsX, positionsY = np.array(positionsX).astype(np.float), np.array(positionsY).astype(np.float)

    if (frameset.get('GameSection') == 'firstHalf'):
        playerPositionsFH[frameset.get('PersonId')] = {}
        playerPositionsFH[frameset.get('PersonId')]['Shortname'] = 'Ball'
        playerPositionsFH[frameset.get('PersonId')]['TeamId'] = frameset.get('TeamId')
        playerPositionsFH[frameset.get('PersonId')]['meanX'] = np.mean(positionsX)
        playerPositionsFH[frameset.get('PersonId')]['meanY'] = np.mean(positionsY)
    elif (frameset.get('GameSection') == 'secondHalf'):
        playerPositionsSH[frameset.get('PersonId')] = {}
        playerPositionsSH[frameset.get('PersonId')]['Shortname'] = 'Ball'
        playerPositionsSH[frameset.get('PersonId')]['TeamId'] = frameset.get('TeamId')
        playerPositionsSH[frameset.get('PersonId')]['meanX'] = np.mean(positionsX)
        playerPositionsSH[frameset.get('PersonId')]['meanY'] = np.mean(positionsY)
    else:
        print('Error: ', frameset.get('GameSection'))

for player in rootMatchInfo.iter('Player'):
    try:
        playerPositionsFH[player.get('PersonId')]['Shortname'] = player.get('Shortname')
        playerPositionsSH[player.get('PersonId')]['Shortname'] = player.get('Shortname')
        playerPositionsFH[player.get('PersonId')]['ShirtNumber'] = player.get('ShirtNumber')
        playerPositionsSH[player.get('PersonId')]['ShirtNumber'] = player.get('ShirtNumber')
    except KeyError:
        print('KeyError: ' + player.get('Shortname') + ' hat nicht gespielt.')
    except:
        print('Error', player.get('PersonId'), player.get('Shortname'))

with open(os.path.dirname(__file__) + '/obj/playerPositionsFH.pkl', 'wb') as output:
    pickle.dump(playerPositionsFH, output, pickle.HIGHEST_PROTOCOL)
with open(os.path.dirname(__file__) + '/obj/playerPositionsSH.pkl', 'wb') as output:
    pickle.dump(playerPositionsSH, output, pickle.HIGHEST_PROTOCOL)


"""Some tools"""

# %%
import doctest
import csv

def replace_greek_alphabet(to_translate: str) -> str:
    """Replace Greek letter by their full latin name

    Parameters
    ----------
    to_translate : str
        the string to transliterate

    Returns
    -------
    str
        the string to translate with all occurences of greel letter replaced

    Note
    ----
    works only for lower case Greek letter

    Examples
    --------

    >>> remove_greek_alphabet("α-pinene")
    'alpha-pinene'
    >>> remove_greek_alphabet("β-pinene")
    'beta-pinene'
    >>> remove_greek_alphabet("From α to ω")
    'From alpha to omega'
    """

    greek_to_latin = {
        "α": "alpha",
        "β": "beta",
        "γ": "gamma",
        "δ": "delta",
        "ε": "epsilon",
        "ζ": "zeta",
        "η": "eta",
        "θ": "theta",
        "ι": "iota",
        "κ": "kappa",
        "λ": "lamda",
        "μ": "mu",
        "ν": "nu",
        "ξ": "xi",
        "ο": "omicron",
        "π": "pi",
        "ρ": "rho",
        "σ": "sigma",
        "ς": "sigma",  # final final ?
        "τ": "tau",
        "υ": "upsilon",
        "φ": "phi",
        "χ": "chi",
        "ψ": "psi",
        "ω": "omega",
    }
    res = to_translate
    for letter, latin in greek_to_latin.items():
        res = res.replace(letter, latin)
    return res

SAMPLE_KEGG_RESULT = """cpd:C00521\t(S)-Limonene; (-)-Limonene; (4S)-1-Methyl-4-(prop-1-en-2-yl)cyclohexene; (-)-(S)-Limonene; (-)-(4S)-Limonene\ncpd:C06078\tLimonene; Dipentene; dl-Limonene; Cajeputene; Kautschin\ncpd:C06099\t(R)-Limonene; (+)-Limonene; d-Limonene; (4R)-1-Methyl-4-(prop-1-en-2-yl)cyclohexene; (+)-(R)-Limonene; (+)-(4R)-Limonene\ncpd:C07271\tLimonene-1,2-epoxide; Limonene oxide; (4R)-Limonene-1,2-epoxide\ncpd:C07276\tLimonene-1,2-diol; (1S,2S,4R)-Limonene-1,2-diol; (1S,2S,4R)-Menth-8-ene-1,2-diol\ncpd:C11937\t(1S,4R)-1-Hydroxy-2-oxolimonene; (1S,4R)-1-Hydroxymenth-8-en-2-one\ncpd:C19081\t(4S)-Limonene-1,2-epoxide\ncpd:C19082\t(1R,2R,4S)-Limonene-1,2-diol; (1R,2R,4S)-Menth-8-ene-1,2-diol\ncpd:C19083\t(1R,4S)-1-Hydroxy-2-oxolimonene\n"""  # pylint: disable=line-too-long

def parse_kegg_list(input_str: str) -> dict[str, list[str]]:
    """Parse un résultat du webservice WSDL de KEGG

    Parameters
    ----------
    input_str : str
        le résultat brut txt/raw

    Returns
    -------
    dict[str, list[str]]
        le dictionnaire du résultat : pour chaque clef, la liste des noms

    Examples
    --------
    >>> len(parse_kegg_list(SAMPLE_KEGG_RESULT))
    9
    >>> isinstance(parse_kegg_list(SAMPLE_KEGG_RESULT), dict)
    True

    """
    # http://rest.kegg.jp/find/compound/%22limonene%22
    # result is a list of lines "cpd:id\tname1; name2; ..."
    lines = csv.reader(input_str.split("\n"), delimiter="\t")
    # après split, la dernière ligne est une ligne vide, on évite les vide
    results_dict = {line[0]: line[1].split("; ") for line in lines if line}
    return results_dict

if __name__ == "__main__":
    doctest.testmod(verbose=False, report=True)


from aiogram import types
from aiogram.dispatcher import FSMContext
from aiogram.dispatcher.filters.builtin import Command
from aiogram.types import ReplyKeyboardRemove
from aiogram.utils.markdown import hcode, hlink

from filters.is_private import IsPrivate
from handlers.users.profile_creating.profile import show_profile
from keyboards.default.likes import like_or_not, LIKE, DISLIKE, SLEEP
from loader import dp
from states.search_states import SearchState
from utils.db_api import quick_commands as db
from utils.db_api.quick_commands import delete_love
from utils.db_api.schemas.love import Love

@dp.message_handler(IsPrivate(), Command("see_love"))
async def im_liked(message: types.Message, state: FSMContext):
    user_id = message.from_user.id
    try:
        love = await Love.query.where(Love.liked == user_id).gino.first()
    except Exception:
        return await message.answer("Пока что ты никому не понравился(\n"
                                    "Смотреть анкеты: /search")

    if love:
        await show_profile(profile_owner_id=love.likes, receiver_id=love.liked, reply_markup=like_or_not)
        await state.update_data(user_id=love.likes)
        await SearchState.Answer.set()
    else:
        return await message.answer("Пока что ты никому не понравился(\n"
                                    "Смотреть анкеты: /search")

@dp.message_handler(IsPrivate(), state=SearchState.Answer, text=LIKE)
async def match_like(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        user_id = data.get("user_id")

    user = await db.select_user(user_id)
    await message.answer("Общаться:\n" +
                         hlink(f"{user.name}", f"tg://user?id={user_id}"))

    await my_mismatch(message, state)

@dp.message_handler(IsPrivate(), state=SearchState.Answer, text=DISLIKE)
async def my_mismatch(message: types.Message, state: FSMContext):
    async with state.proxy() as data:
        user_id = data.get("user_id")

    await delete_love(message.from_user.id, user_id)
    await im_liked(message, state)

@dp.message_handler(IsPrivate(), state=SearchState.Answer, text=SLEEP)
async def my_missleep(message: types.Message, state: FSMContext):

    await message.answer("Я устал", reply_markup=ReplyKeyboardRemove())
    await state.finish()


import uuid
import logging

from board import Board
from board_status import BoardStatus
from board_type import BoardType

logger = logging.getLogger()
logger.setLevel(logging.INFO)

from board_db import connection
db_conn = connection.Connection()

def get_boards_for_user(cognito_username):
	with db_conn.get_cursor() as cursor:
		cursor.execute('''
						SELECT b.board_id, b.owner_id, b.board_name, BIN_TO_UUID(b.join_code), b.board_status_id, b.board_type_id, b.start_date, b.end_date
						FROM board b
						JOIN person p ON b.owner_id = p.person_id
						WHERE p.cognito_username = UUID_TO_BIN(%s)''',
						(cognito_username,))
		results = cursor.fetchall()
		db_conn.conn.commit()
		return [_board_tuple_to_board(board) for board in results]

def get_board_by_join_code(join_code):
	with db_conn.get_cursor() as cursor:
		board = _get_board_by_join_code(cursor, join_code)
		db_conn.conn.commit()
		return board

def create_board(cognito_username, board_name, board_status, board_type):
	with db_conn.get_cursor() as cursor:
		owner_id = _get_person_id_for_username(cursor, cognito_username)
		new_uuid = uuid.uuid4()
		cursor.execute(	'''
						INSERT INTO board (owner_id, board_name, join_code, board_status_id, board_type_id)
						VALUES (%s, %s, UUID_TO_BIN(%s), %s, %s);
						''',
						(owner_id, board_name, new_uuid, board_status.value, board_type.value))
		db_conn.conn.commit()
		return _get_board_by_join_code(cursor, new_uuid)

def update_board(board):
	start_date = board.start_date.strftime('%Y-%m-%d %H:%M:%S') if board.start_date else None
	end_date = board.end_date.strftime('%Y-%m-%d %H:%M:%S') if board.end_date else None
	with db_conn.get_cursor() as cursor:
		cursor.execute( '''
						UPDATE board
						SET
							board_status_id = %s,
							start_date = %s,
							end_date = %s
						WHERE
							join_code=UUID_TO_BIN(%s)
						''',
						(board.board_status.value, start_date, end_date, board.join_code))
		updated_board = _get_board_by_join_code(cursor, board.join_code)
		db_conn.conn.commit()
		return updated_board

def create_photo_for_board(cognito_username,
						   photo_key,
						   s3_bucket_name,
						   s3_object_key,
						   join_code,
						   board_photo_status):
	with db_conn.get_cursor() as cursor:
		try:
			person_id = _get_person_id_for_username(cursor, cognito_username)
			board = _get_board_by_join_code(cursor, join_code)
			new_photo_id = _create_photo(cursor, person_id, photo_key, s3_bucket_name, s3_object_key)
			_create_mapping(cursor, board, new_photo_id, board_photo_status)
			db_conn.conn.commit()
			cursor.close()
		except:
			logging.exception(f'Could not insert photo {url} for user {cognito_username}')
			db_conn.conn.rollback()
			raise Exception('Could not insert photo.')

def set_board_photo_status(photo_key, join_code, board_photo_status):
	with db_conn.get_cursor() as cursor:
		cursor.execute(	'''
						UPDATE board_photo_map m
						JOIN photo p ON p.photo_id = m.photo_id
						JOIN board b ON b.board_id = m.board_id
						SET m.board_photo_map_status_id = %s
						WHERE p.photo_key = UUID_TO_BIN(%s)
							AND b.join_code = UUID_TO_BIN(%s)
						''',
						(board_photo_status.value, str(photo_key), str(join_code)))
		db_conn.conn.commit()

def get_photos_for_board(join_code):
	with db_conn.get_cursor() as cursor:
		cursor.execute(	'''
						SELECT BIN_TO_UUID(p.photo_key) FROM board b
						JOIN board_photo_map bp ON b.board_id = bp.board_id
						JOIN photo p ON bp.photo_id = p.photo_id
						WHERE b.join_code=UUID_TO_BIN(%s)
						''',
						str(join_code))
		results = cursor.fetchall()
		detupled_results = [photo_key for photo_key, in results]
		db_conn.conn.commit()
		return detupled_results

def get_board_owner_username(join_code):
	with db_conn.get_cursor() as cursor:
		cursor.execute(	'''
						SELECT BIN_TO_UUID(p.cognito_username) FROM board b
						JOIN person p ON b.owner_id = p.person_id
						WHERE b.join_code = UUID_TO_BIN(%s)
						''',
						(join_code))
		results = cursor.fetchone()
		db_conn.conn.commit()
		if not results:
			return None
		else:
			return results[0]

def get_connections_for_board(join_code):
	with db_conn.get_cursor() as cursor:
		cursor.execute(	'''
			SELECT bc.ws_connection_id FROM board b
			JOIN board_connection bc ON bc.board_id = b.board_id
			WHERE
				b.join_code = UUID_TO_BIN(%s)
				AND bc.board_connection_status_id = 1 # CONNECTED
			''',
			join_code)

		results = cursor.fetchall()
		detupled_results = [photo_key for photo_key, in results]
		db_conn.conn.commit()
		return detupled_results

def get_first_succeeded_payment_id_for_user(cognito_username):
	with db_conn.get_cursor() as cursor:
		person_id = _get_person_id_for_username(cursor, cognito_username)
		cursor.execute(	'''
						SELECT payment_id FROM payment
						WHERE person_id=%s
							AND payment_status_id=2 -- SUCCEEDED
						LIMIT 1
						''',
						(person_id))
		results = cursor.fetchone()
		db_conn.conn.commit()
		if not results:
			return None
		else:
			return results[0]

def update_payment_status(payment_id, new_status):
	with db_conn.get_cursor() as cursor:
		cursor.execute(	'''
						UPDATE payment
						SET payment_status_id=%s
						WHERE payment_id=%s
						''',
						(new_status.value, payment_id))
		db_conn.conn.commit()

def _create_photo(cursor, person_id, photo_key, s3_bucket_name, s3_object_key):
	cursor.execute(	'''
					INSERT INTO photo (uploader_id, photo_key, s3_bucket_name, s3_object_key, upload_date)
					VALUES (%s, UUID_TO_BIN(%s), %s, %s, NOW());
					''',
					(person_id, photo_key, s3_bucket_name, s3_object_key))
	return cursor.lastrowid

def _create_mapping(cursor, board, photo_id, board_photo_status):
	cursor.execute(	'''
					INSERT INTO board_photo_map (board_id, photo_id, board_photo_map_status_id, add_date)
					VALUES (%s, %s, %s, NOW())
					''',
					(board.board_id, photo_id, board_photo_status.value))

def _get_board_by_join_code(cursor, join_code):
	cursor.execute(	'''
					SELECT board_id, owner_id, board_name, BIN_TO_UUID(join_code), board_status_id, board_type_id, start_date, end_date
					FROM board
					WHERE join_code=UUID_TO_BIN(%s)
					''',
					(join_code,))
	board = cursor.fetchone()
	if not board:
		logger.error('No board found for join code: ' + str(join_code))
		return None
	else:
		return _board_tuple_to_board(board)

def _get_person_id_for_username(cursor, cognito_username):
	if not cognito_username:
		return None

	cursor.execute(	'''
					SELECT person_id
					FROM person
					WHERE person.cognito_username = UUID_TO_BIN(%s)''',
					(cognito_username,))
	person_id = cursor.fetchone()
	return person_id

def _board_tuple_to_board(board_tuple):
	board_id, owner_id, board_name, join_code, board_status_id, board_type_id, start_date, end_date = board_tuple
	return Board(board_id, owner_id, board_name, join_code, BoardStatus(board_status_id), BoardType(board_type_id), start_date, end_date)


# STEP4: TSR FINDING ALGORITHM from Rocky which I have modified slightly

from collections import defaultdict

def run_step_four(step_three_file, window_size, chromosome_sizes, output_filename):
    fi = open(step_three_file, 'r')

    DDCHRSIZE = chromosome_sizes

    id_to_process = '1'
    lines_to_process = []
    OFILE = open(output_filename, 'w')
    STEP = window_size

    def TSRF(LIST, STEPSIZE):
        k = 0
        TSR = []

        append_last = True

        while repr(k) != repr(len(LIST)):
            DDL = defaultdict(list)
            for f in LIST:
                DATA = f
                TMP = DATA[0].strip() + ':' + DATA[1].strip() + '-' + DATA[2].strip()
                DDL[TMP] = DATA
            REMOVE = set()
            try:
                MAX = LIST[0]
            except IndexError:
                append_last = False
                break

            for l in LIST[1:]:
                if len(range(max(int(l[1]), int(MAX[1])), min(int(l[2]), int(MAX[2])))) > 0 and int(l[4]) > int(MAX[4]):
                    MAX = l
                elif len(range(max(int(l[1]), int(MAX[1])), min(int(l[2]), int(MAX[2])))) < 1:
                    TSR.append(MAX)
                    MAX = l
            TSR.append(MAX)
            REMOVE = [rn[0].strip() + ':' + '-'.join([repr(nr), repr(nr + STEPSIZE)]).strip() for rn in TSR for nr in
                      range((int(rn[1]) + 1) - STEPSIZE, int(rn[2]))]
            k = len(LIST)
            LIST = [[int(DDL[ls][1]), DDL[ls]] for ls in set(DDL.keys()).difference(REMOVE)]
            LIST.sort(key=lambda x: x[0])
            LIST = [sl[1] for sl in LIST]

        if append_last:
            try:
                TSR.append(MAX)
            except UnboundLocalError:
                pass

        TSR = set(['\t'.join(ts).strip() for ts in TSR])
        TSR = [[int(srrt.strip().split('\t')[1]), srrt.strip()] for srrt in list(TSR)]
        TSR.sort(key=lambda x: x[0])
        TSR = [w[1].strip() for w in TSR]
        return TSR

    while True:
        raw_line = fi.readline()
        # check whether we're at eof
        if not raw_line:
            break
        # get line
        line = raw_line.rstrip().split("\t")
        id = line[0].strip()
        strand = line[-1].strip()
        # same id
        if id == id_to_process.strip():
            lines_to_process.append(line)
        # a new id is coming
        else:
            # do something with your lines
            if len(lines_to_process) > 0:
                for tsrf in TSRF(lines_to_process, STEP):
                    CHECKTSRBUNDRY = tsrf.strip().split('\t')
                    if DDCHRSIZE[CHECKTSRBUNDRY[0].strip()] > 0 and int(CHECKTSRBUNDRY[2]) <= DDCHRSIZE[
                        CHECKTSRBUNDRY[0].strip()]:
                        OFILE.write(tsrf.strip() + '\n')
            # now proceed with next id
            id_to_process = id.strip()
            lines_to_process = [line]

    for tsrl in TSRF(lines_to_process, STEP):
        CHECKTSRBUNDRY = tsrl.strip().split('\t')
        if DDCHRSIZE[CHECKTSRBUNDRY[0].strip()] > 0 and int(CHECKTSRBUNDRY[2]) <= DDCHRSIZE[CHECKTSRBUNDRY[0].strip()]:
            OFILE.write(tsrl.strip() + '\n')
    OFILE.close()


#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Built-in imports
import itertools

# 3rd party imports
import numpy as np
import xarray as xr

__author__ = "Louis Richard"
__email__ = "louisr@irfu.se"
__copyright__ = "Copyright 2020-2023"
__license__ = "MIT"
__version__ = "2.4.2"
__status__ = "Prototype"

def _idx_closest(lst0, lst1):
    return [(np.abs(np.asarray(lst0) - k)).argmin() for k in lst1]

def eis_spec_combine_sc(omni_vars, method: str = "mean"):
    r"""Combines omni-directional energy spectrogram variable from EIS on
    multiple MMS spacecraft.

    Parameters
    ----------
    omni_vars : list of xarray.DataArray
        Omni-directional energy spectrograms of all spacecraft.
    method : str, Optional
        Method to combine spectra, "mean" or "sum"

    Returns
    -------
    omni_spec : xarray.DataArray
        Combined omni-directional energy spectrogram.

    See Also
    --------
    pyrfu.mms.get_eis_allt, pyrfu.mms.eis_omni, pyrfu.mms.eis_pad_combine_sc

    Examples
    --------
    >>> from pyrfu.mms import get_eis_allt, eis_omni, eis_spec_combine_sc

    Define time interval

    >>> tint = ["2017-07-23T16:10:00", "2017-07-23T18:10:00"]

    Load EIS ExTOF flux spectrograms for all 6 telescopes for all spacecraft

    >>> extof_allt_mms = []
    >>> for ic in range(2, 5):
    ...     extof_allt_mms.append(get_eis_allt("flux_extof_proton_srvy_l2",
    ...                             tint, ic))

    Compute the omni-direction flux spectrogram for all spacecraft

    >>> extof_omni_mms = []
    >>> for extof_allt in extof_allt_mms:
    ...     extof_omni_mms.append(eis_omni(extof_allt))

    Combine spectrograms of all spacecraft

    >>> extof_omni_mmsx = eis_spec_combine_sc(extof_omni_mms)

    """

    assert method.lower() in ["mean", "sum"]

    reftime_sc_loc = np.argmin([len(x_.time.data) for x_ in omni_vars])
    refener_sc_loc = np.argmin([len(x_.energy.data) for x_ in omni_vars])

    time_refprobe = omni_vars[reftime_sc_loc]
    ener_refprobe = omni_vars[refener_sc_loc]

    nt_ref, ne_ref = [time_refprobe.shape[0], ener_refprobe.shape[1]]

    # time x energy x spacecraft
    omni_spec_data = np.empty([nt_ref, ne_ref, len(omni_vars)])
    omni_spec_data[:] = np.nan
    # time x energy
    omni_spec = np.empty([nt_ref, ne_ref])
    omni_spec[:] = np.nan

    # energy_data = np.zeros([ne_ref, len(omni_vars)])

    # Average omni flux over all spacecraft and define common energy grid
    for i_p, flux_ in enumerate(omni_vars):
        idx_closest = _idx_closest(
            flux_.energy.data,
            ener_refprobe.energy.data,
        )
        # energy_data[:, pp] = flux_.energy.data[0:ne_ref]
        omni_spec_data[0:nt_ref, :, i_p] = flux_.data[0:nt_ref, idx_closest]

    # Average omni flux over all spacecraft
    for i_t, i_e in itertools.product(range(nt_ref), range(ne_ref)):
        if method.lower() == "mean":
            omni_spec[i_t, i_e] = np.nanmean(
                omni_spec_data[i_t, i_e, :],
                axis=0,
            )
        else:
            omni_spec[i_t, i_e] = np.nansum(
                omni_spec_data[i_t, i_e, :],
                axis=0,
            )

    omni_spec = xr.DataArray(
        omni_spec,
        coords=[time_refprobe.time.data, ener_refprobe.energy.data],
        dims=["time", "energy"],
    )
    omni_spec.attrs["energy_dplus"] = ener_refprobe.attrs["energy_dplus"]
    omni_spec.attrs["energy_dminus"] = ener_refprobe.attrs["energy_dminus"]

    return omni_spec


import sys
input = sys.stdin.readline
import collections
from collections import deque

lst = deque()
def push(n):
    lst.append(n)

def pop():
    if len(lst) == 0:
        print(-1)
    else:
        print(lst.popleft())

def size():
    print(len(lst))

def empty():
    if len(lst) == 0:
        print(1)
    else:
        print(0)

def front():
    if len(lst) == 0:
        print(-1)
    else:
        print(lst[0])

def back():
    if len(lst) == 0:
        print(-1)
    else:
        print(lst[-1])

i = int(input())
for _ in range(i):
    com = input().rsplit()
    if com[0] == 'pop':
        pop()
    elif com[0]  == 'front':
        front()
    elif com[0]  == 'back':
        back()
    elif com[0]  == 'size':
        size()
    elif com[0]  == 'empty':
        empty()
    else:
        push(com[1])


#_*_ coding:utf-8 _*_

# prepapre data
data1=np.genfromtxt('recipe_loss_posterior8.csv',delimiter=',')
data1=np.hstack((data1[:,0].reshape(-1,1),data1[:,3].reshape(-1,1),data1[:,5].reshape(-1,1)))

df=pd.DataFrame(data1)
df=df.sort_values(by=[2])
df=df.drop_duplicates(subset=[0,1], keep='first')
data1=df.values

x=data1[:,0]
y=data1[:,1]
z=data1[:,2]

# plotting
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np

np.random.seed(19680801)
npts = 200
ngridx = 200
ngridy = 200
'''
x = np.random.uniform(-2, 2, npts)
y = np.random.uniform(-2, 2, npts)
z = x * np.exp(-x**2 - y**2)
'''

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (5,4.1)

fig, (ax1) = plt.subplots(nrows=1)
# -----------------------
# Interpolation on a grid
# -----------------------
# A contour plot of irregularly spaced data coordinates
# via interpolation on a grid.

# Create grid values first.
xi = np.linspace(0, 45, ngridx)
yi = np.linspace(0.5, 20, ngridy)

# Perform linear interpolation of the data (x,y)
# on a grid defined by (xi,yi)
triang = tri.Triangulation(x, y)
interpolator = tri.LinearTriInterpolator(triang, z)
Xi, Yi = np.meshgrid(xi, yi)
zi = interpolator(Xi, Yi)

# Note that scipy.interpolate provides means to interpolate data on a grid
# as well. The following would be an alternative to the four lines above:
#from scipy.interpolate import griddata
#zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='linear')

ax1.contour(xi, yi, zi,levels=14,linestyles='dashed',linewidths=0.6,colors='white')
cntr1 = ax1.contourf(xi, yi, zi, levels=np.linspace(0,1,100), cmap="plasma")

#fig.colorbar(cntr1, ax=ax1)
#fig.colorbar(cntr1, boundaries=np.linspace(0, 1, 10),ticks=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1],)
a=fig.colorbar(cntr1, boundaries=np.linspace(0, 1, 10),ticks=[0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1],)
a.ax.get_yaxis().labelpad = 10
a.ax.set_ylabel('Loss', rotation=90)

#ax1.plot(x, y, 'ko', ms=2,color='r')
ax1.set(xlim=(4, 45), ylim=(0.5, 20))

plt.setp(ax1.get_yticklabels(), visible=False)
#plt.setp(ax1.get_xticklabels(), visible=False)

plt.yticks([])

plt.xticks([10,20,30,40])

ax1.set(xlabel='QAgNO3(%)')

#ax1.set_title('Run 8')

plt.show()


import nltk
from nltk.translate import AlignedSent
from nltk.translate.ibm1 import IBMModel1

# 示例双语语料库
bitext = []
bitext.append(AlignedSent(['I', 'love', 'machine', 'learning'], ['我', '喜欢', '机器学习']))
bitext.append(AlignedSent(['Statistical', 'models', 'are', 'useful'], ['统计', '模型', '很', '有用']))

# 训练IBM Model 1模型
ibm1 = IBMModel1(bitext, 5)

# 测试翻译
source_sentence = ['I', 'love', 'machine', 'learning']
target_sentence = ibm1.align(source_sentence)
print('Source Sentence:', ' '.join(source_sentence))
print('Translated Sentence:', ' '.join(target_sentence))

Statistical Machine Translation SMT/example.py


from django.contrib import admin
from .models import Goods
from django.contrib.auth.models import User, Group

admin.site.unregister(User)
admin.site.unregister(Group)

@admin.register(Goods)
class GoodsAdmin(admin.ModelAdmin):
    list_display = ('image_tag', 'slug', 'sale_price', 'created_date', 'sales')
    list_filter = ('author', 'created_date', 'sale_price', 'sales')
    fields = ['author', 'slug', 'title', 'description', ('pln_price', 'uah_price', 'sale_price'), ('sales', 'image')]
    search_fields = ('slug', 'title', 'author')
    readonly_fields = ["image_tag"]


class Fraction:
    def __init__(self, initNum, initDenom=None):
        if initDenom != 0:
            self.num = initNum
            self.denom = initDenom
        else:
            self.num = initNum
            self.denom = 1
            print("Zero cannot be the denominator.")
            print("fraction", str(initNum)+"/0 was converted to:", str(initNum)+"/1")

    def __str__(self):
        if self.denom == None:
            return str(self.num)
        else:
            return str(self.num)+"/"+str(self.denom)

    def getNum(self):
        return self.num

    def getDenom(self):
        if self.denom == None:
            return 1
        else:
            return self.denom

    def __add__(self, other):
        d1 = self.getDenom()
        d2 = other.getDenom()
        Newd = d1 * d2
        Newn = ((other.getDenom() * self.getNum()) + (self.getDenom() * other.getNum()))
        New = Fraction(Newn, Newd)
        good = New.Simplify()
        return good

    def Simplify(self):
        n = self.getNum()
        d = self.getDenom()
        factor = self.SharedFactor()
        if n == d:
            One = Fraction(1)
            return One
        elif (n/d)%1 == 0:
            return int(n/d)
        elif (d/n)%1 == 0:
            good = Fraction(1, int(d/n))
            return good
        elif factor > 1:
            new = Fraction(int(n/factor), int(d/factor))
            return new
        else:
            return self

    def SharedFactor(self):
        n = self.getNum()
        d = self.getDenom()
        factor = 1
        for i in range(max(n, d), 1, -1):
            if (n%i == 0) and (d%i == 0):
                if i > factor:
                    factor = i
        return factor

    def Reciprocal(self):
        n = self.getNum()
        d = self.getDenom()
        New = Fraction(d, n)
        return New

a = Fraction(1,2)
b = Fraction(1)
c = Fraction(3,4)
d = Fraction(100, 20)
print(a + b)
print(a + c)
print(a + a)
print(c.Reciprocal())
print(d, d.Simplify(), d.Reciprocal(), (d.Reciprocal()).Simplify())
e = Fraction(8, 0)
print(e + b)


from tkinter import filedialog
from tkinter import *
import cv2
import os
root = Tk()

root.title('아스키코드로 변환')

root.geometry('1000x800')

def img_path():
    root.file = filedialog.askopenfile(title='파일을 선택하세요')
    txt.configure(text='경로: ' + root.file.name)

def img_ascll():
    chars = ' .,-~:;=!*#%@'
    nw = 100
    img = cv2.imread(root.file.name)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    h, w = img.shape
    nh = int(h / w * nw)
    img = cv2.resize(img, (nw * 2, nh))
    del_path = str(root.file.name).split('/')

    for i in del_path:
        del_path = i

    re_img = open('/Users/dotslashdash/Downloads/'+del_path[:-3]+'txt', 'w')
    for row in img:
        for pixel in row:
            index = int(pixel / 256 * len(chars))
            re_img.write(chars[index])
        re_img.write('\n')

# 아스키코드 변환 버튼
path_button = Button(root, text='아스키코드로 변환', width=15, command=img_ascll)
path_button.pack(side='bottom')

# 파일 버튼 생성
path_button = Button(root, text='파일 선택', width=15, command=img_path)
path_button.pack(side='bottom')

# 파일 경로
txt = Label(root, text="경로:")
txt.pack(side='bottom')

# GUI 실행
root.mainloop()


import uuid
import typing as t
from fastapi import status
from tortoise.expressions import Q
from fermerce.core.enum.sort_type import SortOrder
from fermerce.core.schemas.response import ITotalCount
from fermerce.core.services.base import filter_and_list
from fermerce.lib.errors import error
from fermerce.app.status import schemas, models
from fastapi import Response

# create permission
async def create(
    data_in: schemas.IStatusIn,
) -> models.Status:
    check_status = await models.Status.get_or_none(name=data_in.name)
    if check_status:
        raise error.DuplicateError("status already exists")
    new_type = await models.Status.create(**data_in.dict())
    if not new_type:
        raise error.ServerError("Internal server error")
    return new_type

async def get(
    status_id: uuid.UUID,
) -> models.Status:
    perm = await models.Status.get_or_none(id=status_id)
    if not perm:
        raise error.NotFoundError("status not found")
    return perm

# # get all permissions
async def filter(
    filter_string: str,
    per_page: int = 10,
    page: int = 0,
    select: str = "",
    sort_by: SortOrder = SortOrder.asc,
    order_by: str = None,
) -> t.List[models.Status]:
    query = models.Status.filter(Q(name__icontains=filter_string))
    result = await filter_and_list(
        model=models.Status,
        query=query,
        per_page=per_page,
        page=page,
        order_by=order_by,
        select=select,
        sort_by=sort_by,
    )
    return result

async def get_total_count() -> ITotalCount:
    total = await models.Status.all().count()
    return ITotalCount(count=total).dict()

# # update permission
async def update(
    status_id: uuid.UUID,
    data_in: schemas.IStatusIn,
) -> models.Status:
    check_status = await models.Status.get_or_none(id=status_id)
    if not check_status:
        raise error.NotFoundError("status does not exist")
    check_name = await models.Status.get_or_none(name=data_in.name)
    if check_name and check_name.id != status_id:
        raise error.DuplicateError("status already exists")
    elif check_name and check_name.id == status_id:
        return check_status
    check_status.update_from_dict(data_in.dict())
    await check_status.save()
    return check_status

# # delete permission
async def delete(
    status_id: uuid.UUID,
) -> None:
    deleted_status = await models.Status.filter(id=status_id).delete()
    if not deleted_status:
        raise error.NotFoundError("status does not exist")
    return Response(status_code=status.HTTP_204_NO_CONTENT)


import cv2
import numpy as np
import numpy

image1 = cv2.imread("/home/wang_shuai/Assignment-4-Material/Left.jpg")
image2 = cv2.imread("/home/wang_shuai/Assignment-4-Material/Right.jpg")

# kp1 = np.array([kp1[g.queryIdx].pt for g in good])
# kp2 = np.array([kp2[g.trainIdx].pt for g in good])

def perpare2d(path):
    x,y = [],[]
    with open(path, "r") as file:
        x = file.readline().split(", ")
        y = file.readline().split(", ")
    x = [float(x_) for x_ in x]
    y = [float(y_) for y_ in y]
    x = numpy.array(x, dtype=numpy.float)
    y = numpy.array(y, dtype=numpy.float)

    return numpy.stack([x,y],axis=1)
kp1 = perpare2d("Homopoint2d_Left.txt")
kp2 = perpare2d("Homopoint2d_Right.txt")
# 可视化
h,w,c= image1.shape
img3 = numpy.zeros([h,w*2,c], dtype=np.uint8)
img3[:, 0:w] = image1
img3[:,w:2*w] = image2

for i in range(6):
    x1 = int(kp1[i][0])
    y1 = int(kp1[i][1])
    x2 = int(kp2[i][0])+w
    y2 = int(kp2[i][1])
    cv2.line(img3, (x1,y1), (x2,y2), (100,200,100), 2)

cv2.imshow("match", img3)
cv2.waitKey()
#

def solve(kp1, kp2):
    n,_ = kp1.shape
    A = np.zeros([n*2,9])
    for i in range(n):
        A[2*i,0:2] = kp1[i]
        A[2*i,2] = 1
        A[2*i,6:8] = -kp1[i]*kp2[i,0]
        A[2*i,8] = -kp2[i][0]

        A[2*i+1,3:5] = kp1[i]
        A[2*i+1,5] = 1
        A[2*i+1,6:8] = -kp1[i]*kp2[i,1]
        A[2*i+1,8] = -kp2[i][1]
    ATA = np.matmul(np.transpose(A), A)
    eig, eigx = np.linalg.eig(ATA)
    eigx = eigx[:,eig.argmin()]
    eigx = eigx / eigx[-1]
    return eigx.transpose()

x = solve(kp1, kp2)

x = x.reshape(3,3)
print("using my:")
print(x)
# print(kp2[0])

t =  np.array([kp1[0][0],kp1[0][1],1])
y = np.matmul(x,t)
# print(y / y[2])

homo,_  = cv2.findHomography(kp1,kp2,0)
print("using opencv:")
print(homo)
# y = np.matmul(homo,t)
# print(y/y[-1])


import os
import sys
import json

from collections import OrderedDict

EMOJI_MODIFIER_BASE = {
  '1f590', '1f468', '1f46e', '1f595', '1f3c3', '1f935', '1f646', '1f449',
  '1f477', '1f91c', '1f486', '1f6b6', '1f919', '1f930', '1f44b', '1f933',
  '1f6b5', '270b', '1f483', '1f64b', '1f470', '270a', '1f443', '1f918',
  '1f448', '1f471', '1f474', '1f467', '26f9', '1f44f', '1f93e', '1f6cc',
  '1f481', '1f485', '1f4aa', '1f596', '1f47c', '1f487', '1f44c', '1f476',
  '261d', '1f934', '1f385', '270c', '1f3c4', '1f64f', '1f645', '1f91e',
  '1f926', '270d', '1f647', '1f3c2', '1f6a3', '1f574', '1f3cc', '1f44a',
  '1f57a', '1f3ca', '1f450', '1f442', '1f91a', '1f93d', '1f472', '1f64d',
  '1f482', '1f3c7', '1f64c', '1f6b4', '1f938', '1f3cb', '1f936', '1f44d',
  '1f469', '1f937', '1f64e', '1f91b', '1f478', '1f447', '1f466', '1f44e',
  '1f575', '1f446', '1f6c0', '1f473', '1f939', '1f475', '1f93c'}

class EmojiDictionary:

  def __init__(self):
    self.emoji = self.__load()

  def search(self, search_term, max_items=None):
    term = search_term.lower()

    if term:
      matches = []
      for emoji in self.emoji:
        if term in emoji['description']:
          matches.append(emoji)

          if max_items and len(matches) >= max_items:
            break

      return matches
    else:
      if max_items:
        return self.emoji[:max_items]
      else:
        return self.emoji

  def __load(self):

      with open(os.path.join(os.path.dirname(__file__), 'emoji.json')) as emoji_json:
        emoji_raw = json.loads(
          emoji_json.read(), object_pairs_hook=OrderedDict)

      emojis = []

      base_props = {}
      for emoji in emoji_raw:
        category = emoji_raw[emoji]['category']
        if emoji in EMOJI_MODIFIER_BASE:
          base_props[emoji] = emoji_raw[emoji]

        if '-' in emoji:
          main_codepoint = emoji.split('-')[0]

          if main_codepoint in EMOJI_MODIFIER_BASE:
            shortname = base_props[main_codepoint]['shortname']
            description = (base_props[main_codepoint]['name']
                    + '. Keywords:'
                    + ' '.join(
                      base_props[main_codepoint]['keywords']))
          else:
            shortname = emoji_raw[emoji]['shortname']
            description = (emoji_raw[emoji]['name']
                    + '. Keywords: '
                    + ' '.join(emoji_raw[emoji]['keywords']))
        else:
          shortname = emoji_raw[emoji]['shortname']
          description = (emoji_raw[emoji]['name']
                  + '. Keywords: '
                  + ' '.join(emoji_raw[emoji]['keywords']))

        path = os.path.join(
            os.path.dirname(__file__),
            'emojitwo/png/' +
            emoji + '.png')

        if os.access(path, os.F_OK):
          emojis.append({
            'path': path,
            'name': shortname,
            'category': category,
            'emoji': emoji,
            'description': description
          })

      return emojis


#python videoPlayBackFromFiles.py --folderPath ZakiBashakha

import numpy as np
import os
import six.moves.urllib as urllib
import sys
import tarfile
import zipfile

from collections import defaultdict
from io import StringIO
from matplotlib import  pyplot  as plt
from PIL import Image
import cv2
import argparse

def  showVideofromFrames():
    		frameNum=1
    		for filename in imgFiles:
    			print(filename)
    			img = cv2.imread(os.path.join(folderPath,filename))
    			#img = cv2.resize(img, (width, height))
    			if (img is None):
    				frameNum=frameNum+1
    				continue
    			img=cv2.resize(img,(width,height))
    			video_creator.write(img)
    			cv2.imshow(folderPath,img)
				#if (frameNum==1):
					#raw_input("press any key to continue")
    			cv2.waitKey(1)
    			frameNum=frameNum+1
    			#out.write(img)
    			if cv2.waitKey(1) & 0xFF == ord('q'):
    				break

#fourcc = cv2.VideoWriter_fourcc(*'XVID')
#out = cv2.VideoWriter("Detect_HardHat.m4v",fourcc, 5, (1152,648))
    #read the arguments

if __name__ == "__main__":

    ap = argparse.ArgumentParser()
    ap.add_argument("--folderPath", required=True,help="path to frames  of video")

    args = vars(ap.parse_args())
    folderPath=args["folderPath"]

    scaleFactor=0.6
    width=1280
    height=720
    width=int(width*scaleFactor)
    height=int(height*scaleFactor)
    filenamesList=os.listdir(folderPath)
    fourcc = cv2.VideoWriter_fourcc(*'XVID')
    fileName="demo.mp4"

    video_creator = cv2.VideoWriter(fileName,fourcc, 2, (width,height))
    imgFiles=os.listdir(folderPath)
    imgFiles.sort()
    imgFiles=sorted(os.listdir(folderPath))

    showVideofromFrames()
    video_creator.release()
    print("[INFO] Video file created  and saved to {}".format(fileName))


#!/usr/bin/env python
# -*- coding:Utf-8 -*-

from flask import request
from flask import session
from flask import redirect
from flask import url_for
from flask import Blueprint
from flask import render_template

from steamcommerce_api.api import user
from steamcommerce_api.api import steam
from steamcommerce_api.api import userrequest
from steamcommerce_api.api import paidrequest
from steamcommerce_api.api import testimonial
from steamcommerce_api.api import notification
from steamcommerce_api.api import creditrequest

import re
import config
import datetime

from oid import oid
from forms import user as user_form
from utils import route_decorators

user_view = Blueprint('views.user', __name__)

@user_view.route('/user/<username>')
@route_decorators.is_logged_in
@route_decorators.is_admin
def user_admin_profile(username):
    try:
        user_data = user.User().get_by_username(username)
    except user.User().model.DoesNotExist:
        error = {
            'title': 'Usuario inexistente',
            'content': 'El usuario no existe :('
        }

        return render_template('views/error.html', **error)

    notifications = notification.Notification().get_for_user(user_data['id'])

    userrequests = userrequest.UserRequest().get_by_user_id(
        user_data['id']
    )

    creditrequests = creditrequest.CreditRequest().get_by_user_id(
        user_data['id']
    )

    paidrequests = paidrequest.PaidRequest().get_by_user_id(
        user_data['id']
    )

    spent_incomes = user.User().get_user_spent_incomes(user_data['id'])

    register_delta = datetime.datetime.now() - (
        user_data.get('register_date') or datetime.datetime(year=2012, month=8, day=1)
    )

    form = user_form.ProfileForm(obj=user_data)

    params = {
        'form': form,
        'user': user_data,
        'userrequests': userrequests,
        'paidrequests': paidrequests,
        'notifications': notifications,
        'creditrequests': creditrequests,
        'spent_incomes': spent_incomes,
        'register_delta': register_delta
    }

    return render_template('views/user/profile.html', **params)

@user_view.route('/login')
@user_view.route('/login/')
@route_decorators.not_logged_in
@oid.loginhandler
def user_login():
    return oid.try_login(config.STEAM_OPENID_URL)

@user_view.route('/registro', methods=['GET', 'POST'])
@user_view.route('/registro/', methods=['GET', 'POST'])
@route_decorators.is_logged_in
@route_decorators.has_no_email
def user_register():
    user_id = session.get('user')
    curr_user = user.User().get_by_id(user_id)

    if request.method == 'GET':
        form = user_form.RegisterForm()

        return render_template(
            'views/user/register.html',
            user=curr_user,
            form=form
        )
    elif request.method == 'POST':
        form = user_form.RegisterForm(request.form)

        if not form.validate():
            return render_template(
                'views/user/register.html',
                user=curr_user,
                form=form
            )

        user.User().set_email(user_id, None, form.email.data)
        session['email'] = form.email.data

        return redirect(url_for('views.store.store_catalog'))

@user_view.route('/logout')
@user_view.route('/logout/')
@route_decorators.is_logged_in
def user_logout():
    try:
        session.pop('user')
    except:
        pass

    try:
        session.pop('admin')
    except:
        pass

    return redirect(url_for('views.store.store_catalog'))

@user_view.route('/perfil', methods=['GET', 'POST'])
@route_decorators.is_logged_in
def user_profile():
    user_id = session.get('user')
    user_data = user.User().get_by_id(user_id)

    notifications = notification.Notification().get_user_top_notifications(
        user_id
    )

    userrequests = userrequest.UserRequest().get_by_user_id(user_id)
    creditrequests = creditrequest.CreditRequest().get_by_user_id(user_id)
    paidrequests = paidrequest.PaidRequest().get_by_user_id(user_id)

    params = {
        'user': user_data,
        'userrequests': userrequests,
        'paidrequests': paidrequests,
        'notifications': notifications,
        'creditrequests': creditrequests
    }

    if request.method == 'GET':
        form = user_form.ProfileForm(obj=user_data)
        params.update({'form': form})

    elif request.method == 'POST':
        form = user_form.ProfileForm(request.form)
        params.update({'form': form})

        if form.validate():
            if user_data['email'] != form.email.data:
                user.User().set_email(
                    user_id,
                    user_data['email'],
                    form.email.data
                )

            name = form.name.data
            last_name = form.last_name.data

            if (
                user_data['name'] != name or
                user_data['last_name'] != last_name
            ):
                user.User().set_name(user_id, name, last_name)

    return render_template('views/user/profile.html', **params)

@user_view.route('/historial/<custom_id:history_identifier>')
@route_decorators.is_logged_in
def user_history(history_identifier):
    user_id = session.get('user')

    request_type = history_identifier['type']
    request_id = int(history_identifier['number'])

    incorrect_request = {
        'title': 'El pedido no corresponde a este usuario',
        'content': u'El pedido no está asociado a esta cuenta'
    }

    if request_type == 'A':
        try:
            userrequest_data = userrequest.UserRequest().get_id(request_id)
        except userrequest.UserRequest().model.DoesNotExist:
            return render_template('views/error.html', **incorrect_request)

        if userrequest_data['user']['id'] != user_id:
            return render_template('views/error.html', **incorrect_request)

        params = {
            'request_type': request_type,
            'request_id': request_id,
            'userrequest': userrequest_data
        }

        return render_template(
            'views/user/user-history.html',
            **params
        )
    elif request_type == 'B':
        try:
            creditrequest_data = creditrequest.CreditRequest().get_id(
                request_id
            )
        except creditrequest.CreditRequest().model.DoesNotExist:
            return render_template('views/error.html', **incorrect_request)

        if creditrequest_data['user']['id'] != user_id:
            return render_template('views/error.html', **incorrect_request)

        params = {
            'request_type': request_type,
            'request_id': request_id,
            'creditrequest': creditrequest_data
        }

        return render_template(
            'views/user/user-history.html',
            **params
        )
    elif request_type == 'C':
        try:
            paidrequest_data = paidrequest.PaidRequest().get_id(request_id)
        except paidrequest.PaidRequest.DoesNotExist:
            return render_template('views/error.html', **incorrect_request)

        if paidrequest_data['user']['id'] != user_id:
            return render_template('views/error.html', **incorrect_request)

        params = {
            'request_type': request_type,
            'request_id': request_id,
            'paidrequest': paidrequest_data
        }

        return render_template(
            'views/user/user-history.html',
            **params
        )

@user_view.route('/notifications/seen/')
@route_decorators.is_logged_in
@route_decorators.as_json
def user_notifications_seen():
    user_id = session.get('user')
    notification.Notification().update_seen(user_id)

    return {'success': True}

@user_view.route('/testimonios/nuevo')
@route_decorators.is_logged_in
def user_testimonials_new():
    return redirect('/')

@user_view.route('/testimonial/skip/', methods=['POST'])
@route_decorators.is_logged_in
@route_decorators.as_json
def user_testimonial_skip():
    user_id = session.get('user')
    testimonial_id = request.form.get('testimonial_id')

    if not testimonial_id:
        return ({'success': False}, 500)

    pending_testimonials = testimonial.Testimonial().get_unsubmited(
        user_id,
        excludes=['all']
    )

    testimonial_id = int(testimonial_id)

    if testimonial_id not in [x['id'] for x in pending_testimonials]:
        return ({'success': False}, 500)

    testimonial.Testimonial().update(**{
        'id': testimonial_id,
        'visible': False
    })

    return {'success': True}

@user_view.route('/testimonial/submit/', methods=['POST'])
@route_decorators.is_logged_in
@route_decorators.as_json
def user_testimonial_submit():
    return {'success': True}

@user_view.route('/wishlist')
@route_decorators.is_logged_in
def user_wishlist():
    return redirect('/')

@user_view.route('/wishlist/retry')
@route_decorators.is_logged_in
def user_wishlist_retry():
    return redirect(url_for('views.user.user_wishlist'))

@user_view.route('/user/cart/')
@route_decorators.is_logged_in
def user_cart():
    return ''

@user_view.route('/user/notifications/')
@route_decorators.is_logged_in
def user_notifications():
    user_id = session.get('user')

    notifications = notification.Notification().get_user_top_notifications(
        user_id,
        excludes=[
            'all',
        ]
    )

    params = {
        'notifications': notifications
    }

    return render_template(
        'views/user/nav-notifications.html',
        **params
    )

@oid.after_login
def steam_after_login(resp):
    user_steam_id = re.findall(
        config.STEAM_IDENTITY_URL_REGEX,
        resp.identity_url,
        re.DOTALL
    )

    if len(user_steam_id) < 1:
        # TODO: Log event

        return redirect(url_for('views.store.store_catalog'))

    try:
        steam_user = user.User().get_by_steam64(user_steam_id[0])
    except user.User().model.DoesNotExist:
        ip_address = request.headers.get(
            'CF-Connecting-IP',
            request.remote_addr
        )

        user_id = user.User().register(user_steam_id[0], ip_address)

        session['user'] = user_id
        session['email'] = None

        return redirect(url_for('views.user.user_register'))

    if not steam_user.email or len(steam_user.email) < 1:
        session['user'] = steam_user.id
        session['email'] = None

        return redirect(url_for('views.user.user_register'))

    if steam_user.is_banned:
        return render_template(
            'views/user/banned.html',
            user=steam_user
        )

    session['user'] = steam_user.id
    session['email'] = steam_user.email

    if steam_user.admin:
        session['admin'] = True

    player_info = steam.Steam().get_player_summaries(user_steam_id[0])

    if player_info:
        user.User().update(**{
            'id': steam_user.id,
            'avatar_url': player_info.get('avatarfull')
        })

    return redirect(
        request.args.get(
            'next',
            url_for('views.store.store_catalog')
        )
    )


from .ckan import CKANInstance
from .data_dictionaries import DATA_DICTIONARY

def dict_to_ckan(request):
    request_body = request.get_json(silent=True) or {}
    data = request_body.get('data')
    ckan_url = request_body.get('ckan_url')
    ckan_api_key = request_body.get('ckan_api_key')

    result = []

    if ckan_url and data and ckan_api_key:
        config = {
            'apikey': ckan_api_key,
            'address': ckan_url,
        }
        ckan = CKANInstance(config)
        for sheet in data:
            try:
                dataset_data = {
                    'name': sheet['name'],
                }
                dataset = ckan.create_dataset(dataset_data)
                resource = ckan.create_resource(sheet['name'], dataset)
                if resource:
                    resource_data = sheet['data']
                    fields = get_fields(resource_data[0], DATA_DICTIONARY)
                    ckan.create_resource_in_datastore(resource)
                    ckan.send_data_to_datastore(fields, resource_data, resource)
                result.append({
                    'info': f'Processed {sheet["name"]} data.'
                })
            except Exception as e:
                result.append({
                    'error': str(e),
                })
        return result
    else:
        return {'error': 'Missing CKAN URL or data.'}

def get_fields(sample_data, data_dict):
    fields = []
    for item in sample_data:
        match = None
        for dict_dataset in data_dict:
            try:
                match = data_dict[dict_dataset][item]
                fields.append({
                    'id': item,
                    'type': match['type'],
                })
                break
            except KeyError:
                pass
        if match is None:
            # default type to text
            fields.append({
                'id': item,
                'type': 'text',
            })
    return fields