import sys
import os
import time

from openpyxl import load_workbook, Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
from PyQt5.QtWidgets import QApplication, QWidget, QFileDialog, QPushButton,\
    QLineEdit, QTextEdit, QLabel, QGridLayout, QComboBox
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QFont

def is_number(mark):
    if (''.join(mark.split('.'))).isdigit():
        return True
    return False

def get_needed_mark(mark):
    if not is_number(mark):
        return mark
    else:
        mark = float(mark)

    if mark == 0:
        return '0'
    elif mark < 2.5:
        return '2'
    elif mark < 3.5:
        return '3'
    elif mark < 4.5:
        return '4'
    return '5'

def classify(marks):
    if 'Н/А' in marks:
        return 'Есть неаттестации'
    if 'Нзч' in marks:
        return 'Есть незачёты'
    if '2' in marks:
        return 'Двоечник'
    if marks.count('3') == 1:
        return 'С одной 3'
    if marks.count('3') > 1:
        return 'Троечник'
    if marks.count('4') == 1:
        return 'С одной 4'
    if marks.count('4') > 1:
        return 'Хорошист'
    if '5' in marks:
        return 'Отличник'
    return 'Недостаточно данных'

class ExcelMarksInterface(QWidget):
    def __init__(self):
        super().__init__()
        self.needed_file_description, self.select_file_button, self.selected_file_label, self.period_label,\
            self.period_input, self.form_data_description, self.form_input, self.start_analysing_button,\
            self.or_label, self.start_analysing_all_button, self.output_console = [None] * 11
        self.init_ui()
        self.analyser = ExcelMarksAnalyser()
        self.filename = None
        self.show()

    def init_ui(self):
        self.setFixedSize(800, 600)
        self.setWindowTitle('Обработка оценок учеников')

        grid = QGridLayout()
        grid.setContentsMargins(40, 20, 40, 30)
        grid.setSpacing(15)
        self.setLayout(grid)

        self.needed_file_description = QLabel('Выберите файл с итоговыми оценками:', self)
        self.needed_file_description.setFont(QFont('Arial', 13))
        grid.addWidget(self.needed_file_description, 0, 0, 1, 3, alignment=Qt.AlignCenter)

        self.select_file_button = QPushButton('Выбрать файл', self)
        self.select_file_button.setFont(QFont('Arial', 13))
        self.select_file_button.clicked.connect(self.select_file)
        self.select_file_button.setFixedSize(150, 40)
        grid.addWidget(self.select_file_button, 1, 0, alignment=Qt.AlignCenter)

        self.selected_file_label = QLabel('Файл не выбран.', self)
        self.selected_file_label.setFont(QFont('Arial', 13))
        grid.addWidget(self.selected_file_label, 1, 1, 1, 2)

        self.period_label = QLabel('Период аттестации (триместр/полугодие/год):', self)
        self.period_label.setFont(QFont('Arial', 13))
        grid.addWidget(self.period_label, 2, 0, 1, 2, alignment=Qt.AlignCenter)

        self.period_input = QComboBox(self)
        self.period_input.addItems(['1', '2', '3', 'Год'])
        self.period_input.setFont(QFont('Arial', 14))
        grid.addWidget(self.period_input, 2, 2, alignment=Qt.AlignCenter)

        self.form_data_description = QLabel('Название класса (разделяя номер и букву дефисом):', self)
        self.form_data_description.setFont(QFont('Arial', 13))
        grid.addWidget(self.form_data_description, 3, 0, 1, 2, alignment=Qt.AlignCenter)

        self.form_input = QLineEdit('', self)
        self.form_input.setFont(QFont('Arial', 14))
        self.form_input.setMaximumWidth(150)
        grid.addWidget(self.form_input, 3, 2, alignment=Qt.AlignCenter)

        self.start_analysing_button = QPushButton('Обработать', self)
        self.start_analysing_button.setFont(QFont('Arial', 13))
        self.start_analysing_button.clicked.connect(self.analyse)
        self.start_analysing_button.setAutoDefault(True)
        self.start_analysing_button.setFixedSize(200, 50)
        grid.addWidget(self.start_analysing_button, 4, 0, 1, 3, alignment=Qt.AlignCenter)

        self.or_label = QLabel('ИЛИ', self)
        self.or_label.setFont(QFont('Arial', 13))
        grid.addWidget(self.or_label, 5, 0, 1, 3, alignment=Qt.AlignCenter)

        self.start_analysing_all_button = QPushButton('Обработать все файлы в папке')
        self.start_analysing_all_button.setFont(QFont('Arial', 13))
        self.start_analysing_all_button.clicked.connect(self.analyse_all)
        self.start_analysing_all_button.setFixedSize(300, 50)
        grid.addWidget(self.start_analysing_all_button, 6, 0, 1, 3, alignment=Qt.AlignCenter)

        self.output_console = QTextEdit('', self)
        self.output_console.setFont(QFont('Arial', 12))
        self.output_console.setReadOnly(True)
        self.output_console.setMaximumHeight(300)
        grid.addWidget(self.output_console, 7, 0, 1, 3)

    def select_file(self):  # метод для отображения окна выбора файла
        filename = QFileDialog.getOpenFileName(self, 'Выбор файла для обработки')[0]
        if filename == '':
            self.selected_file_label.setText('Файл не выбран.')
        else:
            self.filename = filename
            self.selected_file_label.setText('Выбранный файл: "{}".'.format(filename.split('/')[-1]))

    def analyse(self, form=None, period=None):  # метод для обработки файла
        if self.filename in (None, ''):  # проверка на то, что файл не выбран
            self.output_console.append('Ошибка: Файл не выбран.\n')
            return
        if not self.filename.endswith('.xlsx'):  # проверка на расширение файла
            self.output_console.append('Ошибка: Неподдерживаемое расширение файла: "{}".\n'.
                                       format(self.filename.split('.')[-1]))
            return

        if not form:
            form = self.form_input.text().upper()
        if form == '':  # проверка на то, что класс не указан
            self.output_console.append('Ошибка: Класс не указан.\n')
            return
        if '-' not in form:  # проверка на отсутствие дефиса в названии класса
            self.output_console.append('Ошибка: Неправильный формат названия класса.\n')
            return

        if not period:
            period = self.period_input.currentText()
        if int(form.split('-')[0]) in (10, 11) and period == '3':
            self.output_console.append('Ошибка: Неправильный формат периода аттестации.\n')
            return

        try:
            start_time = time.time()

            new_filename = 'Заключение по итоговым оценкам_{}.xlsx'.format(form)

            self.analyser.analyse_file(self.filename, form, period)
            self.analyser.create_resulting_file(new_filename, form, period)
            self.analyser.reset()

            self.output_console.append('Успешно обработано: "{}" ({}).'.format(self.filename, form))
            self.output_console.append('Файл "{}" успешно создан.'.format(new_filename))
            self.output_console.append('Длительность выполнения: {} сек.\n'.
                                       format(str(round(time.time() - start_time, 2))))

        except Exception as e:
            self.output_console.append('Ошибка: {}.\n'.format(e))

    def analyse_all(self):
        if self.filename in (None, ''):  # проверка на то, что файл не выбран
            self.output_console.append('Ошибка: Файл не выбран.\n')
            return
        if not self.filename.endswith('.xlsx'):  # проверка на расширение файла
            self.output_console.append('Ошибка: Неподдерживаемое расширение файла: "{}".\n'.
                                       format(self.filename.split('.')[-1]))
            return

        period = self.period_input.currentText()

        if len(self.filename.split('/')) > 1:
            path = '/'.join(self.filename.split('/')[:-1]) + '/'
        else:
            path = ''

        files = os.listdir(path)
        forms = []
        for file in files:
            file = file.split('-')
            if not file[-1].endswith('.xlsx'):
                continue

            for i in range(len(file) - 1):
                if len(file[i]) < 1 or len(file[i + 1]) < 1:
                    continue

                if file[i + 1][0].isalpha():
                    if file[i].endswith('10') or file[i].endswith('11'):
                        forms.append(file[i][-2:] + '-' + file[i + 1][0])
                        break
                    elif file[i][-1].isdigit():
                        forms.append(file[i][-1] + '-' + file[i + 1][0])
                        break

        for form in forms:
            self.analyse(form, period)
            self.output_console.repaint()

        self.output_console.append('Обработка файлов завершена.\n')

class ExcelMarksAnalyser:
    def __init__(self):
        self.all_subjects = None
        self.students = {}
        self.classifications = {}
        self.THIN = Side(border_style='thin', color='000000')
        self.THICK = Side(border_style='thick', color='000000')
        self.DOUBLE = Side(border_style='double', color='000000')

    def reset(self):
        self.all_subjects = None
        self.students = {}
        self.classifications = {}

    def get_average_marks(self, path, filenames, period):  # метод для получения средних баллов из первого файла
        if len(filenames) == 1:
            file_num = 0
        else:
            raise ValueError('Слишком много файлов со средними оценками')

        workbook = load_workbook('{}{}'.format(path, filenames[file_num]), read_only=True)
        sheet = workbook.active

        subjects = list(map(lambda s: s.value, sheet[6][1:]))
        self.all_subjects = subjects.copy()

        row_num = 7
        while True:  # пробегаемся по всем рядам таблицы с учениками
            if row_num > sheet.max_row:
                break
            row = list(map(lambda c: c.value, sheet[row_num]))
            student = row[0]
            if student in ('', None):  # проверка на пустоту ячейки
                break
            if student not in self.students.keys():
                self.students[student] = {}

            for mark_index in range(len(row[1:])):  # пробегаемся по всем оценкам данного ученика
                mark = row[1:][mark_index]
                subject = subjects[mark_index]

                if subject not in self.students[student].keys():
                    self.students[student][subject] = [[None] * 2, [None] * 2, [None] * 2, [None] * 2]

                if period.isdigit():
                    self.students[student][subject][int(period) - 1][0] = mark
                else:
                    self.students[student][subject][3][0] = mark

            row_num += 1

    def get_final_marks(self, filename, form):  # метод для получения триместровых оценок
        workbook = load_workbook(filename, read_only=False)

        form_num = form.split('-')[0]
        sheet = workbook[form_num]

        data = list(map(lambda el: el.value, sheet['B']))
        index = data.index(form) + 1

        subj_index = index + 2
        col = 2
        subjects, periods = {}, {}
        while sheet.cell(row=subj_index + 1, column=col).value not in (None, ''):  # анализируем шапку
            subject = sheet.cell(row=subj_index, column=col).value
            if subject not in (None, ''):
                subjects[col] = subject

                if subject not in self.all_subjects:
                    self.all_subjects.append(subject)
            else:
                subjects[col] = subjects[col - 1]

            period = sheet.cell(row=subj_index + 1, column=col).value
            if period not in (None, ''):
                periods[col] = period

            col += 1

        max_col = col

        student_index = subj_index + 2
        student_name = sheet.cell(row=student_index, column=1).value
        while student_name not in (None, ''):  # пробегаемся по всем ученикам нужного класса
            short_name = ' '.join(student_name.split()[:2])

            if short_name not in self.students.keys():
                self.students[short_name] = {}

            for col in range(2, max_col):  # пробегаемся по всем оценкам данного ученика
                mark = sheet.cell(row=student_index, column=col).value
                if mark in (None, ''):
                    continue

                subject = subjects[col]
                if subject not in self.students[short_name].keys():
                    self.students[short_name][subject] = [[None] * 2, [None] * 2, [None] * 2, [None] * 2]

                if int(form_num) in (10, 11):
                    if periods[col] == 'Первое полугодие':  # если это итоговая 1 полугодия
                        self.students[short_name][subject][0][1] = mark
                    elif periods[col] == 'Второе полугодие':  # если это итоговая 2 полугодия
                        self.students[short_name][subject][1][1] = mark
                else:
                    if periods[col] == '1 триместр':  # если это итоговая 1 триместра
                        self.students[short_name][subject][0][1] = mark
                    elif periods[col] == '2 триместр':  # если это итоговая 2 триместра
                        self.students[short_name][subject][1][1] = mark
                    elif periods[col] == '3 триместр':  # если это итоговая 3 триместра
                        self.students[short_name][subject][2][1] = mark

                if periods[col] == 'Год':  # если это годовая оценка
                    self.students[short_name][subject][3][1] = mark

            student_index += 1
            student_name = sheet.cell(row=student_index, column=1).value

    def classify_students(self, period):
        for student in self.students:
            marks = []
            for subject in self.students[student]:
                if period.isdigit():
                    marks.append(self.students[student][subject][int(period) - 1][1])
                else:
                    marks.append(self.students[student][subject][3][1])

            self.classifications[student] = classify(marks)

    def analyse_file(self, filename, form, period):  # основной метод для обработки данных файлов
        if len(filename.split('/')) > 1:
            path = '/'.join(filename.split('/')[:-1]) + '/'
        else:
            path = ''

        filenames = []
        for file in os.listdir(path):
            if form in file and '.xlsx' in file:
                filenames.append(file)

        if len(filenames) == 0:
            raise ValueError('Файл со средними оценками не найден')

        self.get_average_marks(path, filenames, period)
        self.get_final_marks(filename, form)
        self.classify_students(period)

    def create_resulting_file(self, filename, form, period):  # метод для создания результирующего файла
        wrong_marks = []

        workbook = Workbook()
        sheet = workbook.active

        sheet['A1'] = 'Номер'
        sheet['A1'].alignment = Alignment(horizontal='center', vertical='center')
        sheet.merge_cells('A1:A3')
        sheet['A1'].border, sheet['A2'].border, sheet['A3'].border = \
            Border(right=self.THIN), Border(right=self.THIN), Border(right=self.THIN, bottom=self.THIN)
        sheet.column_dimensions['A'].width = 8

        sheet['B1'] = 'Имя ученика'
        sheet['B1'].alignment = Alignment(horizontal='center', vertical='center')
        sheet.merge_cells('B1:B3')
        sheet['B1'].border, sheet['B2'].border, sheet['B3'].border = \
            Border(right=self.THICK), Border(right=self.THICK), Border(right=self.THICK, bottom=self.THIN)
        sheet.column_dimensions['B'].width = 45

        student_index = 0  # порядковый номер ученика
        for student in sorted(self.students.keys()):  # пробегаемся по всем ученикам
            sheet.cell(row=student_index + 4, column=1).alignment = Alignment(horizontal='left')

            if student_index == len(self.students) - 1:
                sheet.cell(row=student_index + 4, column=2, value=student).border = Border(bottom=self.THIN,
                                                                                right=self.THICK)
                sheet.cell(row=student_index + 4, column=1, value=student_index + 1).border = Border(bottom=self.THIN,
                                                                                right=self.THIN)
            else:
                sheet.cell(row=student_index + 4, column=1, value=student_index + 1).border = Border(right=self.THIN)
                sheet.cell(row=student_index + 4, column=2, value=student).border = Border(right=self.THICK)

            subject_index = 0
            for subject in sorted(self.all_subjects):  # пробегаемся по всем предметам

                subject_column = 3 + subject_index * 3
                if student_index == 0:  # если это список предметов первого ученика, заполняем шапку
                    sheet.cell(row=1, column=subject_column).value = subject
                    sheet.cell(row=1, column=subject_column).alignment = Alignment(horizontal='center')
                    sheet.merge_cells(start_row=1, start_column=subject_column,
                                      end_row=1, end_column=subject_column + 2)
                    sheet.cell(row=1, column=subject_column + 2).border = Border(right=self.THICK)

                if student_index == 0:  # если это список предметов первого ученика, заполняем шапку
                    if not period.isdigit():
                        sheet.cell(row=2, column=subject_column).value = 'Год'
                    elif int(form.split('-')[0]) in (10, 11):
                        sheet.cell(row=2, column=subject_column).value = '{}-е полугодие'.format(period)
                    else:
                        sheet.cell(row=2, column=subject_column).value = '{}-й триместр'.format(period)

                    sheet.cell(row=2, column=subject_column).alignment = Alignment(horizontal='center')
                    sheet.merge_cells(start_row=2, start_column=subject_column,
                                      end_row=2, end_column=subject_column + 2)
                    sheet.cell(row=2, column=subject_column).border = Border(top=self.THIN, bottom=self.THIN)
                    sheet.cell(row=2, column=subject_column + 1).border = Border(top=self.THIN, bottom=self.THIN)
                    sheet.cell(row=2, column=subject_column + 2).border = Border(bottom=self.THIN,
                                                                                top=self.THIN, right=self.THICK)

                    sheet.cell(row=3, column=subject_column).value = 'ср. б.'
                    sheet.cell(row=3, column=subject_column + 1).value = 'рек.'
                    sheet.cell(row=3, column=subject_column + 2).value = 'фактич.'

                    sheet.cell(row=3, column=subject_column).alignment = Alignment(horizontal='center')
                    sheet.cell(row=3, column=subject_column + 1).alignment = Alignment(horizontal='center')
                    sheet.cell(row=3, column=subject_column + 2).alignment = Alignment(horizontal='center')

                    sheet.cell(row=3, column=subject_column).border = Border(bottom=self.THIN, right=self.THIN)
                    sheet.cell(row=3, column=subject_column + 1).border = Border(bottom=self.THIN, right=self.THIN)
                    sheet.cell(row=3, column=subject_column + 2).border = Border(bottom=self.THIN, right=self.THICK)

                if subject in self.students[student].keys():
                    if period.isdigit():
                        marks = ['0' if mark is None else mark for mark in
                                 self.students[student][subject][int(period) - 1]]
                    else:
                        marks = ['0' if mark is None else mark for mark in self.students[student][subject][3]]
                else:
                    marks = ['0', '0']

                if is_number(marks[0]):
                    marks[0] = float(marks[0])
                if is_number(marks[1]):
                    marks[1] = int(marks[1])
                sheet.cell(row=student_index + 4, column=subject_column).value = marks[0]
                sheet.cell(row=student_index + 4, column=subject_column + 2).value = marks[1]

                sheet.cell(row=student_index + 4, column=subject_column).alignment = Alignment(horizontal='center')
                sheet.cell(row=student_index + 4, column=subject_column + 2).alignment = Alignment(horizontal='center')

                recommended = get_needed_mark(str(marks[0]))
                if is_number(recommended):
                    recommended = int(recommended)
                sheet.cell(row=student_index + 4, column=subject_column + 1).value = recommended
                sheet.cell(row=student_index + 4, column=subject_column + 1).alignment = Alignment(horizontal='center')

                if recommended != marks[1]:
                    wrong_marks.append({'name': student, 'subject': subject, 'period': period,
                                        'average': marks[0], 'recommended': recommended, 'actual': marks[1]})

                    sheet.cell(row=student_index + 4, column=subject_column).font = Font(b=True)
                    sheet.cell(row=student_index + 4, column=subject_column + 1).font = Font(b=True)
                    sheet.cell(row=student_index + 4, column=subject_column + 2).font = Font(b=True)
                    sheet.cell(row=student_index + 4, column=subject_column).fill = PatternFill(
                        start_color='FF4040',
                        end_color='FF4040',
                        fill_type='solid')
                    sheet.cell(row=student_index + 4, column=subject_column + 1).fill = PatternFill(
                        start_color='FF4040',
                        end_color='FF4040',
                        fill_type='solid')
                    sheet.cell(row=student_index + 4, column=subject_column + 2).fill = PatternFill(
                        start_color='FF4040',
                        end_color='FF4040',
                        fill_type='solid')

                if student_index == len(self.students) - 1:  # если это последний ученик в списке,
                    # рисуем нижнюю границу
                    sheet.cell(row=student_index + 4, column=subject_column).border = Border(bottom=self.THIN,
                                                                                right=self.THIN)
                    sheet.cell(row=student_index + 4, column=subject_column + 1).border = Border(bottom=self.THIN,
                                                                                right=self.THIN)
                    sheet.cell(row=student_index + 4, column=subject_column + 2).border = Border(bottom=self.THIN,
                                                                                right=self.THICK)
                else:
                    sheet.cell(row=student_index + 4, column=subject_column).border = Border(right=self.THIN)
                    sheet.cell(row=student_index + 4, column=subject_column + 1).border = Border(right=self.THIN)
                    sheet.cell(row=student_index + 4, column=subject_column + 2).border = Border(right=self.THICK)

                subject_index += 1

            classification_column = 4 + subject_index * 3
            if student_index == 0:
                sheet.column_dimensions[get_column_letter(classification_column)].width = 25
                sheet.merge_cells(start_row=1, end_row=3,
                                  start_column=classification_column, end_column=classification_column)
                sheet.cell(row=1, column=classification_column,
                           value='Оценка успеваемости').alignment = Alignment(horizontal='center', vertical='center')
                sheet.cell(row=1, column=classification_column).border = Border(left=self.THIN, right=self.THIN)
                sheet.cell(row=2, column=classification_column).border = Border(left=self.THIN, right=self.THIN)
                sheet.cell(row=3, column=classification_column).border = Border(left=self.THIN, right=self.THIN,
                                                                                bottom=self.THIN)

            sheet.cell(row=student_index + 4, column=classification_column,
                       value=self.classifications[student]).alignment = Alignment(horizontal='center')
            if student_index == len(self.students) - 1:
                sheet.cell(row=student_index + 4, column=classification_column).border = \
                    Border(left=self.THIN, right=self.THIN, bottom=self.THIN)
            else:
                sheet.cell(row=student_index + 4, column=classification_column).border = \
                    Border(left=self.THIN, right=self.THIN)

            student_index += 1

        if len(wrong_marks) != 0:
            res_sheet = workbook.create_sheet('Results')

            wrong_marks.sort(key=lambda el: el['subject'])

            col_names = ('Ученик', 'Предмет', 'Период', 'Ср. б.', 'Рек.', 'Фактич.')
            for col in range(1, 7):
                res_sheet.cell(row=1, column=col, value=col_names[col - 1]).alignment = Alignment(horizontal='center')
                res_sheet.cell(row=1, column=col).font = Font(b=True)
                res_sheet.cell(row=1, column=col).border = Border(right=self.DOUBLE, bottom=self.DOUBLE)

            res_sheet.column_dimensions['A'].width = 35
            res_sheet.column_dimensions['B'].width = 25
            res_sheet.column_dimensions['C'].width = 20

            if not period.isdigit():
                for i in range(len(wrong_marks)):
                    wrong_marks[i]['period'] = 'Год'
            elif int(form.split('-')[0]) in (10, 11):
                for i in range(len(wrong_marks)):
                    wrong_marks[i]['period'] = '{}-е полугодие'.format(wrong_marks[i]['period'])
            else:
                for i in range(len(wrong_marks)):
                    wrong_marks[i]['period'] = '{}-й триместр'.format(wrong_marks[i]['period'])

            keys = ('name', 'subject', 'period', 'average', 'recommended', 'actual')
            last = False
            for row in range(1, len(wrong_marks) + 1):
                if row == len(wrong_marks):
                    last = True
                for col in range(1, 7):
                    if not last:
                        res_sheet.cell(row=row + 1, column=col, value=wrong_marks[row - 1][keys[col - 1]])\
                            .border = Border(right=self.THIN)
                    else:
                        res_sheet.cell(row=row + 1, column=col, value=wrong_marks[row - 1][keys[col - 1]])\
                            .border = Border(right=self.THIN, bottom=self.THIN)

        workbook.save(filename)

def main():
    try:
        app = QApplication(sys.argv)
        gui = ExcelMarksInterface()
        sys.exit(app.exec())
    except Exception as e:
        print('Ошибка:', e)

if __name__ == '__main__':
    main()


from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import (BillsViewSet,
                    BillsItemsListCreateApiView,
                    BillsItemRUDApiView,
                    ExportAPIView,
                    ArchievedBillListApiView,
                    ArchieveUnarchieveApiView)

app_name = 'bills'

router = DefaultRouter()
router.register(r'bills', BillsViewSet)

urlpatterns = [
    path('', include(router.urls)),

    path('bills/<uuid:pk>/items/',
         BillsItemsListCreateApiView.as_view(),
         name='items-list'),

    path('items/<uuid:pk>/',
         BillsItemRUDApiView.as_view(),
         name='items-update'),

    path('bills/<uuid:pk>/export/',
         ExportAPIView.as_view(),
         name='items-csv'),

    path('archived/',
         ArchievedBillListApiView.as_view(),
         name='archived-bills'),

    path('bills/<uuid:pk>/archive/',
         ArchieveUnarchieveApiView.as_view(),
         name='archive-unarchieve'),
]


class pdfReader():
    def readColumnsFormat(self):
        import textract
        text = textract.process('resources/pdf1.pdf', method='pdfminer')

        open("tmp/00_columns.txt", "w").write(text.decode('utf-8'))

    def readPageRowFormat(self):
        import PyPDF2
        file = open('resources/pdf1.pdf', 'rb')
        fileReader = PyPDF2.PdfFileReader(file)

        pageRange = range(0,fileReader.numPages)

        pdf = PyPDF2.PdfFileReader(file)

        with open('tmp/00_rows.txt', 'w') as f:
            for x in pageRange:
                pdfpage = pdf.getPage(x)
                f.write(pdfpage.extractText().replace("  ","\n"))
                f.write("----")


from collections import defaultdict, deque

class Automat:
    '''
    class for representing final state automata.
    Automata = (
        alphabet = set of chars
        states = set of strings
        transitions = dict{state: dict{letter: {set of children} ...} ...}
        initial_state = string
        final_states = set of strings
    )
    '''

    def __init__(self, alphabet, states, transitions,
                 initial_state, final_states):
        self.alphabet = alphabet
        self.states = states
        self.transitions = transitions
        self.initial_state = initial_state
        self.final_states = final_states

    def to_dfa(self):
        '''
        makes automat deterministic
        '''
        if Automat.is_deterministic(self):
            return self.transitions, self.final_states
        self.remove_lambda_connections()
        queue = deque()
        visited = set()
        self.initial_state = frozenset({self.initial_state})
        queue.append(self.initial_state)
        new_connections = {}
        new_final_states = set()
        new_states = set()
        new_states.add(self.initial_state)
        while queue:
            state = queue.popleft()
            connections = self.__dfa_connection(state)
            new_state = list(connections.keys())[0]
            new_connections.update(connections)
            for connection in connections[new_state]:
                state = frozenset(connections[new_state][connection])
                if state not in visited:
                    queue.append(state)
                    visited.add(state)
                    new_states.add(state)
                    if self.final_states & state:
                        new_final_states.add(state)
        self.transitions = new_connections
        self.final_states = new_final_states
        self.states = new_states
        self.__stringify()
        transitions, full = Automat.__full_transitions(self.states,
                                                       self.alphabet, self.transitions)
        if not full:
            self.transitions = transitions
            self.states.add('_')
        self.__stringify()
        return self.transitions, self.final_states

    @staticmethod
    def is_deterministic(automat):
        '''
        checks if the automata is deterministic
        '''
        for state in automat.states:
            if state not in automat.transitions:
                return False
            for letter in automat.alphabet:
                if (letter not in automat.transitions[state] or
                        len(automat.transitions[state][letter]) > 1):
                    return False
        return True

    def save_dot(self, file):
        '''
        saves graph to a dot file
        '''

        with open(file, 'w') as f:
            f.write('digraph {\n')
            f.write('rankdir = LR\n')
            if self.initial_state:
                f.write(
                    f'{self.initial_state} [ color = "#808080", shape = circle];\n')
            if self.final_states:
                f.write(
                    f'{",".join(self.final_states)} [shape = doublecircle];\n')
            f.write('node [shape = circle];\n')
            for state in self.transitions:
                for connection in self.transitions[state]:
                    for child in self.transitions[state][connection]:
                        f.write(
                            f'{state} -> {child} [label = "{connection}"];\n')
            f.write('}')

    def __dfa_connection(self, states):
        '''
        returns new connections for a new state by combining connections
        of old states
        '''

        new_connections = defaultdict(lambda: defaultdict(set))
        new_state = frozenset(states)
        new_connections[new_state]
        for state in states:
            if state not in self.transitions:
                continue
            for connection in self.transitions[state]:
                new_connections[new_state][connection].update(
                    self.transitions[state][connection])
        return new_connections

    def remove_lambda_connections(self):
        '''
        removes lambda connections, modifies transitions and final_states,
        returns them
        '''

        all_new_connections = defaultdict(lambda: defaultdict(set))
        for state in self.transitions:
            new_connections, new_states = self.__lambda_connections(
                state, state, set(),
                defaultdict(lambda: defaultdict(set)), set())
            self.final_states |= new_states
            all_new_connections[state].update(new_connections[state])
        self.transitions = all_new_connections
        return self.transitions, self.final_states

    def __lambda_connections(self, start, state, visited,
                             new_connections, new_final_states):
        '''
        searches for lambda reachable states (states that can be reached
        by any number of lambda transitions), if start state is in final_states
        adds them to the new_final_states.
        Create connections between start and children of lambda reachable states.
        Returns this connections and new_final_states
        '''
        if state in self.transitions:
            for connection in self.transitions[state]:
                for child in self.transitions[state][connection]:
                    if connection == '' and child not in visited:
                        if start in self.final_states:
                            new_final_states.add(child)
                        visited.add(state)
                        self.__lambda_connections(
                            start, child, visited,
                            new_connections, new_final_states)
                        visited.remove(state)
                    else:
                        if connection != '':
                            new_connections[start][connection].add(child)
        return new_connections, new_final_states

    def __stringify(self):
        '''
        transforms states in transitions dictionaries to stirngs.
        Children are transformed into sets of one string.
        transforms states in "final_states" to strings
        '''
        delim = ','
        transitions = {}
        final_states = set()
        states = set()
        for state in self.transitions:
            for connection in self.transitions[state]:
                new_state = state
                if isinstance(state, set) or isinstance(state, frozenset):
                    new_state = '"' + delim.join(sorted(list(state))) + '"'
                child = self.transitions[state][connection]
                if isinstance(child, set) or isinstance(child, frozenset):
                    child = '"' + delim.join(sorted(
                        list(child))) + '"'
                if new_state not in transitions:
                    transitions[new_state] = {}
                transitions[new_state][connection] = {child}

        for state in self.final_states:
            new_state = state
            if isinstance(new_state, set) or isinstance(new_state, frozenset):
                new_state = '"' + delim.join(sorted(list(new_state))) + '"'
            final_states.add(new_state)

        for state in self.states:
            new_state = state
            if isinstance(new_state, set) or isinstance(new_state, frozenset):
                new_state = '"' + delim.join(sorted(list(new_state))) + '"'
            states.add(new_state)

        self.transitions = transitions
        self.final_states = final_states
        self.states = states
        if (isinstance(self.initial_state, set) or
                isinstance(self.initial_state, frozenset)):
            self.initial_state = '"' + \
                delim.join(sorted(list(self.initial_state))) + '"'

    @staticmethod
    def __state_child(transitions, state, letter):
        '''
        function to get child of a state
        '''

        if state not in transitions or letter not in transitions[state]:
            return None
        child = transitions[state][letter]
        if isinstance(child, set):
            child = tuple(child)[0]
        return child

    @staticmethod
    def __cartesian(transitions1, transitions2, states1, states2, alphabet):
        '''
        returns cartesian product of transition tables
        '''

        transitions = defaultdict(dict)
        for letter in alphabet:
            for st1 in states1:
                for st2 in states2:
                    st1_child = Automat.__state_child(
                        transitions1, st1, letter)
                    st2_child = Automat.__state_child(
                        transitions2, st2, letter)
                    transitions[st1+st2][letter] = st1_child + st2_child
        return transitions

    @staticmethod
    def __new_states(states1, states2):
        '''
        function to generate new states for the new dfa generate by
        {&,|,-} operations
        '''
        new_states = set()
        for st1 in states1:
            for st2 in states2:
                new_states.add(st1+st2)
        return new_states

    @staticmethod
    def __final_state(final_states1, final_states2):
        '''
        helper function to generate final_states for dfa = dfa1 & dfa2
        '''
        final_states = set()
        for fs1 in final_states1:
            for fs2 in final_states2:
                final_states.add(fs1 + fs2)
        return final_states

    @staticmethod
    def __final_state_or(final_states1, final_states2, states1, states2):
        '''
        helper function to generate final_states for dfa = dfa1 | dfa2
        '''
        final_states = set()
        for fs1 in final_states1:
            for st2 in states2:
                final_states.add(fs1 + st2)
        for fs2 in final_states2:
            for st1 in states1:
                final_states.add(st1 + fs2)
        return final_states

    @staticmethod
    def __full_transitions(states, alphabet, transitions):
        '''
        returns full transition table, and True if it was already full,
        False otherwise
        '''
        new_transitions = defaultdict(dict)
        full = True
        for state in states:
            for letter in alphabet:
                if state in transitions and letter in transitions[state]:
                    if isinstance(transitions[state][letter], set):
                        new_transitions[state][letter] = tuple(
                            transitions[state][letter])[0]
                    else:
                        new_transitions[state][letter] = transitions[state][letter]
                else:
                    full = False
                    new_transitions[state][letter] = '_'
        if not full:
            for letter in alphabet:
                new_transitions['_'][letter] = '_'
        return new_transitions, full

    def __and__(self, other):
        '''
        dfa and operation
        '''

        if not (Automat.is_deterministic(self) and
                Automat.is_deterministic(other)):
            raise TypeError('"&" could be applied only to two dfas')
        new_alphabet = self.alphabet | other.alphabet
        ts1, full1 = Automat.__full_transitions(
            self.states,
            new_alphabet,
            self.transitions)
        ts2, full2 = Automat.__full_transitions(
            other.states,
            new_alphabet,
            other.transitions)
        states1 = self.states.copy()
        states2 = other.states.copy()
        transitions1 = self.transitions.copy()
        transitions2 = other.transitions.copy()
        if not full1:
            transitions1 = ts1
            states1.add('_')
        if not full2:
            transitions2 = ts2
            states2.add('_')
        new_transitions = self.__cartesian(
            transitions1,
            transitions2,
            states1,
            states2,
            new_alphabet)
        new_initial_state = self.initial_state + other.initial_state
        new_states = Automat.__new_states(self.states, other.states)
        new_final_states = Automat.__final_state(self.final_states,
                                                 other.final_states)
        result = Automat(
            new_alphabet,
            new_states,
            new_transitions,
            new_initial_state,
            new_final_states,
        )
        result.__stringify()
        return result

    def __or__(self, other):
        '''
        dfa or operation
        '''
        if not (Automat.is_deterministic(self) and
                Automat.is_deterministic(other)):
            raise TypeError('"|" could be applied only to two dfas')
        new_alphabet = self.alphabet | other.alphabet
        ts1, full1 = Automat.__full_transitions(
            self.states,
            new_alphabet,
            self.transitions)
        ts2, full2 = Automat.__full_transitions(
            other.states,
            new_alphabet,
            other.transitions)
        states1 = self.states.copy()
        states2 = other.states.copy()
        transitions1 = self.transitions.copy()
        transitions2 = other.transitions.copy()
        if not full1:
            transitions1 = ts1
            states1.add('_')
        if not full2:
            transitions2 = ts2
            states2.add('_')
        new_transitions = self.__cartesian(
            transitions1,
            transitions2,
            states1,
            states2,
            new_alphabet)
        new_initial_state = self.initial_state + other.initial_state
        new_states = Automat.__new_states(states1, states2)
        new_final_states = Automat.__final_state_or(self.final_states,
                                                    other.final_states, states1, states2)
        result = Automat(
            new_alphabet,
            new_states,
            new_transitions,
            new_initial_state,
            new_final_states,
        )
        result.__stringify()
        return result

    def __invert__(self):
        '''
        dfa complement
        '''
        if not Automat.is_deterministic(self):
            raise TypeError('"~" could be applied only to dfa')
        ts, full = Automat.__full_transitions(
            self.states,
            self.alphabet,
            self.transitions)
        new_states = self.states.copy()
        new_transitions = self.transitions.copy()
        if not full:
            new_transitions = ts
            new_states.add('_')
        new_final_states = (new_states - self.final_states)

        result = Automat(
            alphabet=self.alphabet.copy(),
            states=new_states,
            transitions=new_transitions,
            initial_state=self.initial_state,
            final_states=new_final_states,
        )
        return result

    def __sub__(self, other):
        '''
        dfa - dfa
        '''
        if not (Automat.is_deterministic(self) and
                Automat.is_deterministic(other)):
            raise TypeError('"-" could be applied only to two dfas')

        return ~other & self


from xml.dom import minidom

root = minidom.Document()
xml = root.createElement('root')
root.appendChild(xml)

productChild = root.createElement('produkt')
productChild.setAttribute('nazwa', 'Kurs Python')

xml.appendChild(productChild)
xml_str = root.toprettyxml(indent="\t")

save_path = "produkt.xml"

with open(save_path, "w") as f:
    f.write(xml_str)


"""Test integration."""

import os
import tempfile

import pandas as pd

from app.pipeline import pipeline_completa

def test_integration() -> None:
    """Integration test to check the full consolidate_excels functionality."""
    # Criar uma pasta temporária para simular o ambiente real
    with tempfile.TemporaryDirectory() as tmpdirname:
        # Configurar as pastas de entrada e saída
        input_folder = os.path.join(tmpdirname, "input")
        output_folder = os.path.join(tmpdirname, "output")
        os.makedirs(input_folder)

        # Criar um arquivo Excel real para teste
        sample_data = pd.DataFrame({"A": list(range(1, 11)), "B": list("abcdefghij")})
        sample_file_path = os.path.join(input_folder, "sample.xlsx")
        sample_data.to_excel(sample_file_path, index=False)

        # Executar a função consolidate_excels
        pipeline_completa(input_folder, output_folder, "consolidated.xlsx")

        # Verificar se o arquivo de saída existe e tem o conteúdo esperado
        output_file_path = os.path.join(output_folder, "consolidated.xlsx")
        assert os.path.exists(output_file_path)

        loaded_data = pd.read_excel(output_file_path)
        pd.testing.assert_frame_equal(loaded_data, sample_data)


from urllib.request import Request, urlopen
from bs4 import BeautifulSoup
import unicodedata

from wikiCall import getAbbreviation

abbrev = getAbbreviation()
abbrev.append('ja')

def translate(args):

    if args:
        args = args.split(' ')
    else:
        return 'All languages: ' + ', '.join(abbrev)

    i = 0

    if args[i] in abbrev:
        from_language = args[i]
        i += 1
    else:
        from_language = "auto"

    if args[i] in abbrev:
        to_language = args[i]
        i += 1
    else:
        to_language = "en"

    if i == 1:
        to_language = from_language
        from_language = "auto"

    sentences = '+'.join(args[i:]).split('\n')
    sentences = list(filter(None, sentences))
    textList = []
    for sentence in sentences:
        sentence = unicodedata.normalize('NFKD', sentence).encode('ascii','ignore').decode('utf8')

        url = 'http://translate.google.com/m?hl={0:s}&sl={1:s}&q={2:s}'
        link = url.format(to_language, from_language, sentence)
        request = Request(link, headers={'User-Agent': 'Mozilla/5.0'})
        web_byte = urlopen(request).read()
        webpage = web_byte.decode('utf-8')
        soup = BeautifulSoup(webpage, "html.parser")
        soup = soup.find("div", {'class': 't0'})

        textList.append(soup.get_text())

    text = '\n'.join(textList)
    if text:
        print('From: ' + ' '.join(args[i:]))
        print('To: ' + text)
        return text
    return "I Could not find anything from {0:s}".format(url)


from transformers import pipeline, Conversation

conversational_pipeline = pipeline("conversational")

def convOneLine():
    conv1_start = "Let's watch a movie tonight - any recommendations?"
    conv2_start = "What's your favorite book?"

    conv1 = Conversation(conv1_start)
    conv2 = Conversation(conv2_start)

    conversational_pipeline([conv1, conv2])
    print(conv1)
    print(conv2)

def convToLines():
    conv1_next = "What is it about?"
    conv2_next = "Cool, what is the genre of the book?"

    conv1.add_user_input(conv1_next)
    conv2.add_user_input(conv2_next)

    conversational_pipeline([conv1, conv2])

    print(conv1)
    print(conv2)

def customConversation():

    customConv_input = input(">> ")

    customConv = Conversation(customConv_input)

    conversational_pipeline([customConv])

    while customConv_input != "bye":
        print(customConv)

        customConv_input = input(">> ")
        customConv.add_user_input(customConv_input)
        conversational_pipeline([customConv])

customConversation()


"""Wrapper for running Freebayes.
"""

import errno
import fileinput
import glob
import os
import subprocess

from celery import task
from django.conf import settings

from main.models import Dataset
from main.model_utils import get_dataset_with_type
from pipeline.read_alignment_util import ensure_bwa_index
from pipeline.variant_calling.common import add_vcf_dataset
from pipeline.variant_calling.common import process_vcf_dataset
from pipeline.variant_calling.common import get_common_tool_params

from pipeline.variant_effects import run_snpeff
from utils import uppercase_underscore

def freebayes_regions(ref_genome,
        region_size=settings.FREEBAYES_REGION_SIZE):
    """
    Use bamtools (installed as part of freebayes) to intelligently
    generate regions that will be run in freebayes in parallel.

    ref_genome: the reference genome object
    region_size: how many bases each parallelized region 'chunk' will be
    """

    ref_genome_fasta = get_dataset_with_type(ref_genome,
            Dataset.TYPE.REFERENCE_GENOME_FASTA).get_absolute_location()

    # ensure that the fasta file has an index
    ensure_bwa_index(ref_genome_fasta)

    ref_genome_faidx = ref_genome_fasta + '.fai'

    regions = []

    with open(ref_genome_faidx) as faidx_fh:
        for line in faidx_fh:
            fields = line.strip().split('\t')
            chr_name, chr_len = fields[:2]
            chr_len = int(chr_len)
            end = 0

        while end < chr_len:
            start = end
            end = start + region_size
            if end > chr_len:
                end = chr_len
            regions.append('{chr_name}:{start}-{end}'.format(
                    chr_name=chr_name,
                    start=start,
                    end=end))
            start = end

    return regions

def run_freebayes(fasta_ref, sample_alignments, vcf_output_dir,
        vcf_output_filename, alignment_type, region=None, **kwargs):
    """Run freebayes using the bam alignment files keyed by the alignment_type
    for all Genomes of the passed in ReferenceGenome.

    NOTE: If a Genome doesn't have a bam alignment file with this
    alignment_type, then it won't be used.

    Returns:
        Boolean, True if successfully made it to the end, else False.
    """
    bam_files = [
            get_dataset_with_type(sa, alignment_type).get_absolute_location()
            for sa in sample_alignments]

    # Build up the bam part of the freebayes binary call.
    bam_part = []
    for bam_file in bam_files:
        bam_part.append('--bam')
        bam_part.append(bam_file)

    # Determine alignment ploidy (haploid or diploid).
    alignment_group = sample_alignments[0].alignment_group
    if alignment_group.alignment_options['call_as_haploid']:
        alignment_ploidy = 1
    else:
        alignment_ploidy = 2

    other_args_part = [
        '--fasta-reference', fasta_ref,
        '--pvar', '0.001',
        '--ploidy', str(alignment_ploidy),
        '--min-alternate-fraction', '.3',
        '--hwe-priors-off',
        # '--binomial-obs-priors-off',
        '--use-mapping-quality',
        '--min-base-quality', '25',
        '--min-mapping-quality', '30'
    ]

    if region:
        other_args_part.extend(['--region',region])

    # Build the full command and execute it for all bam files at once.
    full_command = (
            ['%s/freebayes/freebayes' % settings.TOOLS_DIR] +
            bam_part +
            other_args_part)

    with open(vcf_output_filename, 'w') as fh:
        subprocess.check_call(full_command, stdout=fh)

    return True # success

@task
def merge_freebayes_parallel(alignment_group):
    """
    Merge, sort, and make unique all regional freebayes variant calls after
    parallel execution.

    Returns the path to the merged vcf file.
    """
    # First, grab all freebayes parallel vcf files.
    common_params = get_common_tool_params(alignment_group)
    partial_freebayes_vcf_output_dir = os.path.join(
            common_params['output_dir'], 'freebayes')

    # Glob all the parial (region-specific) vcf files.
    # Assert that there is at least one.
    vcf_output_filename_prefix = os.path.join(partial_freebayes_vcf_output_dir,
            uppercase_underscore(common_params['alignment_type']) +
            '.partial.*.vcf')
    vcf_files = glob.glob(vcf_output_filename_prefix)
    assert len(vcf_files), (
            "No vcf files at freebayes merge step. Did freebayes fail?")

    # Generate output filename.
    vcf_ouput_filename_merged = os.path.join(partial_freebayes_vcf_output_dir,
            uppercase_underscore(common_params['alignment_type']) + '.vcf')
    vcf_ouput_filename_merged_fh = open(vcf_ouput_filename_merged, 'w')

    streamsort_cmd = ' '.join([
            settings.VCFSTREAMSORT_BINARY,
            '-w 1000 | ',
            settings.VCFUNIQ_BINARY])

    # create a pipe to write to that will sort all the sub-vcfs
    stream_merge_proc = subprocess.Popen(streamsort_cmd,
            stdin=subprocess.PIPE,
            stdout=vcf_ouput_filename_merged_fh,
            shell=True)

    # concatenate all the vcf files w/ fileinput and keep all but the first
    # header and write to the stream_merge_proc stdin pipe
    header=True
    for line in fileinput.input(vcf_files):
        #https://gist.github.com/waylan/2353749
        try:
            if line.startswith('##'):
                if header:
                    stream_merge_proc.stdin.write(line)
                continue
            elif line.startswith('#'):
                if header:
                   stream_merge_proc.stdin.write(line)
                   header=False
                continue
            stream_merge_proc.stdin.write(line)
        except IOError as e:
            if e.errno == errno.EPIPE or e.errno == errno.EINVAL:
                # Stop loop on "Invalid pipe" or "Invalid argument".
                # No sense in continuing with broken pipe.
                break
            else:
                # Raise any other error.
                raise

    # close the stdin to the stream merge, wait for it to finish,
    # and close the file.
    stream_merge_proc.stdin.close()
    stream_merge_proc.wait()
    vcf_ouput_filename_merged_fh.close()

    vcf_dataset_type = Dataset.TYPE.VCF_FREEBAYES
    vcf_annotated_dataset_type = Dataset.TYPE.VCF_FREEBAYES_SNPEFF

    # add unannotated vcf dataset first
    vcf_dataset = add_vcf_dataset(alignment_group, vcf_dataset_type,
            vcf_ouput_filename_merged)

    # If genome is annotated then run snpeff now,
    # then update the vcf_output_filename and vcf_dataset_type.
    if alignment_group.reference_genome.is_annotated():

        vcf_ouput_filename_merged_snpeff = run_snpeff(
                alignment_group, Dataset.TYPE.BWA_ALIGN)

        vcf_dataset_type = vcf_annotated_dataset_type

        vcf_dataset = add_vcf_dataset(alignment_group,
                vcf_dataset_type,
                vcf_ouput_filename_merged_snpeff)

    # generate variants, process, etc
    process_vcf_dataset(alignment_group, vcf_dataset_type)

    #remove the partial vcfs
    for filename in vcf_files:
        os.remove(filename)

    return vcf_dataset


from conexion import obtener_conexion
import controlador
from flask import Flask, jsonify, request, Response
from flask_cors import CORS
import mysql.connector
from datetime import datetime
import csv

from votacionTemp import VotacionTemp

app = Flask(__name__)
cors = CORS(app, resources={r"/*": {"origins": ["*"]}})
app.config['CORS_HEADERS'] = 'Content-Type'

#Enpoint para probar la conexion con la base de datos
@app.route('/', methods=['GET'])
def index():
    try:
        conexion = obtener_conexion()
        print("CONEXION EXITOSA")
        response = jsonify({'status':'success','Votaciones': "CONEXION EXITOSA"})
        response.status_code = 200
        return response
    except:
        print("NO SE PUEDE ESTABLECER LA CONEXION A LA BASE DE DATOS")
        response = jsonify({'status':'error','Votaciones': "NO SE PUEDE ESTABLECER LA CONEXION A LA BASE DE DATOS"})
        response.status_code = 500
        return response

@app.route('/mostrartablas', methods=['GET'])
def MostrarTablas():
    try:
        datos = controlador.MostrarTablas()
        if datos is not None:
            response = jsonify({'status':'success', 'Votaciones':'DATOS OBTENIDOS EXITOSAMENTE', 'datos':datos})
            response.status_code = 200
            return response
        else:
            response = jsonify({'status':'error','Votaciones': 'ERROR EN LA OBTENCION DE TABLAS','datos':datos})
            response.status_code = 500
            return response
    except:
        response = jsonify({'status':'error','Votaciones': 'ERROR DE COMUNICACION','datos':None})
        response.status_code = 500
        return response

# csv1 = "../tests/candidatos.csv"
# csv2 = "../tests/cargos.csv"
# csv3 = "../tests/ciudadanos.csv"
# csv4 = "../tests/departamentos.csv"
# csv5 = "../tests/mesas.csv"
# csv6 = "../tests/partidos.csv"
# csv7 = "../tests/votaciones.csv"

@app.route('/cargamasiva')
def CargaMasiva():
    # Initialize cursor within app context
    datos_partidos = cargar_datos_desde_csv('../tests/partidos.csv')
    for partido in datos_partidos:
        pass
        # print(partido[0], partido[1], partido[2], partido[3])
        controlador.InsertarPartido(partido[0], partido[1], partido[2], partido[3])
    print("--> SE CARGO PARTIDOS")
    datos_cargo = cargar_datos_desde_csv('../tests/cargos.csv')
    for cargo in datos_cargo:
        pass
        # print(cargo[0], cargo[1])
        controlador.InsertarCargo(cargo[0], cargo[1])
    print("--> SE CARGO CARGOS")
    datos_candidatos = cargar_datos_desde_csv('../tests/candidatos.csv')
    for candidato in datos_candidatos:
        pass
        # print(candidato[0], candidato[1], candidato[2], candidato[3], candidato[4])
        controlador.InsertarCandidato(candidato[0], candidato[1], candidato[2], candidato[3], candidato[4])
    print("--> SE CARGO CANDIDATOS")
    datos_departamentos = cargar_datos_desde_csv('../tests/departamentos.csv')
    for departamento in datos_departamentos:
        pass
        # print(departamento[0], departamento[1])
        controlador.InsertarDepartamento(departamento[0], departamento[1])
    print("--> SE CARGO DEPARTAMENTOS")
    datos_mesa = cargar_datos_desde_csv('../tests/mesas.csv')
    for mesa in datos_mesa:
        pass
        # print(mesa[0], mesa[1])
        controlador.InsertarMesa(mesa[0], mesa[1])
    print("--> SE CARGO MESAS")

    response = jsonify({'status':'error','Votaciones': '','datos':None})
    response.status_code = 500
    return response

@app.route('/ciudadanos')
def Ciudadanos():
    datos_ciudadano = cargar_datos_desde_csv('../tests/ciudadanos.csv')
    if datos_ciudadano is not None:
        for ciudadano in datos_ciudadano:
            pass
            print(ciudadano[0], ciudadano[1], ciudadano[2], ciudadano[3], ciudadano[4], ciudadano[5], ciudadano[6])
            controlador.InsertarCiudadano(ciudadano[0], ciudadano[1], ciudadano[2], ciudadano[3], ciudadano[4], ciudadano[5], ciudadano[6])
        print("--> SE CARGO CIUDADANOS")
        response = jsonify({'status':'error','Votaciones': '','datos':None})
        response.status_code = 500
        return response

@app.route('/votaciones')
def Votaciones():
    datos_votacion = cargar_datos_desde_csv('../tests/votaciones.csv')
    votaciones_dict = {}
    if datos_votacion is not None:
        for indice, votacion in enumerate(datos_votacion):
            voto_id = votacion[0]
            id_candidato = votacion[1]
            if id_candidato != -1:
                if voto_id in votaciones_dict:
                    votaciones_dict[voto_id].agregar_candidato(id_candidato)
                else:
                    nueva_votacion = VotacionTemp(
                        voto_id, votacion[3], votacion[2], votacion[4])
                    nueva_votacion.agregar_candidato(id_candidato)
                    votaciones_dict[voto_id] = nueva_votacion
        # Ahora tendrás un diccionario donde las claves son los voto_id y los valores son instancias de VotacionTemp
        for voto_id, votacion_temp in votaciones_dict.items():
            pass
            # votacion_temp.ciudadano_dpi = votacion_temp.ciudadano_dpi[:-3]
            # print(f"Voto ID: {voto_id}, Ciudadano DPI: {votacion_temp.ciudadano_dpi}, Mesa ID: {votacion_temp.mesa_id}, Fecha: {votacion_temp.fecha_hora}")
            controlador.InsertarVotacion(voto_id, votacion_temp.ciudadano_dpi, votacion_temp.mesa_id, votacion_temp.fecha_hora)
            for candidato_id in votacion_temp.candidatos:
                pass
                # print(f"Voto ID: {voto_id} - Candidato ID: {candidato_id}")
                # if candidato_id != "-1":
                # print("hola", candidato_id, candidato_id != -1)
                controlador.InsertarCandidatoVotado(voto_id, candidato_id)
        print("--> SE CARGO VOTACIONES")
        response = jsonify({'status':'error','Votaciones': '','datos':None})
        response.status_code = 500
        return response

@app.route('/eliminartablas')
def EliminarTablas():
    try:
        controlador.EliminarTablas()
        response = jsonify({'status':'success', 'Votaciones':'TABLAS ELIMINADAS EXITOSAMENTE'})
        response.status_code = 200
        return response
    except:
        response = jsonify({'status':'error','Votaciones': 'ERROR AL ELIMINAR LAS TABLAS'})
        response.status_code = 500
        return response

@app.route('/creartablas')
def CrearTablas():
    try:
        controlador.CrearTablas()
        response = jsonify({'status':'success', 'Votaciones':'TABLAS CREADAS EXITOSAMENTE'})
        response.status_code = 200
        return response
    except:
        response = jsonify({'status':'error','Votaciones': 'ERROR AL CREAR LAS TABLAS'})
        response.status_code = 500
        return response

@app.route('/limpiartablas')
def LimpiarTablas():
    try:
        controlador.LimpiarTablas()
        response = jsonify({'status':'success', 'Votaciones':'LAS TABLAS SE LIMPIARON CORRECTAMENTE'})
        response.status_code = 200
        return response
    except:
        response = jsonify({'status':'error','Votaciones': 'ERROR AL LIMPIAR LAS TABLAS'})
        response.status_code = 500
        return response

@app.route('/reporte/1', methods=['GET'])
def MostrarNumeroCandidatosDiputadosPorPartido():
    try:
        data = controlador.MostrarNumeroCandidatosDiputadosPorPartido()
        response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO', 'datos':data})
        response.status_code = 200
        return response
    except:
        response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE', 'data':None})
        response.status_code = 500
        return response

# @app.route('/reporte/2', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/3', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/4', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/5', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/6', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/7', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/8', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/9', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

# @app.route('/reporte/10', methods=['GET'])
# def LimpiarTablas():
#     try:
#         controlador.LimpiarTablas()
#         response = jsonify({'status':'success', 'Votaciones':'REPORTE CON EXITO'})
#         response.status_code = 200
#         return response
#     except:
#         response = jsonify({'status':'error','Votaciones': 'ERROR AL MOSTRAR EL REPORTE'})
#         response.status_code = 500
#         return response

def cargar_datos_desde_csv(nombre_archivo):
    datos = []
    with open(nombre_archivo, 'r', encoding='utf-8') as csvfile:
        csvreader = csv.reader(csvfile)
        next(csvreader)  # Para omitir la primera fila (encabezados)
        for row in csvreader:
            if row != None:
                datos.append(row)
    return datos

if __name__ == '__main__':
    print("SERVIDOR INICIADO EN EL PUERTO: 5000")
    app.run(host="0.0.0.0", port=5000, debug=True)


import os
from .BacRunner import BacRunner
from Logger import Logger
import torch

class FoldRunner(BacRunner):
    def train(self, fold_gen, test_loader):
        base_dir = self.save_dir
        for i, (train_loader, val_loader) in enumerate(fold_gen):
            self.net.module.init_weight()
            self.optim = torch.optim.Adam(self.net.parameters(), lr=self.arg.lr, betas=self.arg.beta)
            self.save_dir = base_dir + "/fold%d"%(i)
            self.best_metric = -1
            if os.path.exists(self.save_dir) is False:
                os.mkdir(self.save_dir)
            self.logger = Logger(self.save_dir)
            super().train(train_loader, val_loader, test_loader)
        self.save_dir = base_dir

    def test(self, fold_gen, test_loader):
        base_dir = self.save_dir
        test_acc = []
        for i in range(3):
            self.save_dir = base_dir + "/fold%d"%(i)
            self.logger = Logger(self.save_dir)
            super().load()
            test_acc.append(super().test(test_loader, test_loader, test_loader)[2])
        self.save_dir = base_dir
        print("-------------")
        print("Fold 3 Result")
        print("1 : %.4f\n2 : %.4f\n3: %.4f\n"%(test_acc[0], test_acc[1], test_acc[2]))
        print("Avg Test Acc : %.4f\n"%(sum(test_acc) / len(test_acc)))
        print("-------------")


from datahub.activity_stream.serializers import ActivitySerializer
from datahub.interaction.models import Interaction

class InteractionActivitySerializer(ActivitySerializer):
    """Interaction serialiser for activity stream."""

    KINDS_JSON = {
        Interaction.Kind.INTERACTION: 'Interaction',
        Interaction.Kind.SERVICE_DELIVERY: 'ServiceDelivery',
    }

    class Meta:
        model = Interaction

    def _get_project_context(self, project):
        return {} if project is None else {
            'id': f'dit:DataHubInvestmentProject:{project.pk}',
            'type': 'dit:InvestmentProject',
            'name': project.name,
            'url': project.get_absolute_url(),
        }

    def _get_event_context(self, event):
        return {} if event is None else {
            'id': f'dit:DataHubEvent:{event.pk}',
            'type': 'dit:Event',
            'dit:eventType': {'name': event.event_type.name},
            'name': event.name,
            'startTime': event.start_date,
            'endTime': event.end_date,
            'dit:team': self._get_team(event.lead_team),
            'url': event.get_absolute_url(),
        }

    def _get_context(self, instance):
        if instance.kind == Interaction.Kind.INTERACTION:
            context = self._get_project_context(instance.investment_project)
        elif instance.kind == Interaction.Kind.SERVICE_DELIVERY:
            context = self._get_event_context(instance.event)
        else:
            context = {}
        return context

    def _get_dit_participants(self, participants):
        return [
            self._get_adviser_with_team(participant.adviser, participant.team)
            for participant in participants.all()
            if participant.adviser is not None
        ]

    def to_representation(self, instance):
        """
        Serialize the interaction as per Activity Stream spec:
        https://www.w3.org/TR/activitystreams-core/
        """
        interaction_id = f'dit:DataHubInteraction:{instance.pk}'
        interaction = {
            'id': f'{interaction_id}:Announce',
            'type': 'Announce',
            'published': instance.created_on,
            'generator': self._get_generator(),
            'object': {
                'id': interaction_id,
                'type': [
                    'dit:Event',
                    f'dit:{self.KINDS_JSON[instance.kind]}',
                    f'dit:datahub:theme:{instance.theme}',
                ],
                'content': instance.notes,
                'startTime': instance.date,
                'dit:status': instance.status,
                'dit:archived': instance.archived,
                'dit:subject': instance.subject,
                'dit:business_intelligence': instance.was_policy_feedback_provided,
                'attributedTo': [
                    *self._get_companies(instance.companies),
                    *self._get_dit_participants(instance.dit_participants),
                    *self._get_contacts(instance.contacts),
                ],
                'url': instance.get_absolute_url(),
            },
        }

        context = self._get_context(instance)
        if context:
            interaction['object']['context'] = [context]

        if (
            instance.kind == Interaction.Kind.INTERACTION
            and instance.communication_channel is not None
        ):
            interaction['object']['dit:communicationChannel'] = {
                'name': instance.communication_channel.name,
            }

        if instance.service is not None:
            interaction['object']['dit:service'] = {
                'name': instance.service.name,
            }

        if instance.helped_remove_export_barrier:
            interaction['object']['dit:exportBarrierTypes'] = [
                {'name': barrier.name} for barrier in instance.export_barrier_types.all()
            ]
            if instance.export_barrier_notes != '':
                interaction['object']['dit:exportBarrierNotes'] = instance.export_barrier_notes

        return interaction


import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import GradientBoostingClassifier as gdbt
from sklearn.metrics import precision_score, accuracy_score, recall_score
from matplotlib import pyplot as plt

def get_max_crash(series):
    curr_max = series[0]
    max_crash = 0
    for i in range(1, len(series)):
        curr_max = max(curr_max, series[i])
        max_crash = min(max_crash, series[i] - curr_max)

    return abs(max_crash / curr_max)

def get_features(dataframe, upper_shadow_threshold=0.2):
    feature = list()
    close_diff = dataframe['close'].diff()
    close_diff[close_diff >= 0] = 0
    close_diff[close_diff < 0] = 1
    consecutive_decrease = close_diff * (close_diff.groupby((close_diff != close_diff.shift()).cumsum()).cumcount()
                                         + 1)
    feature.append(consecutive_decrease.max())

    ma5_diff = dataframe['ma5'].diff()
    ma10_diff = dataframe['ma10'].diff()
    ma20_diff = dataframe['ma20'].diff()
    ma5_diff[ma5_diff >= 0] = 0
    ma10_diff[ma10_diff >= 0] = 0
    ma20_diff[ma20_diff >= 0] = 0
    ma5_diff[ma5_diff < 0] = 1
    ma10_diff[ma10_diff < 0] = 1
    ma20_diff[ma20_diff < 0] = 1

    ma5_decrease = ma5_diff * (ma5_diff.groupby((ma5_diff != ma5_diff.shift()).cumsum()).cumcount() + 1)
    ma10_decrease = ma10_diff * (ma10_diff.groupby((ma10_diff != ma10_diff.shift()).cumsum()).cumcount() + 1)
    ma20_decrease = ma20_diff * (ma20_diff.groupby((ma20_diff != ma20_diff.shift()).cumsum()).cumcount() + 1)

    feature.append(ma5_decrease.max())
    feature.append(ma10_decrease.max())
    feature.append(ma20_decrease.max())

    ma10 = dataframe['ma10']
    ma20 = dataframe['ma20']
    condition_green = dataframe['close'] < dataframe['open']

    if (ma10[-1] > ma10[0]) and (ma20[-1] > ma20[0]):
        condition_upper_shadow = (dataframe['high'] - dataframe['open']) / (dataframe['open'] - dataframe['close'])
        condition_upper_shadow = condition_upper_shadow > upper_shadow_threshold
        condition = condition_green & condition_upper_shadow
        feature.append(condition[condition == True].shape[0])
    else:
        feature.append(0)

    ma_max = dataframe[['ma5', 'ma10', 'ma20']].max(1)
    ma_min = dataframe[['ma5', 'ma10', 'ma20']].min(1)
    condition_sickle = (dataframe['open'] > ma_max) & (dataframe['close'] < ma_min)
    condition_sickle = condition_green & condition_sickle
    feature.append(condition_sickle[condition_sickle == True].shape[0] > 0)
    return feature

def generate_train_test_samples(df, train_interval, test_interval, upper_shadow_threshold=0.2):
    features = list()
    labels = list()
    for i in range(0, df.shape[0]-train_interval-test_interval):
        df_train = df.iloc[i: i+train_interval]
        feature = get_features(df_train, upper_shadow_threshold=upper_shadow_threshold)
        features.append(feature)
        df_test = df.iloc[i+train_interval: i+train_interval+test_interval]
        max_crash = get_max_crash(df_test['close'])
        labels.append(max_crash)
    return np.array(features), np.array(labels)

def tumble_predict_experiment(model, df_train, df_test, train_interval, test_interval, upper_shadow_threshold,
                              crash_threshold):

    x_train, y_train = generate_train_test_samples(df_train, train_interval, test_interval,
                                                   upper_shadow_threshold=upper_shadow_threshold)
    x_test, y_test = generate_train_test_samples(df_test, train_interval, test_interval,
                                                 upper_shadow_threshold=upper_shadow_threshold)

    label_train = np.copy(y_train)
    label_train[label_train > crash_threshold] = 1
    label_train[label_train <= crash_threshold] = 0

    label_test = np.copy(y_test)
    label_test[label_test > crash_threshold] = 1
    label_test[label_test <= crash_threshold] = 0

    model.fit(x_train, label_train)
    label_train_predict = model.predict(x_train)
    label_test_predict = model.predict(x_test)

    print('In train data:')
    _experiment(df_train, label_train, label_train_predict)
    print('In test data:')
    _experiment(df_test, label_test, label_test_predict)

def _experiment(df, label, label_predict):
    print('All samples num: {}'.format(label.shape[0]))
    print('Positive samples num: {}'.format(label[label == 1].shape[0]))

    p = precision_score(label, label_predict)
    r = recall_score(label, label_predict)
    print('Precision: {}, recall: {}'.format(p, r))

    tp_fp = label_predict[label_predict == 1].shape[0]
    tp = tp_fp * p
    fn = (1 - r) * tp / r
    print('TP: {}, FP: {}, FN: {}'.format(tp, tp_fp - tp, fn))

    positive_indices = [i for i, v in enumerate(label) if v == 1]
    predict_positive_indices = [i for i, v in enumerate(label_predict) if v == 1]

    fig, (ax1, ax2, ax3, ax4) = plt.subplots(nrows=4, ncols=1)
    fig.set_figwidth(16)
    fig.set_figheight(12)

    ax1.plot(df['close'].values)
    ax2.plot(df['close'].values)
    ax3.plot(df['close'].values)
    ax4.plot(df['close'].values)

    tp = [x for x in positive_indices if x in predict_positive_indices]
    fn = [x for x in positive_indices if x not in predict_positive_indices]
    fp = [x for x in predict_positive_indices if x not in positive_indices]

    print('tp: {}, fn: {}, np: {}'.format(len(tp), len(fn), len(fp)))

    for i in positive_indices:
        ax1.axvline(x=i, c='yellow')

    for i in tp:
        ax2.axvline(x=i, c='yellow')
    for i in fn:
        ax3.axvline(x=i, c='red')
    for i in fp:
        ax4.axvline(x=i, c='blue')

    plt.show()
    plt.close()

'''
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation

positive_indices = [i for i, v in enumerate(label) if v == 1]

fig, ax = plt.subplots()
fig.set_tight_layout(True)
fig.set_figheight(6)
fig.set_figwidth(16)

# Plot a scatter that persists (isn't redrawn) and the initial line.
ax.plot(df['close'].values)

line1 = ax.axvline(x=positive_indices[0], c='red')
line2 = ax.axvline(x=positive_indices[0] + 42, c='yellow')
line3 = ax.axvline(x=positive_indices[0] + 63, c='blue')

def update(i):
    label = 'Crash rate: {}'.format(y[positive_indices[i]])
    # Update the line and the axes (with a new xlabel). Return a tuple of
    # "artists" that have to be redrawn for this frame.
    line1.set_xdata(positive_indices[i])
    line2.set_xdata(positive_indices[i] + 42)
    line3.set_xdata(positive_indices[i] + 63)
    ax.set_xlabel(label)
    return line1, line2, line3, ax

anim = FuncAnimation(fig, update, frames=len(positive_indices), interval=200)
anim.save('test1.gif', dpi=80, writer='imagemagick')
'''


from PIL import Image

# to open an image named obtained.png
img = Image.open("obtained.png")

# transposing
transposed_img = img.transpose(Image.FLIP_LEFT_RIGHT)

#save to a new file
transposed_img.save('complete.png')
print("flipping done")


# -*- coding: utf-8 -*-
"""
:Project: routing_emulator
:File: algorithm.py

:Author: Tanbixuan
:Created: 2020-04-24
"""

from scipy.spatial import ConvexHull
from math import fabs, pow, sqrt
import pygame

def get_dis(pointX, pointY, lineX1, lineY1, lineX2, lineY2):
    a = lineY2 - lineY1
    b = lineX1 - lineX2
    c = lineX2 * lineY1 - lineX1 * lineY2
    try:
        dis = (fabs(a * pointX + b * pointY + c)) / (pow(a * a + b * b, 0.5))
    except ZeroDivisionError as e:
        print(e)
        raise
    return dis

def get_second_value(elem):
    return elem[1]

class RoutingAlgorithm(object):
    def __init__(self, test_config,):
        self.test_config = test_config

    def get_convex_hulls(self):
        floating_node_list = self.test_config.floating_node_list
        self.node_list = [x.location[0] for x in floating_node_list]
        for node in self.node_list:
            node[0] += 51
            node[1] += 51
        self.hull = ConvexHull(self.node_list)
        self.fill_color = [0xE8, 0xFF, 0xFF]
        self.map_size = self.test_config.map_size
        self.hull_image = pygame.Surface([self.map_size, self.map_size])
        self.hull_image.fill(self.fill_color)
        self.hull_image.set_colorkey(self.fill_color)
        self.line_color = [0x88, 0x11, 0x66]
        self.ori_target_list = list(self.hull.vertices)
        for i in range(len(self.ori_target_list)):
            self.ori_target_list[i] = int(self.ori_target_list[i])

        for floating_node in floating_node_list:
            if floating_node.id not in self.ori_target_list:
                cur_id = floating_node.id
                min_dis = 100000
                insert_index = 0
                x = self.node_list[cur_id][0]
                y = self.node_list[cur_id][1]

                """ loop in ori_target_list to search witch edge to add into """
                for i in range(len(self.ori_target_list) - 1):
                    point1 = self.node_list[self.ori_target_list[i]]
                    point2 = self.node_list[self.ori_target_list[i + 1]]
                    line_x1 = point1[0]
                    line_y1 = point1[1]
                    line_x2 = point2[0]
                    line_y2 = point2[1]

                    cur_dis = get_dis(self.node_list[cur_id][0],
                                  self.node_list[cur_id][1],
                                  line_x1,
                                  line_y1,
                                  line_x2,
                                  line_y2)
                    dis1 = sqrt((line_x1 - x) ** 2 + (line_y1 - y) ** 2)
                    dis2 = sqrt((line_x2 - x) ** 2 + (line_y2 - y) ** 2)
                    if not (x > line_x1 and x < line_x2):
                        if cur_dis < min(dis1, dis2):
                            cur_dis = min(dis1, dis2)
                    if cur_dis < min_dis:
                        min_dis = cur_dis
                        insert_index = i

                if min_dis <= floating_node.worth_value * 30:
                    """ insert the into the selected edge """
                    self.ori_target_list = self.ori_target_list[:insert_index + 1] + \
                                           [cur_id] + self.ori_target_list[insert_index + 1:]

                    """ resort the nodes beside insert_index """
                    resort_list = self.ori_target_list[insert_index: insert_index + 3]
                    resort_point_position = [[self.node_list[x][0], self.node_list[x][1]] for x in resort_list]
                    dis1 = sqrt((resort_point_position[0][0] - resort_point_position[1][0]) ** 2 +
                                (resort_point_position[0][1] - resort_point_position[1][1]) ** 2)
                    dis2 = sqrt((resort_point_position[0][0] - resort_point_position[2][0]) ** 2 +
                                (resort_point_position[0][1] - resort_point_position[2][1]) ** 2)
                    if dis1 > dis2:
                        resort_list[1], resort_list[2] = resort_list[2], resort_list[1]
                    self.ori_target_list = self.ori_target_list[:insert_index] + resort_list + \
                                           self.ori_target_list[insert_index + 3:]

        point_list = [self.node_list[x] for x in self.ori_target_list]
        pygame.draw.lines(self.hull_image, self.line_color, True, point_list, 3)


from asyncio.tasks import Task
from asyncua import Client
from asyncua.common.subscription import Subscription

class Node:
    """
    Класс для хранения информации об узле из excel документа
    Не путать с Node из asyncua!
    """
    def __init__(self, item: str, key: str, node_id: str):
        """
        :param item: Имя узла
        :param key: Ключ для получения показаний через api
        :param node_id: Адрес узла в OPC-сервере
        """
        self.item = item
        self.key = key
        self.node_id = node_id

    def __str__(self):
        return f"Node with Item = {self.item}, Key = {self.key}, Node_id = {self.node_id}"

class ServerStatus():
    """
    Класс для представления информации о состоянии сервера.
    """
    def __init__(self, connected: bool = False, service_level: int = 0):
        """
        :param connected: Подключение к серверу
        :param service_level: Значение service level узла сервера (при наличии)
        """
        self.connected = connected
        self.service_level = service_level

class ConnectionParams():
    """
    Дополнительные параметры для работы с подключением к серверу
    """
    def __init__(self, client: Client = None, subscription: Subscription = None, handles=None, connection_task: Task = None):
        """
        :param client: Экземпляр OPC-клиента
        :param subscription: Экземпляр объекта подписки
        :param handles: Список элементов для отмены подписки
        :param connection_task: Задача на подключение к серверу
        """
        if handles is None:
            handles = []
        self.client = client
        self.subscription = subscription
        self.handles = handles
        self.connection_task = connection_task

class Server():
    """
    Класс для представления OPC-сервера
    """
    def __init__(self, name: str, address: str = None, nodes=None, status: ServerStatus = ServerStatus(),
                 connection_params: ConnectionParams = None):
        """
        :param name: Имя сервера (Имя листа сервера из excel документа)
        :param address: Адрес сервера из конфиг файла
        :param nodes: Список узлов из excel документа
        :param status: Класс для представления информации о состоянии сервера
        :param connection_params: Дополнительные параметры для работы с подключением к серверу
        """
        if nodes is None:
            nodes = []
        self.name = name
        self.address = address
        self.nodes = nodes
        self.status = status
        self.connection_params = connection_params

    def __str__(self):
        return f"Server with name {self.name}, address {self.address} and {len(self.nodes)} nodes"


from rest_framework import serializers

from auth_.models import MainUser, Profile
from credit_cards.models import CreditCard
from transactions.services import add_bonuses_to_card

from .models import Transaction

class TransactionTransferSerializer(serializers.ModelSerializer):
    author = serializers.HiddenField(default=serializers.CurrentUserDefault())
    source_card = serializers.CharField(min_length=16, max_length=16)
    destination_card = serializers.CharField(min_length=16, max_length=16)
    amount = serializers.FloatField()
    metadata = serializers.JSONField(required=False, allow_null=True)

    class Meta:
        model = Transaction
        fields = (
            "author",
            "source_card",
            "destination_card",
            "amount",
            "metadata",
        )

    def validate(self, attrs):
        if not attrs["source_card"].isnumeric():
            raise serializers.ValidationError(
                "Source card number should be digits only"
            )
        if not attrs["destination_card"].isnumeric():
            raise serializers.ValidationError(
                "Destination card number should be digits only"
            )
        return attrs

    def create(self, validated_data):
        user = validated_data.get("author")
        amount = validated_data.get("amount")
        source_card_number = validated_data.get("source_card")
        destination_card_number = validated_data.get("destination_card")

        if source_card_number == destination_card_number:
            raise serializers.ValidationError("Cannot transfer to the same card")

        source_card = CreditCard.objects.filter(
            user=user, card_number=source_card_number
        ).first()

        if not source_card:
            raise serializers.ValidationError("Source card not found")

        destination_card = CreditCard.objects.filter(
            card_number=destination_card_number
        ).first()

        if source_card.balance < amount:
            raise serializers.ValidationError("Not enough balance on card")
        source_card.balance -= amount
        if not destination_card:
            source_card.balance -= Transaction.COMMISSION
            source_card.save()
            transaction_instance = Transaction.objects.create(
                author=user,
                source_card=source_card,
                amount=amount,
                transaction_type=Transaction.TRANSFER_TO_OTHER_BANK,
                commission=Transaction.COMMISSION,
            )
            return transaction_instance

        destination_card.balance += amount
        source_card.save()
        destination_card.save()
        transaction_instance = Transaction.objects.create(
            author=user,
            source_card=source_card,
            destination_card=destination_card,
            amount=amount,
            transaction_type=Transaction.TRANSFER,
        )
        return transaction_instance

class TransactionPaySerializer(serializers.ModelSerializer):
    author = serializers.HiddenField(default=serializers.CurrentUserDefault())

    class Meta:
        model = Transaction
        fields = ("author", "amount")

    def create(self, validated_data):
        user = validated_data.get("author")
        amount = validated_data.get("amount")
        credit_card = CreditCard.objects.filter(user=user, is_main=True).first()
        if credit_card.balance < amount:
            raise serializers.ValidationError("Not enough balance on card")
        credit_card.balance -= amount
        add_bonuses_to_card(credit_card, amount)
        transaction_instance = Transaction.objects.create(
            author=user,
            source_card=credit_card,
            amount=amount,
            transaction_type=Transaction.PAYOUT,
        )
        return transaction_instance

class TransactionPayCreditCardNestedSerializer(serializers.ModelSerializer):
    class Meta:
        model = CreditCard
        fields = (
            "id",
            "card_number",
            "balance",
            "bonuses",
        )

class TransactionPayDetailSerializer(serializers.ModelSerializer):
    source_card = TransactionPayCreditCardNestedSerializer()

    class Meta:
        model = Transaction
        fields = (
            "id",
            "author",
            "source_card",
            "amount",
            "transaction_type",
        )

class TransactionTransferCreditCardNestedSerializer(serializers.ModelSerializer):
    class Meta:
        model = CreditCard
        fields = (
            "id",
            "card_number",
        )

class TransactionTransferDetailSerializer(serializers.ModelSerializer):
    source_card = TransactionPayCreditCardNestedSerializer()

    class Meta:
        model = Transaction
        fields = (
            "id",
            "author",
            "source_card",
            "amount",
            "transaction_type",
            "commission",
        )

class TransactionCreditCardNestedSerializer(serializers.ModelSerializer):
    class Meta:
        model = CreditCard
        fields = ("card_number",)

class TransactionListSerializer(serializers.ModelSerializer):
    source_card = TransactionCreditCardNestedSerializer()
    destination_card = TransactionCreditCardNestedSerializer()

    class Meta:
        model = Transaction
        fields = (
            "id",
            "source_card",
            "destination_card",
            "amount",
            "transaction_type",
            "commission",
        )

class TransactionDetailSerializer(serializers.ModelSerializer):
    class TransactionUserNestedSerializer(serializers.ModelSerializer):
        class ProfileNestedSerializer(serializers.ModelSerializer):
            class Meta:
                model = Profile
                fields = (
                    "first_name",
                    "last_name",
                )

        profile = ProfileNestedSerializer()

        class Meta:
            model = MainUser
            fields = ("id", "profile")

    source_card = TransactionCreditCardNestedSerializer()
    destination_card = TransactionCreditCardNestedSerializer()
    author = TransactionUserNestedSerializer()

    class Meta:
        model = Transaction
        fields = (
            "id",
            "author",
            "source_card",
            "destination_card",
            "amount",
            "transaction_type",
            "commission",
        )


"""Install Time Series Analysis Package."""

import setuptools
import os

# Get the long description from the README file.
_LONG_DESCRIPTION = "tackling_crohns_disease_2023"
if os.path.exists("README.md"):
    with open('README.md') as fp:
        _LONG_DESCRIPTION = fp.read()

extras = {}

extras["style"] = ["autoflake", "black", "flake8", "isort"]
extras["test"] = ["pytest", "pytest-cov"]

extras["dev"] = extras["style"] + extras["test"]

# Building list from requirements.txt
root_folder = os.path.dirname(os.path.realpath(__file__))
requirements_path = root_folder + '/requirements.txt'
install_requires = []
if os.path.isfile(requirements_path):
    with open(requirements_path) as f:
        install_requires = f.read().splitlines()

setuptools.setup(
    name='tackling_crohns_disease_2023',
    version='1.0.0',
    description='tackling_crohns_disease_2023',
    long_description=_LONG_DESCRIPTION,
    long_description_content_type='text/markdown',
    author='Feifan Fan',
    packages=setuptools.find_packages(),
    package_data={},
    scripts=[],
    install_requires=install_requires,
    extras_require=extras,
    classifiers=[
    ]
)


from __future__ import print_function
from pyspark.sql import SparkSession
import pyspark.sql.types as tp
import pyspark.sql.functions as fn

spark_session = SparkSession\
                    .builder\
                    .enableHiveSupport()\
                    .appName("Task4")\
                    .master("yarn")\
                    .getOrCreate()

spark_session.sparkContext.addFile('parse_tool.py')

from parse_tool import parse_logs

# User logs collection
user_logs = spark_session.sparkContext.textFile("/data/access_logs/big_log/")

parsed_logs = user_logs.map(parse_logs) \
                       .map(lambda parse_res : [
                          parse_res[0] + '_' + parse_res[7],
                          parse_res[3]
                       ])

schema = tp.StructType().add("user_id", tp.StringType())\
                        .add("request_id", tp.StringType())

user_log_df = spark_session.createDataFrame(parsed_logs, schema)

user_log_df_1 = user_log_df.alias("df_1")
user_log_df_2 = user_log_df.alias("df_2")

is_request_to_id = fn.udf(lambda line : line.startswith('/id'), tp.BooleanType())

top_5 = user_log_df_1.groupBy(user_log_df.user_id) \
                     .count() \
                     .orderBy(fn.desc("count")) \
                     .limit(100) \
                     .join(user_log_df_2, user_log_df_1.user_id == user_log_df_2.user_id) \
                     .filter(is_request_to_id("request_id")) \
                     .groupBy("request_id") \
                     .count() \
                     .orderBy(fn.desc("count")) \
                     .take(5)

for request_id, count in top_5:
    print(request_id, count, sep='\t')


from django import forms

from comments.models import Komentarz

class FormKomentarz(forms.Form):
    nick = forms.CharField()
    email = forms.EmailField()
    tytul = forms.CharField()
    tresc = forms.CharField(widget=forms.Textarea())

class FormKomentarz2(forms.ModelForm):
    class Meta:
        model = Komentarz
        fields = ('nick', 'email', 'tytul', 'tresc')


import requests
from bs4 import BeautifulSoup as bs
from os.path import basename

url = 'http://localhost:13579/variables.html'
def return_now_watching():
	soup = bs(requests.get(url).content)
	return '8:: I am now watching : 6{0} - {1} / {2} 8::'.format(
		basename(soup.find(id='filepath').string).replace('_', ' '),
		soup.find(id='positionstring').string,
		soup.find(id='durationstring').string
		)