import sys
import time
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import numpy as np
from matplotlib.backends.qt_compat import QtCore
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
from itertools import *
#from matplotlib.pyplot import cm

from matplotlib.backends.qt_compat import QtCore, QtWidgets, is_pyqt5
if is_pyqt5():
    from matplotlib.backends.backend_qt5agg import (
        FigureCanvas, NavigationToolbar2QT as NavigationToolbar)
 
import random
import ntpath
from Classes import *
from TraceData import TraceData
 
class App(QMainWindow):
 
    def __init__(self, TraceData):
        super().__init__()
        self.left = 10
        self._main = QWidget()
        self.setCentralWidget(self._main)
        self.top = 10
        self.width = 640
        self.height = 400
        self.Data = TraceData
        
        self.setWindowTitle("DysGraphy")
        self.SelectedPictos = [None, None] #[Pict1, Pict2]
        self.SelectedStrokes = [None, None] #[Stroke1, Stroke2]
        self.PictTypes = self.loadPictTypes()
        
        
        #self.m = PlotCanvas()
        
        self.vLayout = QVBoxLayout(self._main)

        self.buttonsWidget= QWidget()
        self.buttonLayout = self.initButtons()


        self.StatusBar = QWidget()
        self.statusBarLayout = self.initStatusBar()
        self.StatusBar.setAutoFillBackground(True)
        p = self.StatusBar.palette()
        p.setColor(self.StatusBar.backgroundRole(), Qt.lightGray)
        self.StatusBar.setPalette(p)


        self.ListWidget = QWidget()
        self.ListLayout = self.initList()

        self.canvas = FigureCanvas(Figure(figsize=(30, 3)))
        self.addToolBar(QtCore.Qt.BottomToolBarArea,
                        NavigationToolbar(self.canvas, self))


        self.dynamic_ax = self.canvas.figure.subplots()
        self.dynamic_ax.set_xlabel('L1 [px]')
        self.dynamic_ax.set_ylabel('L2 [px]')
        #self.canvas.addStrut(1000)


        self.bodyWidget = QWidget()
        self.hlayout= QHBoxLayout(self.bodyWidget)
        self.hlayout.addWidget(self.buttonsWidget)
        self.hlayout.addWidget(self.canvas)
        self.hlayout.addWidget(self.ListWidget)
        self.vLayout.addWidget(self.StatusBar)
        self.vLayout.addWidget(self.bodyWidget)

    def initList(self):

        self.pictTypeCBBWidget = QWidget()
        self.pictTypeCBB1 = QComboBox(self.pictTypeCBBWidget)
        self.pictTypeCBB2 = QComboBox(self.pictTypeCBBWidget)
        pictTypeLay = QVBoxLayout(self.pictTypeCBBWidget)
        self.pictTypeCBB1.addItems(self.PictTypes)
        self.pictTypeCBB2.addItems(self.PictTypes)
        self.pictTypeCBB1.setCurrentIndex(-1)
        self.pictTypeCBB2.setCurrentIndex(-1)
        self.pictTypeCBB1.setEnabled(False)
        self.pictTypeCBB2.setEnabled(False)
        self.pictTypeCBB1.currentIndexChanged[int].connect(self.CBB1Changed)
        self.pictTypeCBB2.currentIndexChanged[int].connect(self.CBB2Changed)

        pictTypeLay.addStretch(1)
        pictTypeLay.addWidget(self.pictTypeCBB1)
        pictTypeLay.addStretch(1)
        pictTypeLay.addWidget(self.pictTypeCBB2)
        pictTypeLay.addStretch(1)

        self.pictListWidget = QWidget()
        pictListLay = QVBoxLayout(self.pictListWidget)
        self.pictList1 = QListWidget()
        self.pictList2 = QListWidget()
        pictListLabel = QLabel(self)
        pictListLabel.setText("Found Pictos: ")
        self.pictList1.itemClicked.connect(self.pictSelected1)
        self.pictList2.itemClicked.connect(self.pictSelected2)
        self.pictList2.setStyleSheet("border: 2px solid red;")
        self.pictList1.setStyleSheet("border: 2px solid green;")

        pictListLay.addWidget(pictListLabel)
        pictListLay.addWidget(self.pictList1)
       
        pictListLay.addWidget(self.pictList2)
        pictListLay.addStrut(200)
        pictListLay.addStretch(1)
        

        self.strokeListWidget = QWidget()
        strokeListLay = QVBoxLayout(self.strokeListWidget)

        self.strokeList1 = MyListWidget(self)
        self.strokeList2 = MyListWidget(self)
        strokeListLabel = QLabel(self)
        strokeListLabel.setText("Strokes: ")
        self.strokeList1.setDragEnabled(True)
        self.strokeList2.setDragEnabled(True)
        self.sList1model=self.strokeList1.model()
        self.sList2model=self.strokeList2.model()
        self.strokeList1.ID = 1
        self.strokeList2.ID = 2
        self.strokeList1.itemClicked.connect(self.strokeSelected1)
        self.strokeList2.itemClicked.connect(self.strokeSelected2)

        strokeListLay.addWidget(strokeListLabel)
        strokeListLay.addWidget(self.strokeList1)
        strokeListLay.addWidget(self.strokeList2)
        strokeListLay.addStretch(1)

        hLay = QHBoxLayout(self.ListWidget)




        hLay.addWidget(self.pictTypeCBBWidget)
        hLay.addWidget(self.pictListWidget)
        hLay.addWidget(self.strokeListWidget)
        
       
        return hLay

    def setSelectedP(self, index, item):
        self.SelectedPictos[index] = item
        self.DrawPictos()

    def setSelectedS(self, index, item):
        self.SelectedStrokes[index] = item
        self.DrawPictos()

    def strokeSelected1(self, item):
        self.setSelectedS(0, int(item.text()))

    def strokeSelected2(self, item):
        self.setSelectedS(1, int(item.text()))

    def CBB1Changed(self, item):
        if item == -1:
            return False
        data = self.pictTypeCBB1.currentText()
        self.Data.Pictos[self.SelectedPictos[0]].ExerciseType = data
        self.Data.Pictos[self.SelectedPictos[0]].ExerciseTypeInd = item
        self.updatePictLists()


    def CBB2Changed(self, item):
        if item == -1:
            return False
        data = self.pictTypeCBB2.currentText()
        self.Data.Pictos[self.SelectedPictos[1]].ExerciseType = data
        self.Data.Pictos[self.SelectedPictos[1]].ExerciseTypeInd = item
        self.updatePictLists()

    def pictSelected1(self, item):
        self.strokeList1.clear()
        text = item.text()
        number = text.split("---")[0]

        self.strokeList1.selectedPict=int(number)
        self.setSelectedP(0, self.strokeList1.selectedPict)
        self.pictTypeCBB1.setCurrentIndex(self.Data.Pictos[self.strokeList1.selectedPict].ExerciseTypeInd)
        self.pictTypeCBB1.setEnabled(True)
        
        for s in self.Data.Pictos[int(number)].sIndex:
            self.strokeList1.addItem(str(s))

    def pictSelected2(self, item):
        self.strokeList2.clear()
        text = item.text()
        number = text.split("---")[0]

        self.strokeList2.selectedPict=int(number)
        self.setSelectedP(1, self.strokeList2.selectedPict)
        self.pictTypeCBB2.setCurrentIndex(self.Data.Pictos[self.strokeList2.selectedPict].ExerciseTypeInd)

        self.pictTypeCBB2.setEnabled(True)
        for s in self.Data.Pictos[int(number)].sIndex:
            self.strokeList2.addItem(str(s))

    def initDummyList(self):
        lay = QVBoxLayout(self.ListWidget)
        self.l = QListWidget()
        self.l.addItem("test")
        lay.addWidget(self.l)
        return lay

    def initStatusBar(self):
        lay = QHBoxLayout(self.StatusBar)
        self.pictCount = QLabel(self)

        self.fileName = QLabel(self)

        lay.addWidget(self.fileName)
        lay.addWidget(self.pictCount)
        
        return lay

    def DoIt(self):
        file = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        self.Data.traceDataToFile(file)

    def generateLAB(self):
        file = str(QFileDialog.getExistingDirectory(self, "Select Directory"))
        self.Data.generateLabFile(file)
 
    def initButtons(self):
        lay = QVBoxLayout(self.buttonsWidget)
        
        capWidget = QWidget()
        capLay = QHBoxLayout(capWidget)

        self.SaveSVCButton = QPushButton('Save to file', self)
        self.SaveSVCButton.setEnabled(False)
        self.SaveSVCButton.clicked.connect(lambda: self.DoIt())

        self.SaveLABButton = QPushButton('Generate LAB file', self)
        self.SaveLABButton.setEnabled(False)
        self.SaveLABButton.clicked.connect(lambda: self.generateLAB())

        self.ProcessButton = QPushButton('Process', self)
        self.ProcessButton.setEnabled(False)
        self.ProcessButton.clicked.connect(lambda: self.solve())

        self.openButton = QPushButton('Open file', self)
        self.openButton.clicked.connect(lambda: self.openFileNameDialog())

        caption1 = QLabel(self)
        caption1.setText("Sensitivity (0-1000): ")
        #caption1.setAttribute(Qt.WA_TranslucentBackground, True)
        

        self.proximityConst = QLineEdit(self)
        self.proximityConst.setText(str(self.Data.proximityConst))
        self.onlyInt = QIntValidator(0, 1000)
        self.proximityConst.setValidator(self.onlyInt)
        capLay.addWidget(caption1)
        capLay.addWidget(self.proximityConst)

        lay.addWidget(self.openButton)
        lay.addWidget(self.ProcessButton)
        lay.addWidget(capWidget)
        lay.addStretch(1)
        lay.addWidget(self.SaveLABButton)
        lay.addWidget(self.SaveSVCButton)
        

        #lay.addWidget(capWidget)
        return lay

    def openFileNameDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getOpenFileName(self,"QFileDialog.getOpenFileName()", "","TraceData File (*.svc)", options=options)
        if fileName:
            self.Data.__init__()
            self.Data.parent = self
            self.defaultGUI()
            self.fileName.setText("File name: " + ntpath.basename(fileName))
            self.Data.fileToTraceData(fileName)
            self.Data.translate()
            self.drawDefault()
            self.ProcessButton.setEnabled(True)

    def defaultGUI(self):
            self.SelectedPictos = [None, None] 
            self.SelectedStrokes = [None, None]
            self.clearAllWidgets()

    def clearAllWidgets(self):
        self.strokeList2.clear()
        self.strokeList1.clear()
        self.pictList1.clear()
        self.pictList2.clear()
        self.pictTypeCBB1.setCurrentIndex(-1)
        self.pictTypeCBB2.setCurrentIndex(-1)
        self.pictTypeCBB1.setEnabled(False)
        self.pictTypeCBB2.setEnabled(False)
        self.SaveSVCButton.setEnabled(False)
        self.SaveLABButton.setEnabled(False)


    def loadPictTypes(self):
        with open("PictType.txt") as f:
            content = f.readlines()
            content = [x.strip() for x in content] 
            return content

    def drawHighlights(self):
        n=5
        m=3
        if self.SelectedPictos[0] != None:
            self.renderSquareStrafed([self.Data.Pictos[self.SelectedPictos[0]].Boundaries[1], self.Data.Pictos[self.SelectedPictos[0]].Boundaries[3]], [self.Data.Pictos[self.SelectedPictos[0]].Boundaries[0], self.Data.Pictos[self.SelectedPictos[0]].Boundaries[2]])
        if self.SelectedPictos[1] != None:
            self.renderSquareDotted([self.Data.Pictos[self.SelectedPictos[1]].Boundaries[1], self.Data.Pictos[self.SelectedPictos[1]].Boundaries[3]], [self.Data.Pictos[self.SelectedPictos[1]].Boundaries[0], self.Data.Pictos[self.SelectedPictos[1]].Boundaries[2]])
        if self.SelectedStrokes[0] != None:
            self.dynamic_ax.scatter(self.Data.StrokesObj[self.SelectedStrokes[0]].Points[::n,0], self.Data.StrokesObj[self.SelectedStrokes[0]].Points[::n,1], marker='+', s=5, c="#33FF42")
            self.dynamic_ax.scatter(self.Data.StrokesObj[self.SelectedStrokes[0]].Points[::m,0], self.Data.StrokesObj[self.SelectedStrokes[0]].Points[::m,1], marker='+', s=5, c="#60693F")
        if self.SelectedStrokes[1] != None:
            self.dynamic_ax.scatter(self.Data.StrokesObj[self.SelectedStrokes[1]].Points[::n,0], self.Data.StrokesObj[self.SelectedStrokes[1]].Points[::n,1], marker='x', s=5, c="#FF6B74")
            self.dynamic_ax.scatter(self.Data.StrokesObj[self.SelectedStrokes[1]].Points[::m,0], self.Data.StrokesObj[self.SelectedStrokes[1]].Points[::m,1], marker='x', s=5, c="#345A56")


    def renderSquareStrafed(self, leftDown = [0, 0], rightUp = [0, 0]):
        self.dynamic_ax.plot([leftDown[0], rightUp[0]], [leftDown[1], leftDown[1]], color='#006600', linestyle='--', linewidth=1)
        self.dynamic_ax.plot([leftDown[0], rightUp[0]], [rightUp[1], rightUp[1]], color='#006600', linestyle='--', linewidth=1)
        self.dynamic_ax.plot([leftDown[0], leftDown[0]], [leftDown[1], rightUp[1]], color='#006600', linestyle='--', linewidth=1)
        self.dynamic_ax.plot([rightUp[0], rightUp[0]], [leftDown[1], rightUp[1]], color='#006600', linestyle='--', linewidth=1)

    def renderSquareDotted(self, leftDown = [0, 0], rightUp = [0, 0]):
        self.dynamic_ax.plot([leftDown[0], rightUp[0]], [leftDown[1], leftDown[1]], color='#cc0000', linestyle=':', linewidth=2)
        self.dynamic_ax.plot([leftDown[0], rightUp[0]], [rightUp[1], rightUp[1]], color='#cc0000', linestyle=':', linewidth=2)
        self.dynamic_ax.plot([leftDown[0], leftDown[0]], [leftDown[1], rightUp[1]], color='#cc0000', linestyle=':', linewidth=2)
        self.dynamic_ax.plot([rightUp[0], rightUp[0]], [leftDown[1], rightUp[1]], color='#cc0000', linestyle=':', linewidth=2)

    def drawDefault(self):
            self.Data.drawDefault()
            self.dynamic_ax.set_xlabel('L1 [px]')
            self.dynamic_ax.set_ylabel('L2 [px]')
            #self.dynamic_ax.clear()
            #if np.size(self.Data.traceOff, 0)>6:
            #    self.dynamic_ax.scatter(self.Data.traceOff[:,0], self.Data.traceOff[:,1], marker='o', s=0.25, c="m")
            #if np.size(self.Data.traceP1, 0)>6:
            #    self.dynamic_ax.scatter(self.Data.traceP1[:,0], self.Data.traceP1[:,1], marker='o', s=0.25, c="b")
            #if np.size(self.Data.traceP2, 0)>6:
            #    self.dynamic_ax.scatter(self.Data.traceP2[:,0], self.Data.traceP2[:,1], marker='o', s=0.25, c="b")
            #if np.size(self.Data.traceP3, 0)>6:
            #    self.dynamic_ax.scatter(self.Data.traceP3[:,0], self.Data.traceP3[:,1], marker='o', s=0.25, c="b")
            #if np.size(self.Data.traceP4, 0)>6:
            #    self.dynamic_ax.scatter(self.Data.traceP4[:,0], self.Data.traceP4[:,1], marker='o', s=0.25, c="b")
            #self.dynamic_ax.figure.canvas.draw()

    def updatePictos(self, ID, pictID):
        if self.strokeList1.selectedPict != self.strokeList2.selectedPict:
            new = None
            if ID == 1:
                items = [] 
                for x in range(self.strokeList1.count()):
                    items.append(int(self.strokeList1.item(x).text()))
                for item in items:
                    matched = False
                    for sInd in self.Data.Pictos[pictID].sIndex:
                        if sInd==item: matched = True
                    if matched == False:
                        new = item
                for i in self.Data.Pictos:
                    for s in range(len(i.sIndex)):
                        if i.sIndex[s] == new:
                            i.sIndex.pop(s)
                            if len(i.sIndex) == 0:
                                i.valid=False
                            break
                self.Data.Pictos[pictID].sIndex.append(new)
                self.Data.updateBound(self.Data.Pictos[pictID], new)
                self.Data.Pictos[self.strokeList2.selectedPict].findBoundaries()

            
            if ID == 2:
                items = [] 
                for x in range(self.strokeList2.count()):
                    items.append(int(self.strokeList2.item(x).text()))
                for item in items:
                    matched = False
                    for sInd in self.Data.Pictos[pictID].sIndex:
                        if sInd==item: matched = True
                    if matched == False:
                        new = item
                for i in self.Data.Pictos:
                    for s in range(len(i.sIndex)):
                        if i.sIndex[s] == new:
                            i.sIndex.pop(s)
                            if len(i.sIndex) == 0:
                                i.valid=False
                            break
                self.Data.Pictos[pictID].sIndex.append(new)
                self.Data.updateBound(self.Data.Pictos[pictID], new)
                self.Data.Pictos[self.strokeList1.selectedPict].findBoundaries()
        self.Data.sortStrokeIndexes()
        self.Data.assignOffTrace()
        self.updatePictLists()
        self.strokeList2.clear()
        for s in self.Data.Pictos[int(self.strokeList2.selectedPict)].sIndex:
            self.strokeList2.addItem(str(s))    
        self.strokeList1.clear()
        for s in self.Data.Pictos[int(self.strokeList1.selectedPict)].sIndex:
            self.strokeList1.addItem(str(s))
        
        self.DrawPictos()
        
        

    def solve(self):
        fName = self.Data.fileName
        data = self.Data.data
        self.Data.__init__()
        self.Data.parent = self
        self.Data.fileName = fName
        self.Data.data = data
        self.Data.proximityConst = int(self.proximityConst.text())
        start = time.time()
        self.Data.basicSolve()
        end = time.time()
        print(end-start)
        count = 0
        for p in self.Data.Pictos:
            if p.valid:
                count+=1
        if count>0:
            self.Data.atLeastOne = count
            self.SaveSVCButton.setEnabled(True)
            self.SaveLABButton.setEnabled(True)
        self.pictCount.setText("Pictos found: " + str(count))
        self.updatePictLists()
        self.DrawPictos()

    def updatePictLists(self):
        self.pictList1.clear()
        self.pictList2.clear()
        for p in self.Data.Pictos:
            if p.valid:
                if p.ExerciseType!=None:
                    self.pictList1.addItem(str(p.pictIndex) +" --- " + p.ExerciseType)
                    self.pictList2.addItem(str(p.pictIndex) +" --- " + p.ExerciseType)
                else:
                    self.pictList1.addItem(str(p.pictIndex))
                    self.pictList2.addItem(str(p.pictIndex))


    def DrawPictos(self):
        self.Data.DrawPictos()
        self.dynamic_ax.set_xlabel('L1 [px]')
        self.dynamic_ax.set_ylabel('L2 [px]')
        #self.dynamic_ax.clear()
        #self.drawHighlights()
        #try:
            
        #    count = 0
        #    for p in self.Data.Pictos:
        #        if p.valid:
        #            count +=1
        #    lino = np.linspace(0,1,num = count)
        #    duha = plt.cm.rainbow(lino)
        #    randC=iter.cycle(duha)


        #    for pict in self.Data.Pictos:
        #        if pict.valid:
        #            a = next(randC)

        #            for s in pict.sIndex:

        #                self.dynamic_ax.scatter(self.Data.StrokesObj[s].Points[:,0], self.Data.StrokesObj[s].Points[:,1], marker='o', s=0.1, c=a)
        #    self.dynamic_ax.figure.canvas.draw()
        #except Exception as ex:
        #    print(ex)
