import asyncio
import datetime
import os
import re
import time
from datetime import timedelta
from typing import Optional, Set, Union, Any

import numpy as np
import qtawesome as qta
from numpy import float64, int32, ndarray
from qtpy import QtGui, QtCore, QtWidgets
from qasync import QEventLoop

from clickpoints.includes.Database import DataFileExtended
from clickpoints.includes.QtShortCuts import AddQSpinBox
from clickpoints.includes.Tools import MySpinBox, HiddeableLayout

def timedelta_mul(self: timedelta, other: float) -> timedelta:
    if isinstance(other, (int, float)):
        return datetime.timedelta(seconds=self.total_seconds() * other)
    else:
        return NotImplemented

def timedelta_div(self: timedelta, other: int) -> timedelta:
    if isinstance(other, (int, float)):
        return datetime.timedelta(seconds=self.total_seconds() / other)
    else:
        return NotImplemented

def BoundBy(value: Any, min: Any, max: Any) -> Any:
    if value is None:
        return min
    if value < min:
        return min
    if value > max:
        return max
    return value

def roundTime(dt: Optional[datetime.datetime] = None, roundTo: float = 60) -> datetime:
    """Round a datetime object to any time laps in seconds
    dt : datetime.datetime object, default now.
    roundTo : Closest number of seconds to round to, default 1 minute.
    Author: Thierry Husson 2012 - Use it as you want but don't blame me.
    """
    if dt == None: dt = datetime.datetime.now()
    seconds = (dt - dt.min).seconds
    # // is a floor division, not a comment on following line:
    rounding = (seconds + roundTo / 2) // roundTo * roundTo
    return dt + datetime.timedelta(0, rounding - seconds, -dt.microsecond)

def roundValue(value, modulo, offset=0):
    return int((value - offset) // modulo) * modulo + offset

def DateDivision(x, y):
    return x.total_seconds() / y.total_seconds()

def Remap(value: Any, minmax1: list, minmax2: list) -> Any:
    length1 = minmax1[1] - minmax1[0]
    length2 = minmax2[1] - minmax2[0]
    if length1 == 0:
        return 0
    try:
        percentage = (value - minmax1[0]) / length1
    except TypeError:
        percentage = DateDivision((value - minmax1[0]), length1)
    try:
        value2 = percentage * length2 + minmax2[0]
    except TypeError:
        value2 = datetime.timedelta(seconds=percentage * length2.total_seconds()) + minmax2[0]
    return value2

class SelectFrame(QtWidgets.QDialog):
    def __init__(self, frame, max_frame):
        QtWidgets.QDialog.__init__(self)

        # Widget
        self.setWindowTitle("Select Frame - ClickPoints")
        self.setWindowIcon(qta.icon("fa.play"))
        self.setModal(True)
        main_layout = QtWidgets.QVBoxLayout(self)
        self.spinBox = AddQSpinBox(main_layout, "Frame Number:", value=frame, float=False)
        self.spinBox.setRange(0, max_frame)
        # set LineEdit text to selected
        self.spinBox.findChild(QtWidgets.QLineEdit).selectAll()

        button2 = QtWidgets.QPushButton("Ok")
        button2.clicked.connect(lambda: self.done(self.spinBox.value() + 1))
        self.spinBox.managingLayout.addWidget(button2)

class TimeLineGrabberSignal(QtCore.QObject):
    sliderPressed = QtCore.Signal()
    sliderMoved = QtCore.Signal()
    sliderReleased = QtCore.Signal()

class TimeLineGrabber(QtWidgets.QGraphicsPathItem):
    def __init__(self, parent: Union["TimeLineSlider", "RealTimeSlider"], value: int, path: QtGui.QPainterPath,
                 gradient: QtGui.QLinearGradient, parent_item: Optional[QtWidgets.QGraphicsPathItem] = None) -> None:
        if parent_item is None:
            QtWidgets.QGraphicsPathItem.__init__(self, parent.parent)
        else:
            QtWidgets.QGraphicsPathItem.__init__(self, parent_item)
        self.parent = parent
        self.pixel_range = [0, 100]
        self.value_range = [0, 100]
        self.setCursor(QtGui.QCursor(QtCore.Qt.OpenHandCursor))
        self.dragged = False

        self.setPath(path)
        self.setBrush(QtGui.QBrush(gradient))
        self.setZValue(10)
        self.value = value

        self.signal = TimeLineGrabberSignal()

    def setPixelRange(self, min: float, max: float) -> None:
        self.pixel_range = [min, max]
        self.updatePos()

    def setValueRange(self, min: Any, max: Any) -> None:
        self.value_range = [min, max]

    def setValue(self, value: Any) -> None:
        self.value = int(round(value))
        self.updatePos()

    def updatePos(self) -> None:
        self.setPos(self.value_to_pixel(self.value), 0)

    def mousePressEvent(self, event: QtCore.QEvent) -> None:
        if event.button() == 1:
            self.dragged = True
            self.signal.sliderPressed.emit()

    def mouseMoveEvent(self, event: QtCore.QEvent) -> None:
        if self.dragged:
            x = BoundBy(self.mapToParent(event.pos()).x(), self.pixel_range[0], self.pixel_range[1])
            self.setValue(self.pixel_to_value(x))
            self.signal.sliderMoved.emit()

    def mouseReleaseEvent(self, event: QtCore.QEvent) -> None:
        self.dragged = False
        self.signal.sliderReleased.emit()

    def pixel_to_value(self, pixel: Any) -> Any:
        return Remap(pixel, self.pixel_range, self.value_range)

    def value_to_pixel(self, value: Any) -> Any:
        return Remap(value, self.value_range, self.pixel_range)

class TimeLineGrabberTime(TimeLineGrabber):
    # def __init__(self, *args):
    #    QGraphicsPathItem.__init__(self, None, parent.scene)

    def mouseMoveEvent(self, event: QtCore.QEvent) -> None:
        if self.dragged:
            x = self.pos().x() + event.pos().x() / self.parent.scale / self.parent.slider_line.transform().m11()
            self.setValue(self.pixel_to_value(x))

    def setValue(self, value: datetime) -> None:
        self.value = BoundBy(value, *self.value_range)
        self.updatePos()

class TimeLineSlider(QtWidgets.QGraphicsView):
    start_changed = QtCore.Signal(int)
    end_changed = QtCore.Signal(int)

    def __init__(self, max_value: int = 0, min_value: int = 0, scale: float = 1) -> None:
        QtWidgets.QGraphicsView.__init__(self)

        self.setMaximumHeight(int(30 * scale))
        if scale != 1:
            self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setSizePolicy(self.sizePolicy().horizontalPolicy(), QtWidgets.QSizePolicy.Preferred)

        self.scene = QtWidgets.QGraphicsScene(self)
        self.setScene(self.scene)
        self.parent = QtWidgets.QGraphicsRectItem(None)
        self.parent.setScale(scale)
        self.scene.addItem(self.parent)
        self.scene.setBackgroundBrush(self.palette().color(QtGui.QPalette.Background))
        self.setStyleSheet("border: 0px")

        self.max_value = max_value
        self.min_value = min_value

        self.slider_line = QtWidgets.QGraphicsRectItem(self.parent)
        self.slider_line.setPen(QtGui.QPen(QtGui.QColor("black")))
        self.slider_line.setPos(0, -2.5)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, 0), QtCore.QPointF(0, 5))
        gradient.setColorAt(0, QtGui.QColor("black"))
        gradient.setColorAt(1, QtGui.QColor(128, 128, 128))
        self.slider_line.setBrush(QtGui.QBrush(gradient))
        self.slider_line.mousePressEvent = self.SliderBarMousePressEvent

        self.slider_line_active = QtWidgets.QGraphicsRectItem(self.parent)
        self.slider_line_active.setPen(QtGui.QPen(QtGui.QColor("black")))
        self.slider_line_active.setPos(0, -2.5)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, 0), QtCore.QPointF(0, 5))
        gradient.setColorAt(0, QtGui.QColor(128, 128, 128))
        gradient.setColorAt(1, QtGui.QColor(200, 200, 200))
        self.slider_line_active.setBrush(QtGui.QBrush(gradient))

        path = QtGui.QPainterPath()
        path.moveTo(-4, +12)
        path.lineTo(0, +2.5)
        path.lineTo(+4, +12)
        path.lineTo(-4, +12)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, 12), QtCore.QPointF(0, 2.5))
        gradient.setColorAt(0, QtGui.QColor(255, 0, 0))
        gradient.setColorAt(1, QtGui.QColor(128, 0, 0))
        self.slider_start = TimeLineGrabber(self, 0, path, gradient)
        self.slider_start.signal.sliderMoved.connect(self.slider_start_changed)

        path = QtGui.QPainterPath()
        path.moveTo(-4, -12)
        path.lineTo(0, -2.5)
        path.lineTo(+4, -12)
        path.lineTo(-4, -12)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, -12), QtCore.QPointF(0, -2.5))
        gradient.setColorAt(0, QtGui.QColor(255, 0, 0))
        gradient.setColorAt(1, QtGui.QColor(128, 0, 0))
        self.slider_end = TimeLineGrabber(self, 100, path, gradient)
        self.slider_end.signal.sliderMoved.connect(self.slider_end_changed)

        path = QtGui.QPainterPath()
        path.addRect(-2, -7, 5, 14)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, -7), QtCore.QPointF(0, 14))
        gradient.setColorAt(0, QtGui.QColor(255, 0, 0))
        gradient.setColorAt(1, QtGui.QColor(128, 0, 0))
        self.slider_position = TimeLineGrabber(self, 0, path, gradient)

        self.length = 1

        self.tick_marker = {}

    def SliderBarMousePressEvent(self, event: QtWidgets.QGraphicsSceneMouseEvent) -> None:
        self.setValue(self.PixelToValue(self.slider_line.mapToScene(event.pos()).x()))
        self.slider_position.signal.sliderReleased.emit()

    def addTickMarker(self, pos: int, type: int = 0, color: QtGui.QColor = QtGui.QColor("red"),
                      height: int = 12) -> None:
        if type == 1:
            color = QtGui.QColor("green")
            height = 8
        if pos in self.tick_marker and type in self.tick_marker[pos]:
            tick_marker = self.tick_marker[pos][type]
        else:
            width = self.ValueToPixel(1)
            if pos == self.max_value:
                width = 2
            tick_marker = QtWidgets.QGraphicsRectItem(0.0, -3.5, width, -height, self.parent)
        tick_marker.setPen(QtGui.QPen(color))
        tick_marker.setBrush(QtGui.QBrush(color))
        tick_marker.value = pos
        tick_marker.type = type
        tick_marker.height = height
        tick_marker.setZValue(1 + type)
        tick_marker.setPos(self.ValueToPixel(pos), 0)
        if pos not in self.tick_marker:
            self.tick_marker[pos] = {}
        self.tick_marker[pos][type] = tick_marker
        self.repaint()

    def removeTickMarker(self, pos: int, type: int = 0) -> None:
        if pos in self.tick_marker and type in self.tick_marker[pos]:
            tick_marker = self.tick_marker[pos][type]
            self.scene.removeItem(tick_marker)
            del self.tick_marker[pos][type]
            if self.tick_marker[pos] == {}:
                del self.tick_marker[pos]
            self.repaint()

    def clearTickMarker(self) -> None:
        for pos, ticks in self.tick_marker.items():
            for type, tick in ticks.items():
                self.scene.removeItem(tick)
        self.tick_marker = {}
        self.repaint()

    def getNextTick(self, pos: int, back: bool = False) -> int:
        if back is False:
            my_range = range(pos + 1, self.max_value + 1, +1)
        else:
            my_range = range(pos - 1, self.min_value - 1, -1)
        search_marked = True
        for i in my_range:
            if (i in self.tick_marker) == search_marked:
                return i
        if len(my_range) == 0:
            if back is False:
                return pos + 1
            return pos - 1
        return my_range[-1]

    def getNextTickChange(self, pos: int, back: bool = False) -> int:
        if back is False:
            my_range = range(pos + 1, self.max_value, +1)
        else:
            my_range = range(pos - 1, self.min_value, -1)
        search_marked = True
        if len(my_range) == 0:
            if back is False:
                return pos + 1
            return pos - 1
        if pos in self.tick_marker and my_range[0] in self.tick_marker:
            search_marked = False
        for i in my_range:
            if (i in self.tick_marker) == search_marked:
                return i
        return my_range[-1]

    def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
        self.length = (self.size().width() - 20) / self.parent.scale()
        self.slider_line.setRect(0, 0, self.length, 5)
        self.slider_line_active.setRect(self.ValueToPixel(self.slider_start.value), 0,
                                        self.ValueToPixel(self.slider_end.value) - self.ValueToPixel(
                                            self.slider_start.value), 5)
        self.ensureVisible(self.slider_line)
        for pos, ticks in self.tick_marker.items():
            for type, tick in ticks.items():
                tick.setPos(self.ValueToPixel(pos), 0)
                width = self.ValueToPixel(1)
                if pos == self.max_value:
                    width = 2
                tick.setRect(0.0, -3.5, width, -tick.height)
        for marker in [self.slider_position, self.slider_start, self.slider_end]:
            marker.setPixelRange(0, self.length)
        self.repaint()

    def setRange(self, min_value: int, max_value: int) -> None:
        self.min_value = min_value
        self.max_value = max_value
        for marker in [self.slider_position, self.slider_start, self.slider_end]:
            marker.setValueRange(self.min_value, self.max_value)

    def setValue(self, value: float) -> None:
        self.slider_position.setValue(BoundBy(value, self.min_value, self.max_value))

    def setStartValue(self, value: int) -> None:
        self.slider_start.setValue(BoundBy(value, self.min_value, self.max_value))
        self.updatePlayRange()
        self.start_changed.emit(value)

    def setEndValue(self, value: float) -> None:
        self.slider_end.setValue(BoundBy(value, self.min_value, self.max_value))
        self.updatePlayRange()
        self.end_changed.emit(value)

    def PixelToValue(self, pixel: float) -> float:
        return Remap(pixel, [0, self.length], [self.min_value, self.max_value])

    def ValueToPixel(self, value: Union[int32, int]) -> Union[float, float64, int]:
        return Remap(value, [self.min_value, self.max_value], [0, self.length])

    def slider_start_changed(self) -> None:
        self.start_changed.emit(self.slider_start.value)
        if self.slider_start.value > self.slider_end.value:
            self.slider_end.setValue(self.slider_start.value)
            self.end_changed.emit(self.slider_end.value)
        self.updatePlayRange()

    def slider_end_changed(self) -> None:
        self.end_changed.emit(self.slider_end.value)
        if self.slider_start.value > self.slider_end.value:
            self.slider_start.setValue(self.slider_end.value)
            self.start_changed.emit(self.slider_start.value)
        self.updatePlayRange()

    def updatePlayRange(self) -> None:
        self.slider_line_active.setRect(self.ValueToPixel(self.slider_start.value), 0,
                                        self.ValueToPixel(self.slider_end.value) - self.ValueToPixel(
                                            self.slider_start.value), 5)

    def value(self) -> int:
        return self.slider_position.value

    def startValue(self) -> int:
        return self.slider_start.value

    def endValue(self) -> int:
        return self.slider_end.value

    def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
        event.setAccepted(False)
        return

class RealTimeSlider(QtWidgets.QGraphicsView):
    is_hidden = True
    min_value = None
    max_value = None

    def __init__(self) -> None:
        QtWidgets.QGraphicsView.__init__(self)

        self.setMaximumHeight(30)
        # self.setRenderHint(QtGui.QPainter.Antialiasing)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setSizePolicy(self.sizePolicy().horizontalPolicy(), QtWidgets.QSizePolicy.Preferred)

        self.scene = QtWidgets.QGraphicsScene(self)
        self.setScene(self.scene)
        self.scene.setBackgroundBrush(self.palette().color(QtGui.QPalette.Background))
        self.setStyleSheet("border: 0px")

        self.slider_line = QtWidgets.QGraphicsRectItem(None)
        self.scene.addItem(self.slider_line)
        self.slider_line.setPen(QtGui.QPen(QtGui.QColor("black")))
        self.slider_line.setPos(0, 0)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, 0), QtCore.QPointF(0, 5))
        gradient.setColorAt(0, QtGui.QColor("black"))
        gradient.setColorAt(1, QtGui.QColor(128, 128, 128))
        self.slider_line.setBrush(QtGui.QBrush(gradient))

        self.markerParent = QtWidgets.QGraphicsPathItem(self.slider_line)
        self.markerGroupParents = []
        for i in range(20):
            self.markerGroupParents.append(QtWidgets.QGraphicsPathItem(self.markerParent))

        path = QtGui.QPainterPath()
        path.addRect(-2, -7, 5, 14)
        gradient = QtGui.QLinearGradient(QtCore.QPointF(0, -7), QtCore.QPointF(0, 14))
        gradient.setColorAt(0, QtGui.QColor(255, 0, 0))
        gradient.setColorAt(1, QtGui.QColor(128, 0, 0))
        self.slider_position = TimeLineGrabberTime(self, 0, path, gradient, parent_item=self.markerGroupParents[-1])
        self.slider_position.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresTransformations)

        self.length = 1

        self.scene_panning = False

        self.tick_marker = []
        self.tick_blocks = []

        self.scale = 1
        self.pan = 0

        self.pixel_len = 1000
        self.slider_position.setPixelRange(0, self.pixel_len)

    def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
        self.length = self.size().width()
        self.slider_line.setRect(0, -0.5, self.pixel_len, 1)
        self.slider_line.resetTransform()
        self.slider_line.setTransform(QtGui.QTransform.fromScale(self.length / self.pixel_len, 1), True)
        self.setSceneRect(0, -10, self.size().width(), 20)
        self.repaint()

    def SliderBarMousePressEvent(self, event: QtCore.QEvent) -> None:
        self.setValue(self.PixelToValue(self.slider_line.mapToScene(event.pos()).x()))
        self.slider_position.signal.sliderReleased.emit()

    def addTickBlock(self, pos1: datetime, pos2: datetime) -> None:
        color = QtGui.QColor(128, 128, 128, 0)
        color2 = QtGui.QColor(128, 128, 128)
        height = 11

        x1 = Remap(pos1, [self.min_value, self.max_value], [0, self.pixel_len])
        x2 = Remap(pos2, [self.min_value, self.max_value], [0, self.pixel_len])

        tick_block = QtWidgets.QGraphicsRectItem(0, -1, x2 - x1, -height, self.markerGroupParents[0])
        tick_block.setPos(x1, 0)

        tick_block.setBrush(QtGui.QBrush(color2))
        tick_block.setPen(QtGui.QPen(color))
        tick_block.setZValue(-10)

        self.tick_blocks.append(tick_block)

    def addTickMarker(self, pos: datetime, type: int = -1, type_name: str = "",
                      color: QtGui.QColor = QtGui.QColor("red"), height: int = 12, text: str = "") -> None:
        if type == -1:
            tick_marker = QtGui.QGraphicsLineItem(0, -3, 0, -height, self.markerParent)
            tick_marker.setZValue(-10)
        else:
            if type_name == "second":
                text = "%02d:%02d:%02d" % (pos.hour, pos.minute, pos.second)
            elif type_name == "minute":
                text = "%02d:%02d" % (pos.hour, pos.minute)
            elif type_name == "hour":
                text = "%02d:%02d" % (pos.hour, pos.minute)
            elif type_name == "day":
                text = "%02d.%02d" % (pos.day, pos.month)
            elif type_name == "month":
                text = "%02d.%02d" % (pos.day, pos.month)
            elif type_name == "year":
                text = "%04d" % pos.year
            tick_marker = QtWidgets.QGraphicsLineItem(0, 3, 0, -height, self.markerGroupParents[type])
            tick_marker.setZValue(10)
        tick_marker.setPen(QtGui.QPen(color))
        if type == -1:
            tick_marker.setPen(QtGui.QPen(color, 3))
        tick_marker.value = pos
        tick_marker.type = type
        tick_marker.height = height

        tick_marker.setPos(Remap(pos, [self.min_value, self.max_value], [0, self.pixel_len]), 0)

        if text != "":
            self.font_parent = QtWidgets.QGraphicsPathItem(tick_marker)

            self.font = QtGui.QFont()
            self.font.setPointSize(8)
            self.text = QtWidgets.QGraphicsSimpleTextItem(self.font_parent)
            self.text.setFont(self.font)
            self.text.setText(text)
            offsetX = self.text.boundingRect().width()
            self.text.setPos(-offsetX * 0.5 + 1, 2)
            self.font_parent.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresTransformations)
            tick_marker.text = self.text
            tick_marker.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresTransformations)
        else:
            tick_marker.setFlag(QtWidgets.QGraphicsItem.ItemIgnoresTransformations)
            tick_marker.text = None
        self.tick_marker.append(tick_marker)

    def setRange(self, min_value: Any, max_value: Any) -> None:
        self.min_value = min_value
        self.max_value = max_value
        for marker in [self.slider_position]:
            marker.setValueRange(self.min_value, self.max_value)

    def setValue(self, value: datetime) -> None:
        if self.min_value is not None and self.max_value is not None:
            self.slider_position.setValue(BoundBy(value, self.min_value, self.max_value))

    def PixelToValue(self, pixel: int) -> float:
        return Remap(pixel, [0, self.length], [self.min_value, self.max_value])

    def ValueToPixel(self, value: float) -> int:
        return Remap(value, [self.min_value, self.max_value], [0, self.length])

    def value(self) -> int:
        return self.slider_position.value

    def keyPressEvent(self, event: QtCore.QEvent) -> None:
        event.setAccepted(False)

    def setTimes(self, data_file: DataFileExtended) -> None:
        # remove old time ticks
        for tick in self.tick_blocks:
            if tick.scene():
                tick.scene().removeItem(tick)
        self.tick_blocks = []

        # get timestamps
        self.data_file = data_file
        timestamps = np.array(self.data_file.table_image.select(self.data_file.table_image.timestamp).where(
            self.data_file.table_image.timestamp != None).tuples().execute())

        # handle empty timeline
        if len(timestamps) == 0:
            self.min_value = datetime.datetime.today()
            self.max_value = datetime.datetime.today() + datetime.timedelta(hours=1)
            self.slider_position.setValueRange(self.min_value, self.max_value)
            self.is_hidden = True
            self.setHidden(True)
            return

        # remove obsolete dimension (Nx1 -> N)
        timestamps = timestamps[:, 0]

        self.is_hidden = False
        self.setHidden(False)

        # get min/max values
        self.min_value = np.amin(timestamps)
        self.max_value = np.amax(timestamps)
        if self.max_value == self.min_value:
            self.max_value = self.min_value + datetime.timedelta(hours=1)
        range = self.max_value - self.min_value

        # add some border
        self.min_value -= timedelta_mul(range, 0.01)
        self.max_value += timedelta_mul(range, 0.01)

        # apply ranges
        self.slider_position.setValueRange(self.min_value, self.max_value)

        # add tick blocks

        # calculate the time between frames
        deltas = timestamps[1:] - timestamps[:-1]

        # if we have only one image
        if len(deltas) == 0:
            return

        # find big gaps
        steps, = np.where(deltas > min(deltas) * 4)

        # start and end are the groups between these gaps
        starts = timestamps[np.concatenate(([0], steps + 1))]
        ends = timestamps[np.concatenate((steps, [len(timestamps) - 1]))]

        # add the groups to the timeline
        for start_time, end_time in zip(starts, ends):
            self.addTickBlock(start_time, end_time)

        # update display
        self.updateTicks()
        self.repaint()

    def updateTicks(self) -> None:
        span = self.max_value - self.min_value
        l = self.pixel_len
        time_per_pixel = timedelta_div(span, self.pixel_len)
        try:
            left_end = self.min_value + timedelta_mul(time_per_pixel, -self.pan / self.scale)
        except OverflowError:
            left_end = datetime.datetime(datetime.MINYEAR, 1, 1)
        try:
            right_end = self.min_value + timedelta_mul(time_per_pixel, (self.pixel_len - self.pan) / self.scale)
        except OverflowError:
            right_end = datetime.datetime(datetime.MAXYEAR, 1, 1)

        for tick in self.tick_marker:
            if tick.scene():
                tick.scene().removeItem(tick)
        self.tick_marker = []

        # determine the smallest possible ticks
        delta_min = timedelta_mul(right_end - left_end, 60 / self.pixel_len)  # self.PixelToValue(60)-left_end
        type_deltas = [datetime.timedelta(seconds=1),
                       # datetime.timedelta(seconds=2),
                       datetime.timedelta(seconds=5),
                       datetime.timedelta(seconds=10),
                       # datetime.timedelta(seconds=15),
                       datetime.timedelta(seconds=30),
                       datetime.timedelta(minutes=1),
                       # datetime.timedelta(minutes=2),
                       datetime.timedelta(minutes=5),
                       datetime.timedelta(minutes=10),
                       # datetime.timedelta(minutes=15),
                       datetime.timedelta(minutes=30),
                       datetime.timedelta(hours=1),
                       # datetime.timedelta(hours=2),
                       datetime.timedelta(hours=3),
                       datetime.timedelta(hours=6),
                       datetime.timedelta(hours=12),
                       datetime.timedelta(days=1),
                       # datetime.timedelta(days=2),
                       # datetime.timedelta(days=5),
                       # datetime.timedelta(days=10),
                       # datetime.timedelta(days=15),
                       datetime.timedelta(days=30),
                       # datetime.timedelta(days=30*2),
                       datetime.timedelta(days=30 * 3),
                       datetime.timedelta(days=30 * 6),
                       datetime.timedelta(days=356),
                       datetime.timedelta(days=356 * 5),
                       datetime.timedelta(days=356 * 10),
                       datetime.timedelta(days=356 * 50),
                       datetime.timedelta(days=356 * 100),
                       datetime.timedelta(days=356 * 200),
                       datetime.timedelta(days=356 * 500),
                       ]
        type_delta_major = type_deltas[0]
        type_delta_minor = type_deltas[0]
        for type_delta_test in type_deltas:
            type_delta_major = type_delta_test
            if type_delta_test > delta_min:
                break
            type_delta_minor = type_delta_test

        tick_types = [["second", 0, 0],
                      ["minute", 0, 0],
                      ["hour", 0, 0],
                      ["day", 0, 1],
                      ["month", 0, 1],
                      ["year", 0, 1]]
        # round to the nearest tick
        years = 0
        years_major = 0
        months = 0
        months_major = 0
        days = 0
        days_major = 0
        if type_delta_major >= datetime.timedelta(days=356):
            # round to years
            if type_delta_minor >= datetime.timedelta(days=356):
                years = int(type_delta_minor.days / 356)
            else:
                months = int(type_delta_minor.days / 30)
            years_major = int(type_delta_major.days / 356)
            tick_time = datetime.datetime(
                BoundBy(roundValue(left_end.year, max(years, 1)), datetime.MINYEAR, datetime.MAXYEAR), 1, 1)
        elif type_delta_major >= datetime.timedelta(days=30):
            # round to months
            if type_delta_minor >= datetime.timedelta(days=30):
                months = int(type_delta_minor.days / 30)
            months_major = int(type_delta_major.days / 30)
            tick_time = datetime.datetime(left_end.year, roundValue(left_end.month, max(months, 1), 1), 1)
        elif type_delta_minor >= datetime.timedelta(days=1):
            days = type_delta_minor.days
            days_major = type_delta_major.days
            tick_time = datetime.datetime(left_end.year, left_end.month, 1)
        else:
            tick_time = roundTime(left_end, type_delta_major.total_seconds())

        count = 0
        self.tick_start = tick_time
        while tick_time < right_end:
            for type in range(len(tick_types)):
                tick_type = tick_types[type]
                value = getattr(tick_time, tick_type[0])
                if tick_type[1]:
                    value %= tick_type[1]
                if value != tick_type[2]:
                    break
            # find out if this is a major tick or not
            is_major_tick = False
            if years_major:
                if tick_time.day == 1 and tick_time.month == 1 and tick_time.year == roundValue(tick_time.year,
                                                                                years_major):
                    is_major_tick = True
            elif months_major:
                if tick_time.day == 1 and tick_time.month == roundValue(tick_time.month, months_major, 1):
                    is_major_tick = True
            elif days_major:
                if tick_time.day == roundValue(tick_time.day, days_major, 1):
                    is_major_tick = True
            elif (tick_time - self.tick_start).total_seconds() % type_delta_major.total_seconds() == 0:
                is_major_tick = True

            # place the tick
            if is_major_tick:
                self.addTickMarker(tick_time, color=QtGui.QColor(0, 0, 0), height=15, type=type,
                                   type_name=tick_types[type][0])
            else:
                self.addTickMarker(tick_time, color=QtGui.QColor(0, 0, 0), height=10, type=type, type_name="")

            # apply the delta
            if years:
                try:
                    tick_time = datetime.datetime(tick_time.year + years, tick_time.month, 1)
                except ValueError:
                    break
            elif months:
                if tick_time.month + months > 12:
                    tick_time = datetime.datetime(tick_time.year + 1, 1, 1)
                else:
                    tick_time = datetime.datetime(tick_time.year, tick_time.month + months, 1)
            elif days:
                try:
                    tick_time = datetime.datetime(tick_time.year, tick_time.month, tick_time.day + days)
                except ValueError:
                    try:
                        tick_time = datetime.datetime(tick_time.year, tick_time.month + 1, 1)
                    except ValueError:
                        tick_time = datetime.datetime(tick_time.year + 1, 1, 1)
            else:
                tick_time = tick_time + type_delta_minor
            count += 1
        self.repaint()

    def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
        if event.button() == 2:
            self.last_pos = PosToArray(
                self.slider_line.mapFromScene(self.mapToScene(event.pos())))  # PosToArray(self.mapToScene(event.pos()))
            self.scene_panning = True
        super(RealTimeSlider, self).mousePressEvent(event)

    def mouseMoveEvent(self, event: QtGui.QMouseEvent) -> None:
        if self.scene_panning:
            new_pos = PosToArray(self.slider_line.mapFromScene(self.mapToScene(event.pos())))
            delta = (new_pos - self.last_pos)[0]
            self.last_pos = new_pos
            self.pan += delta
            self.markerParent.setPos(self.pan, 0)
            self.updateTicks()
            self.repaint()
        super(RealTimeSlider, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None:
        if event.button() == 1:
            pos = (self.slider_line.mapFromScene(self.mapToScene(event.pos())) - self.markerParent.pos()) / self.scale
            pos = QtCore.QPointF(self.mapFromScene(self.slider_line.mapToScene(
                pos) * 1e6)) / 1e6  # Hack to prevent mapFromScene to discard float information
            self.setValue(self.PixelToValue(pos.x()))
            self.slider_position.signal.sliderReleased.emit()
        if event.button() == 2:
            self.scene_panning = False
        super(RealTimeSlider, self).mouseReleaseEvent(event)

    def wheelEvent(self, event: QtGui.QMouseEvent) -> None:
        event.ignore()
        super(RealTimeSlider, self).wheelEvent(event)
        if event.isAccepted():
            return

        try:  # PyQt 5
            angle = event.angleDelta().y()
        except AttributeError:  # PyQt 4
            angle = event.delta()
        old_scale = self.scale
        if angle > 0:
            self.scale *= 1.1
            self.markerParent.setTransform(QtGui.QTransform.fromScale(1.1, 1), True)
        else:
            self.scale *= 0.9
            self.markerParent.setTransform(QtGui.QTransform.fromScale(0.9, 1), True)
        new_pos = PosToArray(self.slider_line.mapFromScene(self.mapToScene(event.pos())))
        x = new_pos[0]
        self.pan = x - self.scale / old_scale * (x - self.pan)
        self.markerParent.setPos(self.pan, 0)
        event.accept()

        self.updateTicks()

def PosToArray(pos) -> np.ndarray:
    return np.array([pos.x(), pos.y()])

class Timeline(QtCore.QObject):
    images_added_signal = QtCore.Signal()
    data_file = None
    config = None
    _startframe = None
    _endframe = None

    fps = 25
    skip = 1  # where skip should be called step width i.e step=10 -> frame0 to frame10

    subsecond_decimals = 0

    def __init__(self, window: "ClickPointsWindow", layout: QtWidgets.QLayout,
                 modules: QtWidgets.QWidget) -> None:
        QtCore.QObject.__init__(self)

        self.window = window
        self.modules = modules

        self.images_added_signal.connect(self.ImagesAddedMain)

        self.button = QtWidgets.QPushButton()
        self.button.setCheckable(True)
        self.button.setIcon(qta.icon("fa.play"))
        self.button.setToolTip("display timeline")
        self.button.clicked.connect(lambda: self.HideInterface(self.hidden is False))
        self.button.setFocusPolicy(QtCore.Qt.NoFocus)
        self.window.layoutButtons.addWidget(self.button)

        # control elements
        self.layoutCtrlParent = HiddeableLayout(layout, QtWidgets.QVBoxLayout)
        self.layoutCtrlParent.setContentsMargins(0, 0, 0, 5)
        self.layoutCtrlParent.setSpacing(0)

        self.layoutCtrl = HiddeableLayout(self.layoutCtrlParent, QtWidgets.QHBoxLayout)
        self.layoutCtrl.setContentsMargins(5, 5, 5, 0)

        # second
        self.layoutCtrl2 = HiddeableLayout(self.layoutCtrlParent, QtWidgets.QHBoxLayout)
        self.layoutCtrl2.setContentsMargins(5, 0, 5, 0)
        self.timeSlider = RealTimeSlider()
        self.layoutCtrl2.addWidget(self.timeSlider)
        # self.timeSlider.setTimes(self.data_file)
        empty_space_keeper = QtWidgets.QLabel()
        empty_space_keeper.setMaximumHeight(0)
        empty_space_keeper.setMaximumWidth(0)
        self.layoutCtrl2.addWidget(empty_space_keeper)

        self.timeSlider.slider_position.signal.sliderPressed.connect(self.PressedSlider)
        self.timeSlider.slider_position.signal.sliderReleased.connect(self.ReleasedSlider2)

        self.timeSlider.setToolTip("current time stamp")

        self.layoutCtrl3 = HiddeableLayout(layout, QtWidgets.QHBoxLayout)
        self.layoutCtrl3.setContentsMargins(0, 0, 0, 0)
        self.progress_bar = QtWidgets.QProgressBar()
        self.progress_bar.setTextVisible(False)
        self.layoutCtrl3.setVisible(False)
        self.layoutCtrl3.addWidget(self.progress_bar)

        # frame control
        self.button_play = QtWidgets.QPushButton()
        self.button_play.setCheckable(True)
        self.button_play.setToolTip("start/stop playback\n[space]")
        self.button_play.toggled.connect(self.Play)
        self.layoutCtrl.addWidget(self.button_play)

        self.label_frame = QtWidgets.QLabel("")
        self.label_frame.setMinimumWidth(40)
        self.label_frame.setAlignment(QtCore.Qt.AlignVCenter)
        self.label_frame.setToolTip("current frame number, frame rate and timestamp")
        self.label_frame.mousePressEvent = self.labelClicked
        self.layoutCtrl.addWidget(self.label_frame)

        self.frameSlider = TimeLineSlider(scale=self.window.scale_factor)
        # if self.get_frame_count():
        #    self.frameSlider.setRange(0, self.get_frame_count() - 1)
        self.frameSlider.slider_position.signal.sliderPressed.connect(self.PressedSlider)
        self.frameSlider.slider_position.signal.sliderReleased.connect(self.ReleasedSlider)
        self.frameSlider.start_changed.connect(lambda value: self.data_file.setOption("play_start", value))
        self.frameSlider.end_changed.connect(lambda value: self.data_file.setOption("play_end", value))
        self.frameSlider.setToolTip("current frame, drag to change current frame\n[b], [n] to set start/end marker")
        # self.frameSlider.setValue(self.get_frame_count())
        self.slider_update = True
        self.layoutCtrl.addWidget(self.frameSlider)

        self.spinBox_FPS = MySpinBox()
        self.spinBox_FPS.setMinimum(1)
        self.spinBox_FPS.setMaximum(1000)
        self.spinBox_FPS.setValue(self.fps)
        self.spinBox_FPS.valueChanged.connect(self.ChangedFPS)
        self.spinBox_FPS.setToolTip("play frame rate")
        self.layoutCtrl.addWidget(self.spinBox_FPS)

        self.spinBox_Skip = MySpinBox()
        self.spinBox_Skip.setMinimum(1)
        self.spinBox_Skip.setMaximum(1000)
        self.spinBox_Skip.setValue(self.skip)
        self.spinBox_Skip.valueChanged.connect(self.ChangedSkip)
        self.spinBox_Skip.setToolTip("display every Nth frame")
        self.layoutCtrl.addWidget(self.spinBox_Skip)

        # video replay
        self.current_fps = 0
        self.last_time = time.time()
        # initialize the frame timer
        loop = self.window.app.loop
        asyncio.ensure_future(self.runTimer(loop), loop=loop)

        self.hidden = True

        self.closeDataFile()

    async def runTimer(self, loop: QEventLoop):

        t = time.time()
        target_fps = 25
        self.target_delta_t = 1 / target_fps
        last_overhead = 0
        mean_fps = target_fps
        averaging_decay = 0.9

        while True:
            if self.running:
                wait = loop.create_task(asyncio.sleep(max(self.target_delta_t - last_overhead, 0)))
                if self.data_file is None or self.get_current_frame() is None:
                    return
                if self.get_current_frame() < self.frameSlider.startValue() or self.get_current_frame() + self.skip > self.frameSlider.endValue():
                    await self.window.load_frame(self.frameSlider.startValue())
                else:
                    await self.window.load_frame(self.window.target_frame + self.skip)
                await wait

                # calculate the time slip
                delta_t = time.time() - t
                t = time.time()
                last_overhead += 0.1 * (delta_t - self.target_delta_t)

                mean_fps = averaging_decay * mean_fps + (1 - averaging_decay) * 1 / (delta_t + 1e-9)
            else:
                await asyncio.sleep(0.01)
                t = time.time()

    def closeDataFile(self) -> None:
        self.data_file = None
        self.config = None

        self.frameSlider.clearTickMarker()

        self.Play(False)

        self.HideInterface(True)

    # load Data File values
    def updateDataFile(self, data_file: DataFileExtended, new_database: bool) -> None:
        self.data_file = data_file
        self.config = data_file.getOptionAccess()

        self.fps = 0
        if self.fps == 0:
            self.fps = 25
        if self.config.fps != 0:
            self.fps = self.config.fps
        self.skip = self.config.skip

        self.spinBox_Skip.setValue(self.skip)

        # prepare timestamp output
        # detect %*f marker get number form 1 to 6 as *
        self.subsecond_decimals = 0
        regexp = re.compile('.*.%(\d)f.*')
        match = regexp.match(self.data_file.getOption("display_timeformat"))
        if match:
            self.subsecond_decimals = match.group(1)

        if self.data_file.getOption("play_start") is not None:
            self._startframe = self.data_file.getOption("play_start")
        if self.data_file.getOption("play_end") is not None:
            self._endframe = self.data_file.getOption("play_end")

        self.Play(self.data_file.getOption("playing"))
        self.hidden = True
        self.HideInterface(self.config.timeline_hide)

    def get_current_frame(self) -> Optional[int]:
        if self.data_file is None:
            return None
        return self.data_file.get_current_image()

    def get_frame_count(self) -> int:
        if self.data_file is None:
            return 0
        return self.data_file.get_image_count()

    def ImagesAdded(self) -> None:
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(0)
        self.layoutCtrl3.setVisible(True)
        self.images_added_signal.emit()

    def ImagesAddedMain(self) -> None:
        update_end = False
        if self.frameSlider.endValue() == self.frameSlider.max_value or self.frameSlider.endValue() == 0:
            update_end = True
        self.frameSlider.setRange(0, self.get_frame_count() - 1)
        if update_end:
            self.frameSlider.setEndValue(self.get_frame_count() - 1)
        self.updateLabel()

        # reset start and end marker (only if all images are loaded frames may be valid)
        if self._startframe is not None:
            # if >1 its a frame nr if < 1 its a fraction
            if self._startframe >= 1:
                self.frameSlider.setStartValue(self._startframe)
            else:
                self.frameSlider.setStartValue(int(self.get_frame_count() * self._startframe))
        if self._endframe is not None:
            if self._endframe > 1:
                self.frameSlider.setEndValue(self._endframe)
            else:
                self.frameSlider.setEndValue(int(self.get_frame_count() * self._endframe))

    def LoadingFinishedEvent(self) -> None:
        self.progress_bar.setMinimum(0)
        self.progress_bar.setMaximum(100)
        self.layoutCtrl3.setHidden(True)
        if self.data_file.getOption("datetimeline_show"):
            self.timeSlider.setTimes(self.data_file)
            self.layoutCtrl2.setHidden(False)

    def ChangedSkip(self) -> None:
        self.skip = self.spinBox_Skip.value()
        self.data_file.setOption("skip", self.skip)

    def ChangedFPS(self) -> None:
        self.fps = self.spinBox_FPS.value()
        self.data_file.setOption("fps", self.fps)
        if self.playing:
            self.target_delta_t = 1 / self.fps
            self.running = True
            # self.timer.start(1000 / self.fps)

    def ReleasedSlider(self) -> None:
        n = self.frameSlider.value()
        self.slider_update = True
        self.updateFrame(nr=n)

    def ReleasedSlider2(self) -> None:
        timestamp = self.timeSlider.value()
        n = self.data_file.table_image.select(self.data_file.table_image.sort_index).where(
            self.data_file.table_image.timestamp > timestamp).limit(1)
        if n.count() == 0:
            return
        n = n[0].sort_index
        self.slider_update = True
        self.updateFrame(nr=n)

    def PressedSlider(self) -> None:
        self.slider_update = False

    def Play(self, state: bool) -> None:
        if state:
            self.target_delta_t = 1 / self.fps
            self.running = True
            # self.timer.start(1000 / self.fps)
            self.button_play.setIcon(QtGui.QIcon(os.path.join(os.environ["CLICKPOINTS_ICON"], "pause.ico")))
            self.playing = True
        else:
            self.running = False
            # self.timer.stop()
            self.button_play.setIcon(QtGui.QIcon(os.path.join(os.environ["CLICKPOINTS_ICON"], "play.ico")))
            self.playing = False

    def updateFrame(self, nr: int = -1) -> None:
        if self.data_file is None or self.get_current_frame() is None:
            return
        if nr != -1:
            self.window.JumpToFrame(nr)
        else:
            if self.get_current_frame() < self.frameSlider.startValue() or self.get_current_frame() + self.skip > self.frameSlider.endValue():
                self.window.JumpToFrame(self.frameSlider.startValue())
            else:
                self.window.JumpFrames(self.skip)

    def updateLabel(self) -> None:
        if self.data_file is None:
            return
        if self.slider_update or 1:
            self.frameSlider.setValue(self.get_current_frame())

            if self.timeSlider and self.data_file.image and self.data_file.image.timestamp:
                self.timeSlider.setValue(self.data_file.image.timestamp)
            if self.get_current_frame() is not None:
                if self.get_frame_count() == 0:
                    format_string = "{:1,}"
                else:
                    format_string = "{:%d,}" % np.ceil(np.log10(self.get_frame_count()))
                format_string = (format_string + '/' + format_string + "  {:.1f}fps")
                fps = self.current_fps if self.current_fps is not None else 0
                label_string = format_string.format(self.get_current_frame(), self.get_frame_count() - 1, fps)
            else:
                label_string = ""
            if self.data_file.image and self.data_file.image.timestamp:
                # if subsecond decimals are specified - adjust string accordingly
                if not self.subsecond_decimals == 0:
                    display_timeformat = self.data_file.getOption("display_timeformat").replace(
                        '%%%sf' % self.subsecond_decimals, ('%%0%sd' % self.subsecond_decimals) % (
                                self.data_file.image.timestamp.microsecond / 10 ** (
                                6 - int(self.subsecond_decimals))))
                label_string += "\n" + self.data_file.image.timestamp.strftime(display_timeformat)
            self.label_frame.setText(label_string)

    def labelClicked(self, event: QtCore.QEvent) -> None:
        self.select_frame_window = SelectFrame(self.get_current_frame(), self.get_frame_count())

        value = self.select_frame_window.exec_()
        if value > 0:
            self.window.JumpToFrame(value - 1)

    def frameChangedEvent(self) -> None:
        dt = max(time.time() - self.last_time, 1e-6)
        self.last_time = time.time()
        if self.current_fps is None or self.current_fps == 0:
            self.current_fps = 1 / dt
        else:
            a = np.exp(-dt)
            self.current_fps = a * self.current_fps + (1 - a) * 1 / dt

        self.updateLabel()
        # self.timer.allow_next() TODO

    def MaskAdded(self) -> None:
        self.frameSlider.addTickMarker(self.get_current_frame(), type=1)

    def MarkerPointsAdded(self, frame: None = None) -> None:
        if frame is not None:
            self.frameSlider.addTickMarker(frame, type=1)
        else:
            self.frameSlider.addTickMarker(self.get_current_frame(), type=1)

    def MarkerPointsAddedList(self, frames: Optional[Union[ndarray, Set[int32]]] = None) -> None:
        for frame in frames:
            if frame is not None:
                self.frameSlider.addTickMarker(frame, type=1)
            else:
                self.frameSlider.addTickMarker(self.get_current_frame(), type=1)

    def MarkerPointsRemoved(self) -> None:
        self.frameSlider.removeTickMarker(self.get_current_frame(), type=1)

    def AnnotationAdded(self, *args) -> None:
        self.frameSlider.addTickMarker(self.get_current_frame(), type=0)

    def AnnotationRemoved(self, *args):
        self.frameSlider.removeTickMarker(self.get_current_frame(), type=0)

    def AnnotationMarkerAdd(self, position: int, *args) -> None:
        self.frameSlider.addTickMarker(position, type=0)

    def HideInterface(self, hide: bool) -> None:
        self.hidden = hide
        if self.config:
            self.config.timeline_hide = self.hidden
        self.layoutCtrlParent.setHidden(hide)
        self.button.setChecked(not self.hidden)
        self.layoutCtrl2.setHidden(
            self.timeSlider.is_hidden | (self.data_file is None or not self.data_file.getOption("datetimeline_show")))

    def optionsChanged(self, key: None) -> None:
        self.HideInterface(self.hidden)

    def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
        # @key H: hide control elements
        if event.key() == QtCore.Qt.Key_H:
            self.HideInterface(self.hidden is False)
        # @key Space: run/pause
        if event.key() == QtCore.Qt.Key_Space:
            self.current_fps = None
            self.last_time = time.time()
            self.button_play.toggle()

        # @key B: move start marker here
        if event.key() == QtCore.Qt.Key_B:
            self.frameSlider.setStartValue(self.get_current_frame())
        # @key N: move start marker here
        if event.key() == QtCore.Qt.Key_N:
            self.frameSlider.setEndValue(self.get_current_frame())

        # @key ---- Frame jumps ----
        if event.key() == QtCore.Qt.Key_Left and event.modifiers() & QtCore.Qt.ControlModifier:
            # @key Ctrl+Left: previous annotated image
            tick = self.frameSlider.getNextTick(self.get_current_frame(), back=True)
            self.window.JumpToFrame(tick)
        if event.key() == QtCore.Qt.Key_Right and event.modifiers() & QtCore.Qt.ControlModifier:
            # @key Ctrl+Right: next annotated image
            tick = self.frameSlider.getNextTick(self.get_current_frame())
            self.window.JumpToFrame(tick)

        if event.key() == QtCore.Qt.Key_Left and event.modifiers() & QtCore.Qt.AltModifier:
            # @key Alt+Left: previous annotation block
            tick = self.frameSlider.getNextTickChange(self.get_current_frame(), back=True)
            self.window.JumpToFrame(tick)
        if event.key() == QtCore.Qt.Key_Right and event.modifiers() & QtCore.Qt.AltModifier:
            # @key Alt+Right: next annotation block
            tick = self.frameSlider.getNextTickChange(self.get_current_frame())
            self.window.JumpToFrame(tick)

        if event.key() == QtCore.Qt.Key_Home and event.modifiers() & QtCore.Qt.ControlModifier:
            # @key Ctrl+Home: jump to start marker
            self.window.JumpToFrame(self.frameSlider.startValue())
        if event.key() == QtCore.Qt.Key_End and event.modifiers() & QtCore.Qt.ControlModifier:
            # @key Ctrl+End: jump to end marker
            self.window.JumpToFrame(self.frameSlider.endValue())

    def closeEvent(self, event: QtGui.QCloseEvent) -> None:
        self.Play(False)

    @staticmethod
    def file() -> str:
        return __file__


import paddle
import paddle.nn as nn
import paddle.nn.functional as F
from paddle.io import Dataset
from paddle.vision.transforms import Compose, Normalize
from paddle.vision.models import LeNet
import math
import numpy as np
import random
import os
from PIL import Image
normalize = Normalize(mean=[127.5],
                        std=[127.5],
                        data_format='HWC')

#创建数据集读取
class RandomDataset(Dataset):
    def __init__(self, root = "data",mode="train"):
        self.mode = mode
        if mode == "train":
            self.txt_file = os.path.join(root,"train.txt")
        else:
            self.txt_file = os.path.join(root,"test.txt")
        self.records_list = []
        self.parse_dataset()

    def __getitem__(self, idx):
        path=self.records_list[idx][0]
        img = Image.open(path)
        img = img.resize((28, 28), Image.BILINEAR)
        img = normalize(img)
        label = int(self.records_list[idx][1])
        return img, label

    def __len__(self):
        return len(self.records_list)

    def parse_dataset(self):
        print(self.txt_file)
        with open(self.txt_file,'r') as f:
            for line in f.readlines():
                img_path, label = line.strip().split()
                self.records_list.append([img_path,label])
        random.shuffle(self.records_list)
train_dataset=RandomDataset()
test_dataset=RandomDataset(mode="test")

train_dataset=RandomDataset()
test_dataset=RandomDataset(mode="test")
train_loader = paddle.io.DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = paddle.io.DataLoader(test_dataset, batch_size=32, shuffle=False)
# 加载训练集 batch_size 设为 64
def train(model):
    model.train()
    epochs = 10
    optim = paddle.optimizer.Adam(learning_rate=0.001, parameters=model.parameters())
    # 用Adam作为优化函数
    for epoch in range(epochs):
        for batch_id, data in enumerate(train_loader()):
            x_data = data[0]
            y_data = data[1]
            y_data = paddle.unsqueeze(y_data, axis=1)
            predicts = model(x_data)
            loss = F.cross_entropy(predicts, y_data)
            # 计算损失
            acc = paddle.metric.accuracy(predicts, y_data,k=1)
            loss.backward()
            if batch_id % 300 == 0:
                print("epoch: {}, batch_id: {}, loss is: {}, acc is: {}".format(epoch, batch_id, loss.numpy(), acc.numpy()))
            optim.step()
            optim.clear_grad()
        model.eval()
        for batch_id, data in enumerate(train_loader()):
            x_data = data[0]
            y_data = data[1]
            y_data = paddle.unsqueeze(y_data, axis=1)
            predicts = model(x_data)
            loss = F.cross_entropy(predicts, y_data)
            # 计算损失
            test_acc = paddle.metric.accuracy(predicts, y_data,k=1)
            #loss.backward()
        print("test:loss is: {}, acc is: {}".format(loss.numpy(), acc.numpy()))
        model.train()
        if epoch % 2 == 0:
            paddle.save(model.state_dict(), "Tibetan_epoch"+str(epoch)+".pdparams")
model = LeNet()
train(model)


import os
import os.path
import shutil
import tempfile
import pickledb
import numpy as np
import networkx as nx
import matplotlib.colors as mcolors
import matplotlib.pyplot as plt

class Helper:

    def __init__(self, G):
        self._g = G
        self._dimensions = G.nodes['0'].keys()

    def color(self, node):
        vec = np.array([self._g.nodes[node][d] for d in self._dimensions])
        ref = np.zeros_like(vec)
        ref[0] = 1

        d = np.sqrt(np.sum([e ** 2 for e in vec]))
        theta = vec.dot(ref) / np.sqrt(np.sum(vec ** 2) * np.sum(ref ** 2))
        return d * np.sin(theta)

    def weights_color(self):
        weights = [attr['weight'] for *_, attr in self._g.edges(data=True)]
        if weights:
            weights = np.array(weights)
            weights = weights / np.max(weights)
        colors = [(0.2, 0.2, 0.2, w) for w in weights]
        return colors

    @property
    def dimensions(self):
        return self.dimensions

class RandomGraph:

    def __init__(self, filename, trackid):
        self._outdb = pickledb.load(filename, False)
        self._trackid = trackid
        tmpgraph = nx.parse_gml(self._outdb.get(trackid + '_0'))
        self._pos = nx.random_layout(tmpgraph)

        nkeys = self._outdb.totalkeys() - 1
        snapshot_rate = self._outdb.get('_params')['snapshot_rate']
        self._snapshots = range(0, nkeys * snapshot_rate, snapshot_rate)

    def _load(self, graphid):
        return nx.parse_gml(self._outdb.get(graphid))

    def _plot(self, stepid):
        G = self._load(self._trackid + '_' + stepid)
        helper = Helper(G)
        nodecolors = [helper.color(node) for node in G.nodes]
        nodesize = 30
        edgecolor = helper.weights_color()

        nodes = nx.draw_networkx_nodes(G, self._pos, \
                node_color=nodecolors, node_size=nodesize, linewidths=.3, \
                edgecolors='#333333', cmap=plt.cm.Spectral)
        edges = nx.draw_networkx_edges(G, self._pos, node_size=nodesize, \
                width=.5)
        if edges:
            edges._edgecolors = mcolors.to_rgba_array(edgecolor)

    def plot_gif(self, filename, deleteimgs=True):
        tmpdir = tempfile.mkdtemp()
        imgcounter = 0
        for i in self._snapshots:
            imgname = '%04d.png' % imgcounter
            path = os.path.join(tmpdir, imgname)
            self.plot(str(i), path)
            imgcounter += 1

        os.system(f'convert {tmpdir}/* -delay 50 -loop 0 {filename}')

        if deleteimgs:
            shutil.rmtree(tmpdir)

    def plot(self, stepid, filename):
        self._plot(stepid)
        plt.savefig(filename, dpi=150, bbox_inches='tight', \
                pad_inches=-0.05)
        plt.clf()

class ClusterGraph(RandomGraph):
    def __init__(self, filename, trackid):
        self._outdb = pickledb.load(filename, False)
        self._trackid = str(trackid)

        nkeys = self._outdb.totalkeys() - 1
        snapshot_rate = self._outdb.get('_params')['snapshot_rate']
        last_snapshot = nkeys * snapshot_rate
        self._snapshots = range(0, last_snapshot, snapshot_rate)

        graphid = trackid + '_' + str(last_snapshot - snapshot_rate)
        tmpgraph = nx.parse_gml(self._outdb.get(graphid))
        self._pos = nx.spring_layout(tmpgraph)

class SpringGraph(RandomGraph):
    def _load(self, graphid):
        G = nx.parse_gml(self._outdb.get(graphid))
        self._pos = nx.spring_layout(G)
        return G

class ScatterPlot:

    def __init__(self, filename, trackid):
        self._outdb = pickledb.load(filename, False)
        self._trackid = trackid
        nkeys = self._outdb.totalkeys() - 1
        snapshot_rate = self._outdb.get('_params')['snapshot_rate']
        self._snapshots = range(0, nkeys * snapshot_rate, snapshot_rate)

    def _load(self, graphid):
        return nx.parse_gml(self._outdb.get(graphid))

    def _plot(self, stepid):
        G = self._load(self._trackid + '_' + stepid)
        helper = Helper(G)
        nodecolors = [helper.color(node) for node in G.nodes]
        time = np.full_like(nodecolors, stepid)
        plt.scatter(time, nodecolors, s=2, c="#555555")

    def plot(self, filename):
        for i in self._snapshots:
            self._plot(str(i))

        plt.savefig(filename, dpi=150, bbox_inches='tight')
        plt.clf()


#!/usr/bin/env python3
"""Test creation of volumes when containers are being created"""

import random
import unittest
import docker

from control.container import Container
from control.service import create_service

class VolumeCreationTests(unittest.TestCase):
    """
    Double check that volumes are being created correctly. A later class will
    check that they are being removed correctly.
    """

    @classmethod
    def setUpClass(cls):
        cls.dclient = docker.Client('unix://var/run/docker.sock')

    def setUp(self):
        # control.options.debug = True
        self.image = ''
        self.conf = {}
        self.container_volumes = []
        self.container_name = 'unittest_volumecreation_{}'.format(
            random.randint(1, 65535))

    def tearDown(self):
        try:
            self.dclient.remove_container(self.container_name, v=True, force=True)
            for vol in self.container_volumes:
                self.dclient.remove_volume(vol)
        except docker.errors.NotFound:
            pass

    @unittest.expectedFailure
    def test_anon_volumes(self):
        """
        Make sure that anonymous volumes are correctly registered

        Currently unimplemented and will fail
        """
        self.image = 'busybox'
        self.conf = {
            "image": self.image,
            "container": {
                "name": self.container_name,
                "hostname": "busybox",
                "volumes": ["/var"]
            }
        }
        serv = create_service(self.conf, './Controlfile')
        container = Container(serv).create(prod=False)
        container.start()
        self.assertEqual(len(container.inspect['Mounts']), 1)
        self.assertEqual(len(container.inspect['Mounts'][0]['Name']), 65)
        self.assertEqual(container.inspect['Mounts'][0]['Destination'], '/var')
        self.assertTrue(
            container.inspect['Mounts'][0]['Source'].startswith(
                '/var/lib/docker/volumes'),
            msg="Unexpected mount source: {}".format(
                container.inspect['Mount'][0]['Source']))

    def test_named_volumes(self):
        """Make sure that named volumes are correctly registered"""
        volume_name = "control_unittest_volume{}".format(random.randint(1, 65535))
        self.container_volumes.append(volume_name)
        self.image = 'busybox'
        self.conf = {
            "image": self.image,
            "container": {
                "name": self.container_name,
                "hostname": "busybox",
                "volumes": ["{}:/var".format(volume_name)]
            }
        }
        serv = create_service(self.conf, './Controlfile')
        container = Container(serv).create(prod=False)
        container.start()
        self.assertEqual(len(container.inspect['Mounts']), 1)
        self.assertEqual(len(container.inspect['Mounts'][0]['Name']), len(volume_name))
        self.assertEqual(container.inspect['Mounts'][0]['Destination'], '/var')
        self.assertTrue(
            container.inspect['Mounts'][0]['Source'].startswith(
                '/var/lib/docker/volumes'),
            msg="Unexpected mount source: {}".format(
                container.inspect['Mounts'][0]['Source']))

    def test_mounted_volumes(self):
        """Make sure that mounted volumes are correctly registered"""
        import tempfile

        temp_dir = tempfile.TemporaryDirectory()
        self.image = 'busybox'
        self.conf = {
            "image": self.image,
            "container": {
                "name": self.container_name,
                "hostname": "busybox",
                "volumes": ["{}:/var".format(temp_dir.name)]
            }
        }
        serv = create_service(self.conf, './Controlfile')
        container = Container(serv).create(prod=False)
        container.start()
        self.assertEqual(len(container.inspect['Mounts']), 1)
        self.assertEqual(container.inspect['Mounts'][0]['Destination'], '/var')
        self.assertTrue(
            container.inspect['Mounts'][0]['Source'] == temp_dir.name,
            msg="Unexpected mount source: {}".format(
                container.inspect['Mounts'][0]['Source']))
        temp_dir.cleanup()

def setUpModule():
    """Ensure that our test images exist"""
    dclient = docker.Client('unix://var/run/docker.sock')
    dclient.pull('busybox:latest')

if __name__ == '__main__':
    unittest.main()


"""Tests for Qiskti to Braket adapter."""
from unittest import TestCase

from braket.circuits import Circuit, FreeParameter, observables
import numpy as np
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter

from qiskit_braket_provider.providers.adapter import (
    convert_qiskit_to_braket_circuit,
    qiskit_gate_name_to_braket_gate_mapping,
    qiskit_gate_names_to_braket_gates,
    qiskit_to_braket_gate_names_mapping,
    wrap_circuits_in_verbatim_box,
)

class TestAdapter(TestCase):
    """Tests adapter."""

    def test_mappers(self):
        """Tests mappers."""
        self.assertEqual(
            list(sorted(qiskit_to_braket_gate_names_mapping.keys())),
            list(sorted(qiskit_gate_names_to_braket_gates.keys())),
        )

        self.assertEqual(
            list(sorted(qiskit_to_braket_gate_names_mapping.values())),
            list(sorted(qiskit_gate_name_to_braket_gate_mapping.keys())),
        )

    def test_convert_parametric_qiskit_to_braket_circuit(self):
        """Tests convert_qiskit_to_braket_circuit works with parametric circuits."""

        theta = Parameter("θ")
        phi = Parameter("φ")
        lam = Parameter("λ")
        qiskit_circuit = QuantumCircuit(1, 1)
        qiskit_circuit.rz(theta, 0)
        qiskit_circuit.u(theta, phi, lam, 0)
        qiskit_circuit.u(theta, phi, np.pi, 0)
        braket_circuit = convert_qiskit_to_braket_circuit(qiskit_circuit)

        braket_circuit_ans = (
            Circuit()  # pylint: disable=no-member
            .rz(0, FreeParameter("θ"))
            .rz(0, FreeParameter("λ"))
            .rx(0, np.pi / 2)
            .rz(0, FreeParameter("θ"))
            .rx(0, -np.pi / 2)
            .rz(0, FreeParameter("φ"))
            .rz(0, np.pi)
            .rx(0, np.pi / 2)
            .rz(0, FreeParameter("θ"))
            .rx(0, -np.pi / 2)
            .rz(0, FreeParameter("φ"))
        )

        self.assertEqual(braket_circuit, braket_circuit_ans)

    def test_sample_result_type(self):
        """Tests sample result type with observables Z"""

        qiskit_circuit = QuantumCircuit(2, 2)
        qiskit_circuit.h(0)
        qiskit_circuit.cnot(0, 1)
        qiskit_circuit.measure(0, 0)
        braket_circuit = convert_qiskit_to_braket_circuit(qiskit_circuit)

        circuits = (
            Circuit()  # pylint: disable=no-member
            .h(0)
            .cnot(0, 1)
            .sample(observable=observables.Z(), target=0)
        )

        self.assertEqual(braket_circuit, circuits)

class TestVerbatimBoxWrapper(TestCase):
    """Test wrapping in Verbatim box."""

    def test_wrapped_circuits_have_one_instruction_equivalent_to_original_one(self):
        """Test circuits wrapped in verbatim box have correct instructions."""
        circuits = [
            Circuit().rz(1, 0.1).cz(0, 1).rx(0, 0.1),  # pylint: disable=no-member
            Circuit().cz(0, 1).cz(1, 2),  # pylint: disable=no-member
        ]

        wrapped_circuits = wrap_circuits_in_verbatim_box(circuits)

        # Verify circuits comprise of verbatim box
        self.assertTrue(
            all(
                wrapped.instructions[0].operator.name == "StartVerbatimBox"
                for wrapped in wrapped_circuits
            )
        )

        self.assertTrue(
            all(
                wrapped.instructions[-1].operator.name == "EndVerbatimBox"
                for wrapped in wrapped_circuits
            )
        )

        # verify that the contents of the verbatim box are identical
        # to the original circuit
        self.assertTrue(
            all(
                wrapped.instructions[1:-1] == original.instructions
                for wrapped, original in zip(wrapped_circuits, circuits)
            )
        )


from tkinter import *
import tkinter.messagebox
from tkinter import ttk
from tkinter import font
import sqlite3
from patient_form import Patient
from room_form import Room
from employee_form import Employee
from appointment_form import Appointment
from billing_form import Billing

conn=sqlite3.connect("HospitalDB.db")

print("DATABASE CONNECTION SUCCESSFUL")

#Class For Menu
class Menu:
    def __init__(self,master):
        self.master = master
        self.master.title("HOSPITAL MANAGEMENT SYSTEM")
        self.master.geometry("800x600+0+0")
        self.master.config(bg="cadet blue")
        self.frame = Frame(self.master,bg="cadet blue")
        self.frame.pack()

        self.lblTitle = Label(self.frame,text = "MAIN MENU", font="Helvetica 20 bold",bg="cadet blue")
        self.lblTitle.grid(row =0 ,column = 0,columnspan=2,pady=50)

        self.LoginFrame = Frame(self.frame,width=400,height=80,relief="ridge",bg="cadet blue",bd=20)
        self.LoginFrame.grid(row=1,column=0)
        #===========BUTTONS=============
        self.button1 = Button(self.LoginFrame,text = "1.PATIENT REGISTRATION", width =30,font="Helvetica 14 bold",bg="cadet blue",command=self.Patient_Reg)
        self.button1.grid(row=1,column=0,pady=10)

        self.button2 = Button(self.LoginFrame, text="2.ROOM ALLOCATION",width =30,font="Helvetica 14 bold",bg="cadet blue",command=self.Room_Allocation)
        self.button2.grid(row=3,column=0,pady=10)

        self.button3 = Button(self.LoginFrame, text="3.EMPLOYEE REGISTRATION",width =30,font="Helvetica 14 bold",bg="cadet blue",command=self.Employee_Reg)
        self.button3.grid(row=5,column=0,pady=10)

        self.button4 = Button(self.LoginFrame, text="4.BOOK APPOINTMENT",width =30,font="Helvetica 14 bold",bg="cadet blue",command=self.Appointment_Form)
        self.button4.grid(row=7,column=0,pady=10)

        self.button5 = Button(self.LoginFrame, text="5.PATIENT BILL",width =30,font="Helvetica 14 bold",bg="cadet blue",command=self.Billing_Form)
        self.button5.grid(row=9,column=0,pady=10)

        self.button6 = Button(self.LoginFrame, text="6.EXIT",width =30,font="Helvetica 14 bold",bg="cadet blue",command = self.Exit)
        self.button6.grid(row=11,column=0,pady=10)

    #Function to Exit Menu Window
    def Exit(self):
        self.master.destroy()

    #Function to open Patient Registration Window
    def Patient_Reg(self):
        self.newWindow = Toplevel(self.master)
        self.app = Patient(self.newWindow)

    #Function to open Room Allocation Window

    def Room_Allocation(self):
        self.newWindow = Toplevel(self.master)
        self.app = Room(self.newWindow)

    #Function to open Employee Registration Window
    def Employee_Reg(self):
        self.newWindow = Toplevel(self.master)
        self.app = Employee(self.newWindow)

    #Function to open Appointment Window
    def Appointment_Form(self):
        self.newWindow = Toplevel(self.master)
        self.app = Appointment(self.newWindow)

    #Function to open Billing Window
    def Billing_Form(self):
        self.newWindow = Toplevel(self.master)
        self.app = Billing(self.newWindow)


import logging

from src import app

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

application = app.create_app()

if __name__ == "__main__":
    logger.info("Starting the API ...")
    application.run(port=5001, host="0.0.0.0")


#!/usr/bin/env python
###################################

from argparse import ArgumentParser
import sys, urllib2, csv

def write(cogs, infile, outfile):
    if outfile: hout = open(outfile, 'w')
    else: hout = sys.stdout
    hin = open(infile, 'r')
    hincsv = csv.reader(hin, delimiter = '\t')
    houtcsv = csv.writer(hout, delimiter = '\t')
    for i,row in enumerate(hincsv):
        if i==0:
            header= row[1:]
            out = ["Cat1","Cat2","COG"]+header
            houtcsv.writerow(out)
            continue
        cog = row[0]
        try: out = [cogs[cog]["firstcat"],cogs[cog]["secondcat"],cog+" "+cogs[cog]["name"]]+row[1:]
        except KeyError: out = [cog,cog,cog]+row[1:]
        houtcsv.writerow(out)
    hout.close()
    hin.close()

def main():
    parser = ArgumentParser()
    parser.add_argument("-i", "--infile", type=str,
            help="COG table for which to add hierarchy")
    #parser.add_argument("-H", "--hier", type=str,
    #        help="Supply a COG functional hierarchy flatfile. If none is supplied the script attempts to download one from ftp://ftp.ncbi.nih.gov/pub/COG/COG/fun.txt")
    parser.add_argument("-o", "--outfile", type=str,
            help="Write tab-delimited pathway hierarchy to outfile. Defaults to stdout")
    args = parser.parse_args()

    if not args.infile: sys.exit(parser.print_help())

    cogs = ParseWHOG()
    cogs = ParseFUN(cogs)
    write(cogs, args.infile, args.outfile)

def ParseWHOG():
    cogs = {}
    whogurl = "ftp://ftp.ncbi.nih.gov/pub/COG/COG/whog"
    data = urllib2.urlopen(whogurl)
    data = data.read()
    data = data.split("\n")
    for line in data:
        if line=="": continue
        if not line[0]=="[": continue
        items = line.rsplit()
        cats = items[0]
        cog = items[1]
        name = " ".join(items[2:])
        cats = cats.replace("[","")
        cats = cats.replace("]","")
        cogs[cog] = {"name": name, "catletter": cats[0], "firstcat": "", "secondcat": ""}
    return cogs

def ParseFUN(cogs):
    f = urllib2.urlopen("ftp://ftp.ncbi.nih.gov/pub/COG/COG/fun.txt")
    data = f.read()
    data = data.split("\n")
    cats = {}
    for line in data:
        line = line.lstrip()
        if line=="": continue
        if line[0]=="[":
            catletter = line[1]
            name = line.split("]")[1].lstrip()
            name = name.rstrip()
            cats[catletter] = {"secondcat": name, "firstcat":parent}
        else: parent = line
    for cog in cogs.keys():
        catletter = cogs[cog]["catletter"]
        firstcat = cats[catletter]["firstcat"]
        secondcat = cats[catletter]["secondcat"]
        cogs[cog]["firstcat"] = firstcat
        cogs[cog]["secondcat"] = secondcat
    return cogs

if __name__ == '__main__':
    main()


from __future__ import print_function

import argparse
import os

from torch.utils.data import DataLoader
import torchvision
from torchvision import datasets, transforms
import torch
import numpy as np

import random

from diffusion import diffusor
from classification import classification

# ===========================================================
# Training settings
# ===========================================================
parser = argparse.ArgumentParser(description='PyTorch classification')
# hyper-parameters
parser.add_argument('--epoch', type=int, default=200, help='number of epochs to train for')
parser.add_argument('--lr', type=float, default=0.01, help='Learning Rate. Default=0.0001')
parser.add_argument('--gpu', type=int, default=0)
parser.add_argument('--log', type=int, default=1)
parser.add_argument('--batchSize', type=int, default=32, help='training batch size')
parser.add_argument('--decay', type=float, default=0.0001, help='Weight Decay. Default=0.0001')
parser.add_argument('--seed', type=int, default=123, help='random seed to use. Default=123')

# model configuration
parser.add_argument('--model', '-m', type=str, default='diffusion', help='choose which model is going to use')
parser.add_argument('--size', type=int, default=224, help='image size for resize')
parser.add_argument('--diffusion', type=str, default='anisotropic', help='which diffusion')
parser.add_argument('--diffusionCoeff', '--dc', type=float, default=0.001, help='diffusion coefficient')
parser.add_argument('--classifier', type=str, default='ResNet18', help='which classifier')
parser.add_argument('--num_classes', type=int, default=10, help='number of classes')
parser.add_argument('--kernel_size', type=int, default=11, help='kernel size for gaussian kernel')
parser.add_argument('--std', type=float, default=10.5, help='std for gaussian kernel')
parser.add_argument('--title', type=str, default='anisotropic_diffusion')

args = parser.parse_args()

class main:
    def __init__(self):
        self.model = None
        self.train_loader = None
        self.val_loader = None

    def dataLoad(self):
        # ===========================================================
        # Set train dataset & test dataset
        # ===========================================================
        print('===> Loading datasets')

        def seed_worker(self):
            np.random.seed(args.seed)
            random.seed(args.seed)

        transform = transforms.Compose([
            transforms.Resize(args.size),
            transforms.ToTensor(),
            # transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
        ])

        trainset = torchvision.datasets.STL10(root='../../../dataset/stl10', split='train', download=True, transform=transform)
        testset = torchvision.datasets.STL10(root='../../../dataset/stl10', split='test', download=True, transform=transform)

        self.train_loader = torch.utils.data.DataLoader(trainset, batch_size=args.batchSize, shuffle=True, num_workers=2)
        self.val_loader = torch.utils.data.DataLoader(testset, batch_size=args.batchSize, shuffle=False, num_workers=2)

    def modelCall(self):

        if args.model == 'diffusion':          # anisotropic and isotropic diffusion auto-encoder
            self.model = diffusor(args, self.train_loader, self.val_loader, args.diffusion)

        elif args.model == 'classification':   # classification
            self.model = classification(args, self.train_loader, self.val_loader, args.diffusion)

if __name__ == '__main__':
    os.environ["CUDA_DEVICE_ORDER"]="PCI_BUS_ID"
    os.environ["CUDA_VISIBLE_DEVICES"]=str(args.gpu)
    # os.environ["CUDA_VISIBLE_DEVICES"]="0"

    torch.manual_seed(args.seed)
    torch.cuda.manual_seed(args.seed)
    torch.cuda.manual_seed_all(args.seed)
    np.random.seed(args.seed)
    random.seed(args.seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = False

    main = main()
    main.dataLoad()
    main.modelCall()

    main.model.runner()


import requests

class FlightSearch:

    def __init__(self, some_apikey: str, some_date_from: str, some_date_to: str, some_IATA_from: str, some_IATA_to: str,
                 some_api_url: str):
        self.apikey = some_apikey
        self.date_from = some_date_from
        self.date_to = some_date_to
        self.fly_from = some_IATA_from
        self.fly_to = some_IATA_to
        self.url = some_api_url

    def make_headers(self):
        self.headers = {
            "apikey": self.apikey,
            "Content-Encoding": "gzip"
        }
        return self.headers

    def make_parameters(self):
        self.parameters = {
            "fly_from": self.fly_from,
            "fly_to": self.fly_to,
            "date_from": self.date_from,
            "date_to": self.date_to
        }
        return self.parameters

    def make_requests(self):
        """This method makes a request to KIWI.com API """
        response = requests.get(url=self.url, headers=self.headers, params=self.parameters)
        response.raise_for_status()
        kiwi_data = response.json()
        return kiwi_data


import os
from enum import Enum, auto
from typing import Dict, Tuple, List
import time
import subprocess
import platform
from tkinter import *
from tkinter import ttk
from tkinter.filedialog import askopenfilename
import numpy as np
import tensorflow as tf
from PIL import Image, ImageTk
from egg_classifier.image_processor import ImageSplitter, ImageDrawer
from egg_classifier.classifier import Classifier
from egg_classifier.classifier.mobilenetv2_classifier import Mobilenetv2Classifier
from egg_classifier.classifier.histogram_classifier import HistogramClassifier

tf.autograph.set_verbosity(0)

class ClassifierType(Enum):
    MOBILENETV2 = auto()
    HISTOGRAM = auto()

class EggClassifier():
    def __init__(self, number_of_rows: int, number_of_columns: int,
                 offset_x_percent: int, offset_y_percent: int,
                 radius: int, colors: Dict[str, str], font: str,
                 font_size: int, classifier_type: ClassifierType, model_path: str,
                 classes: List[str], prediction_threshold: float,
                 image_size: Tuple[int, int] = (128, 128)) -> None:
        assert len(classes) == 2
        assert prediction_threshold >= 0 and prediction_threshold <= 1
        assert len(colors) == 2

        self.__image_splitter: ImageSplitter = ImageSplitter(number_of_rows, number_of_columns,
                                                             offset_x_percent, offset_y_percent)
        self.__image_drawer: ImageDrawer = ImageDrawer(number_of_rows, number_of_columns, radius,
                                                       colors, font, font_size)
        self.__classes = classes
        self.__prediction_threshold = prediction_threshold
        self.__classifier: Classifier = None
        if classifier_type == ClassifierType.MOBILENETV2:
            self.__classifier = Mobilenetv2Classifier(model_path, image_size)
        else:
            self.__classifier = HistogramClassifier(model_path, image_size)

    def predict(self, image_np: np.ndarray) -> np.ndarray:
        images = self.__image_splitter.split_image(image_np)
        outputs = self.__classifier.predict(images)
        labels = [self.__classes[0] if x <=
                  self.__prediction_threshold else self.__classes[1] for x in outputs]
        output_image = self.__image_drawer.draw(image_np, labels)
        return output_image

class EggClassifierUI():
    def __init__(self, classifier: EggClassifier, image_size: Tuple[int, int]):
        self.__classifier = classifier
        self.__image_size = image_size
        self.__image_tk = None
        self.__delete_images()
        self.__initialize()

    def __initialize(self):
        self.__root = Tk()
        self.__root.title("Egg Classifier")
        self.__root.resizable(False, False)
        self.__master = ttk.Frame(self.__root)
        self.__master.grid(row=0, column=0, padx=8, pady=4)
        file_button = ttk.Button(
            self.__master,
            text="Browse",
            command=self.__load_file
        )
        file_button.grid(row=1, column=0, sticky=(N, W, E, S))

        capture_button = ttk.Button(
            self.__master,
            text="Capture",
            command=self.__capture
        )
        capture_button.grid(row=1, column=1, sticky=(N, W, E, S))

        self.__canvas = Canvas(
            self.__master, width=self.__image_size[0], height=self.__image_size[1])
        self.__canvas.grid(row=0, column=0, columnspan=2, sticky=(N, W, E, S))

    def __load_file(self) -> None:
        file_name = askopenfilename(
            filetypes=[("Image", "*.jpg;*.jpeg;*.png")])
        start_time = time.time()
        self.__predict(file_name)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"Execution Time: {execution_time} seconds")

    def __capture(self) -> None:
        if platform.system() == "Windows":
            return
        subprocess.run([
            "nvgstcapture-1.0",
            "--automate",
            "--capture-auto"
        ])
        image_path = self.__get_image_path()
        if image_path is None:
            print("no captured image found")
            return
        start_time = time.time()
        self.__predict(image_path)
        end_time = time.time()
        execution_time = end_time - start_time
        print(f"Execution Time: {execution_time} seconds")
        self.__delete_images()

    def __predict(self, file_name: str) -> Tuple[Image.Image, float]:
        with Image.open(file_name) as image:
            image_np = np.array(image)
        output_image_np = self.__classifier.predict(image_np)
        output_image = Image.fromarray(output_image_np)
        output_image = output_image.resize(self.__image_size)

        self.__image_tk = ImageTk.PhotoImage(output_image)
        image_label = ttk.Label(self.__canvas, image=self.__image_tk)
        image_label.grid(row=0, column=0, sticky=(N, W, E, S))

    def __delete_images(self) -> None:
        for file_name in os.listdir():
            if file_name.split(".")[-1] == "jpg":
                os.remove(file_name)

    def __get_image_path(self) -> str:
        for file_name in os.listdir():
            if file_name.split(".")[-1] == "jpg":
                return file_name
        return None

    def run(self) -> None:
        self.__root.mainloop()


from flask import Flask, jsonify
app = Flask(__name__)

@app.route("/")
def home():
    return "
Home
"

@app.route("/test_json")
def test_json():
    """Function to test JSON return on web
    """
    name = "Chris"
    age = 34
    degrees = [
        {
            'first_degree': 'AAS Intelligence Operations',
            'second_degree': "BA Honors Economics with a Quantitative Emphasis, Math, Applied Math",
            'third_degree': "MS Quantitative Economics"
        }
    ]

    data = {
        'Name': name,
        'Age': age,
        'Degrees': degrees
    }
    return jsonify(data)

if __name__ == "__main__":
    app.run(debug=True, host="127.0.0.1")


from earl_nema import NemaRC
import pydicom
from pydicom.tag import Tag
import os
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

class NemaPlots():

    def __init__(self, RCs, recons, title):

        ''' Recovery coefficient plots including EARL guidelines
            using RCs generated from NemaRC class

        Parameters:
        RCs (list): List containing NemaRC objects from each recon
        recons (list): List containing strngs with the recon parameters of each element in RCs
        title (str): Title of plot (recon parameters to be compared)
        '''
        self.RCs = RCs
        self.recons = recons
        self.title = title

        # EARL ranges

        #EARL 1
        self.RC_max_1 = np.array([[0.95,1.16],[0.91,1.13],[0.83,1.09],
                                        [0.73,1.01],[0.59,0.85],[0.31,0.49]])
        self.RC_mean_1 = np.array([[0.76,0.89],[0.72,0.85],[0.63,0.78],
                                        [0.57,0.73],[0.44,0.60],[0.27,0.38]])

        #EARL 2
        self.RC_max_2 = np.array([[1.05,1.29],[1.01,1.26],[1.01,1.32],
                                        [1.00,1.38],[0.85,1.22],[0.52,0.88]])
        self.RC_mean_2 = np.array([[0.85,1.0],[0.82,0.97],[0.8,0.99],
                                        [0.76,0.97],[0.63,0.86],[0.39,0.61]])
        self.SUV_peak_2 = np.array([[0.99,1.07],[0.95,1.07],[0.9,1.09],[0.75,0.99],[0.45,0.69],[0.27,0.41]])

        self.spheres = np.array([37, 28, 22, 17, 13, 10])

        sns.set_palette("husl")

    def RCmean(self):

        x = [10,37]
        y = [1,1]

        sns.set_style("white")
        #sns.set_palette("husl")
        plt.figure(figsize=(8,7))
        for RC,recon in zip(self.RCs,self.recons):
            plt.plot(self.spheres,RC.spheres['RC_mean'],marker='o', linestyle = '--',label=recon)

        plt.fill_between(self.spheres, self.RC_mean_1[:,0], self.RC_mean_1[:,1],
                                color='lightblue', alpha=0.2, label='EARL 1')
        plt.fill_between(self.spheres, self.RC_mean_2[:,0], self.RC_mean_2[:,1],
                                color='C4', alpha=0.2, label='EARL 2')
        plt.xlabel('Sphere Diameter (mm)',fontsize = 16)
        plt.plot(x,y,linestyle='--',color='gray')
        plt.ylabel('RC Mean', fontsize = 16)
        plt.ylim(0.4,1.2)
        plt.legend(fontsize = 12,loc='lower right')
        plt.title(self.title + ' RC Mean',fontsize=16)
        plt.show()

    def RCmax(self):

        x = [10,37]
        y = [1,1]

        sns.set_style("white")
        #sns.set_palette("husl")
        plt.figure(figsize=(8,7))
        for RC,recon in zip(self.RCs,self.recons):
            plt.plot(self.spheres,RC.spheres['RC_max'],marker='o', linestyle = '--',label=recon)

        plt.fill_between(self.spheres, self.RC_max_1[:,0], self.RC_max_1[:,1],
                                color='lightblue', alpha=0.2, label='EARL 1')
        plt.fill_between(self.spheres, self.RC_max_2[:,0], self.RC_max_2[:,1],
                                color='C4', alpha=0.2, label='EARL 2')
        plt.xlabel('Sphere Diameter (mm)',fontsize = 16)
        plt.plot(x,y,linestyle='--',color='gray')
        plt.ylabel('RC Max', fontsize = 16)
        plt.ylim(0.4,1.6)
        plt.legend(fontsize = 12,loc='lower right')
        plt.title(self.title + ' RC Max',fontsize=16)
        plt.show()

    def COV(self,xaxis,axis_title):

        sns.set_style("white")
        #sns.set_palette("husl")
        plt.figure(figsize=(8,7))

        for RC,recon,x in zip(self.RCs,self.recons,xaxis):
            plt.errorbar(x,RC.COV,yerr=RC.COV_error, marker='o',label=recon)

        threshold = [0.15,0.15,0.15,0.15,0.15,0.15]
        plt.plot(xaxis,threshold,linestyle = 'dashed',color='gray',label='limit')
        plt.ylabel('COV',fontsize=16)
        plt.xlabel(axis_title,fontsize=16)
        plt.legend(fontsize = 12)
        plt.title(self.title + ' Background COV',fontsize=16)
        plt.show()

    def noise(self):
        cov = []
        for RC in self.RCs:
            cov.append(RC.COV*100)

        return cov

    def bias(self): #1 - SUV mean Mean contrast recovery
        mcr_bias = []
        for RC in self.RCs:
            #mcr_bias.append(np.abs(1-RC.MCR_mean)*100)
            mcr_bias.append((RC.MCR_mean-1)*100)
        return mcr_bias

    def max_bias(self): #1 - SUV mean Mean contrast recovery
        mcr_max_bias = []
        for RC in self.RCs:
            #mcr_max_bias.append(np.abs(1-RC.MCR_max)*100)
            mcr_max_bias.append((RC.MCR_max-1)*100)

        return mcr_max_bias

    # Noise vs Bias plots

    def cov_v_mcr(self): #nvb = CoV (noise) vs MCR (average SUV mean bias of all 6 spheres)

        cov = []
        mcr_bias = []
        for RC in self.RCs:
            cov.append(RC.COV)
            mcr_bias.append(np.abs(1-RC.MCR_mean))

        sns.set_style("white")
        plt.figure(figsize=(8,7))

        plt.plot(cov,mcr_bias)

        plt.xlabel(r'Noise (\% COV)',fontsize=16)
        plt.ylabel(r'Bias (mean \% recovery)',fontsize=16)
        plt.title(self.title + ' MCR bias vs COV',fontsize=16)
        plt.show()

    def cov_v_max_mcr(self):

        cov = []
        mcr_bias = []
        for RC in self.RCs:
            cov.append(RC.COV)
            mcr_bias.append(1-RC.MCR_max)

        sns.set_style("white")
        plt.figure(figsize=(8,7))

        plt.plot(cov,mcr_bias)

        plt.xlabel('Noise (COV)',fontsize=16)
        plt.ylabel('Bias (SUV max)',fontsize=16)
        plt.title(self.title + ' MCR max bias vs COV',fontsize=16)
        plt.show()

    def cov_time(self):

        cov_time = []
        scan_duration = [19,38,75,150,300,600]
        for RC in self.RCs:
            cov_time.append(RC.COV)

        sns.set_style("white")
        plt.figure(figsize=(8,7))

        plt.plot(cov_time,scan_duration)

        plt.xlabel('Scan Duration (s)',fontsize=16)
        plt.ylabel('COV',fontsize=16)
        plt.title(self.title + ' MCR max bias vs COV',fontsize=16)
        plt.show()
        return cov_time


from django.urls import path
from App import views

urlpatterns= [
    # path('admin/', admin.site.urls),
    path('', views.inicio, name="Inicio"),
    path('eventos', views.eventos, name="Eventos"),
    path('eventos/', views.eventos, name="EventosBuscar"),
    path('bandas', views.bandas, name="Bandas"),
    path('bandas/', views.bandas, name="BandasBuscar"),
    path('instrumentos', views.instrumentos, name="Instrumentos"),
    path('instrumentos/', views.instrumentos, name="InstrumentosBuscar")
]