import numpy as np
import os
from qtpy import QtGui, QtCore, QtWidgets
import sharppy.sharptab as tab
from sharppy.sharptab.constants import *
import sharppy.databases.sars as sars
import platform
from datetime import datetime
## routine written by Kelton Halbert
## keltonhalbert@ou.edu
__all__ = ['backgroundAnalogues', 'plotAnalogues']
[docs]class backgroundAnalogues(QtWidgets.QFrame):
    '''
    Handles drawing the background frame for the
    SARS window.
    '''
    def __init__(self):
        ''' Calls the initUI function to initialize
            the background frame. Inherits from the
            QtWidgets.QFrame Object.
        '''
        super(backgroundAnalogues, self).__init__()
        self.initUI()
[docs]    def initUI(self):
        '''
        Initializes the frame.
        
        The frame is drawn on a QPixmap, 
        and is not rendered visible in this function.
        '''
        ## set the frame stylesheet
        self.setStyleSheet("QFrame {"
            "  background-color: rgb(0, 0, 0);"
            "  border-width: 1px;"
            "  border-style: solid;"
            "  border-color: #3399CC;}")
        ## Set the padding constants
        self.lpad = 3; self.rpad = 5
        self.tpad = 5; self.bpad = 5
        ## set the window metrics (height, width)
        self.wid = self.size().width()
        self.hgt = self.size().height()
        self.tlx = self.rpad; self.tly = self.tpad
        self.brx = self.wid; self.bry = self.hgt
        fsize1 = np.floor(.09 * self.hgt)
        fsize2 = np.floor(.07 * self.hgt)
        fsize3 = np.floor(.06 * self.hgt)
        self.tpad = np.floor(.03 * self.hgt)
        ## set various fonts
        self.title_font = QtGui.QFont('Helvetica', fsize1)
        self.plot_font = QtGui.QFont('Helvetica', fsize2)
        self.match_font = QtGui.QFont('Helvetica', fsize3)
        ## get the metrics on the fonts. This is used to get their size.
        self.title_metrics = QtGui.QFontMetrics( self.title_font )
        self.plot_metrics = QtGui.QFontMetrics( self.plot_font )
        self.match_metrics = QtGui.QFontMetrics( self.match_font )
        ## get the height of each font. This is so that we can do propper font aligning
        ## when drawing text
        if platform.system() == "Windows":
            fsize1 -= self.title_metrics.descent()
            fsize2 -= self.plot_metrics.descent()
            fsize3 -= self.match_metrics.descent()
            self.title_font = QtGui.QFont('Helvetica', fsize1)
            self.plot_font = QtGui.QFont('Helvetica', fsize2)
            self.match_font = QtGui.QFont('Helvetica', fsize3)
            ## get the metrics on the fonts. This is used to get their size.
            self.title_metrics = QtGui.QFontMetrics( self.title_font )
            self.plot_metrics = QtGui.QFontMetrics( self.plot_font )
            self.match_metrics = QtGui.QFontMetrics( self.match_font )
		
        self.title_height = self.title_metrics.xHeight() + self.tpad
        self.plot_height = self.plot_metrics.xHeight() + self.tpad
        self.match_height = self.match_metrics.xHeight() + self.tpad
        ## this variable gets set and used by other functions for knowing
        ## where in pixel space the last line of text ends
        self.ylast = self.tpad
        self.text_start = 0
        ## placement of supercell vs hail
        self.divide = (self.brx / 6)*3+10
        self.selectRect = None
        ## The widget will be drawn on a QPixmap
        self.plotBitMap = QtGui.QPixmap(self.width()-2, self.height()-2)
        self.plotBitMap.fill(self.bg_color)
        ## plot the background
        self.plotBackground() 
    
[docs]    def draw_frame(self, qp):
        '''
        Draws the background frame and the text headers.
        '''
        ## initialize a white pen with thickness 1 and a solid line
        pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine)
        qp.setPen(pen)
        
        ## make the initial x value relative to the width of the frame
        x1 = self.brx / 6
        self.ylast = self.tpad
        ## use the larger title font to plot the title, and then
        ## add to self.ylast the height of the font + padding
        qp.setFont(self.title_font)
        rect0 = QtCore.QRect(0, self.ylast, self.brx, self.title_height)
        qp.drawText(rect0, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
            'SARS - Sounding Analogue System')
        self.ylast += (self.title_height + self.tpad)
        
        ## draw some lines to seperate the hail and supercell windows,
        ## then add to the running sum for vertical placement
        qp.drawLine(0, self.ylast, self.brx, self.ylast)
        qp.drawLine(self.brx/2, self.ylast, self.brx/2, self.bry)
        self.ylast += self.tpad
        
        ## plot the text for the hail and supercell windows using the running
        ## ylast sum
        qp.setFont(self.plot_font)
        rect1 = QtCore.QRect(x1*1, self.ylast, x1, self.plot_height)
        qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
            'SUPERCELL')
            
        rect2 = QtCore.QRect(x1*4, self.ylast, x1, self.plot_height)
        qp.drawText(rect2, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
            'SGFNT HAIL')
        ## Add to the running sum once more for future text
        self.ylast += (self.title_height)
        ## the hail and supercell windows both need to have a vertical starting reference
        self.text_start = self.ylast 
    
    
[docs]    def resizeEvent(self, e):
        '''
        Handles when the window gets resized.
        '''
        self.initUI() 
[docs]    def plotBackground(self):
        '''
        Handles drawing the text background.
        
        This draws onto a QPixmap.
        '''
        ## initialize a QPainter objext
        qp = QtGui.QPainter()
        qp.begin(self.plotBitMap)
        ## draw the frame
        self.draw_frame(qp)
        qp.end()  
[docs]class plotAnalogues(backgroundAnalogues):
    updatematch = QtCore.Signal(str)
    '''
    Handles the non-background plotting
    of the SARS window. This inherits a
    backgroundAnalogues Object that
    takes care of drawing the frame
    background onto a QPixmap. This will
    inherit that QPixmap and continue 
    drawing on it, finally rendering the
    QPixmap via the function paintEvent.
    '''
    def __init__(self):
        '''
        Initializes the data needed for drawing the
        data onto the QPixmap. 
        
        Parameters
        ----------
        prof: a Profile object
        self.view.setDataSource(self.data_sources[self.model], self.run)
        
        '''
        ## get the surfce based, most unstable, and mixed layer
        ## parcels to use for indices, as well as the sounding
        ## profile itself.
        self.bg_color = QtGui.QColor('#000000')
        self.fg_color = QtGui.QColor('#ffffff')
        self.use_left = False
        super(plotAnalogues, self).__init__()
        self.prof = None 
[docs]    def setProf(self, prof):
        self.prof = prof
        if self.use_left:
            self.hail_matches = prof.left_matches
            self.sup_matches = prof.left_supercell_matches
        else:
            self.hail_matches = prof.right_matches
            self.sup_matches = prof.right_supercell_matches
        self.ybounds_hail = np.empty((len(self.hail_matches[0]),2))
        self.ybounds_sup = np.empty((len(self.sup_matches[0]),2))
        self.ylast = self.tpad
        self.clearData()
        self.plotBackground()
        self.plotData()
        self.update() 
[docs]    def setPreferences(self, update_gui=True, **prefs):
        self.bg_color = QtGui.QColor(prefs['bg_color'])
        self.fg_color = QtGui.QColor(prefs['fg_color'])
        if update_gui:
            if self.use_left:
                self.hail_matches = self.prof.left_matches
                self.sup_matches = self.prof.left_supercell_matches
            else:
                self.hail_matches = self.prof.right_matches
                self.sup_matches = self.prof.right_supercell_matches
            self.ybounds_hail = np.empty((len(self.hail_matches[0]),2))
            self.ybounds_sup = np.empty((len(self.sup_matches[0]),2))
            self.clearData()
            self.plotBackground()
            self.plotData()
            self.update() 
[docs]    def setDeviant(self, deviant):
        self.use_left = deviant == 'left'
        if self.use_left:
            self.hail_matches = self.prof.left_matches
            self.sup_matches = self.prof.left_supercell_matches
        else:
            self.hail_matches = self.prof.right_matches
            self.sup_matches = self.prof.right_supercell_matches
        self.ybounds_hail = np.empty((len(self.hail_matches[0]),2))
        self.ybounds_sup = np.empty((len(self.sup_matches[0]),2))
        self.clearData()
        self.plotBackground()
        self.plotData()
        self.update() 
[docs]    def resizeEvent(self, e):
        '''
        Handles when the window is resized.
        
        Parameters
        ----------
        e: an Event object
        
        '''
        super(plotAnalogues, self).resizeEvent(e)
        ## if the window is resized, replot the data
        ## in the QPixmap.
        self.plotData() 
    
[docs]    def paintEvent(self, e):
        '''
        Handles drawing the QPixmap onto the
        widget.
        
        Parameters
        ----------
        e: an Event object
        
        '''
        super(plotAnalogues, self).paintEvent(e)
        qp = QtGui.QPainter()
        qp.begin(self)
        qp.drawPixmap(1, 1, self.plotBitMap)
        qp.end() 
[docs]    def clearData(self):
        '''
        Handles the clearing of the pixmap
        in the frame.
        '''
        self.plotBitMap = QtGui.QPixmap(self.width(), self.height())
        self.plotBitMap.fill(self.bg_color) 
[docs]    def plotData(self):
        '''
        Handles the drawing of the SARS
        matches onto the QPixmap.
        '''
        if self.prof is None:
            return
        ## initialize a QPainter object
        qp = QtGui.QPainter()
        qp.begin(self.plotBitMap)
        ## draw the matches
        self.drawSARS(qp, type='HAIL')
        self.drawSARS(qp, type='TOR')
        qp.end() 
    
[docs]    def drawSARS(self, qp, **kwargs):
        '''
        This draws the SARS matches.
        
        Parameters
        ----------
        qp: a QtGui.QPainter Object
        type: A string for the type of 
            SARS matches. 'HAIL' for 
            hail matches and 'TOR' for 
            supercell matches.
        '''
        x1 = self.brx / 6
        ## get the type of matches, and determine
        ## which side of the frame the matches will
        ## be plotted in.
        type = kwargs.get('type', 'HAIL')
        if type == 'TOR':
            self.matches = self.sup_matches
            sigstr = 'TOR'
            ## this is the horizontal placement
            ## of the text in the frame. Valid
            ## integers are from 0-6.
            place = 1
            ## the quality match date [0] and the type/size
            ## [1] palcement are set in this tuple.
            place2 = (self.lpad, (self.brx/2.) - x1 * 3./4. + 2)
            self.ybounds = self.ybounds_sup
        else:
            self.matches = self.hail_matches
            sigstr = 'SIG'
            ## this is the horizontal placement
            ## of the text in the frame. Valid
            ## integers are from 0-6.
            place = 4
            ## the quality match date [0] and the type/size
            ## [1] palcement are set in this tuple.
            place2 = (x1*3+7, x1*5.5-5)
            self.ybounds = self.ybounds_hail
        ## if there are no matches, leave the function to prevent crashing
        pen = QtGui.QPen(self.fg_color, 1, QtCore.Qt.SolidLine)
        if self.matches[0].size == 0:
            pen.setColor(self.fg_color)
            qp.setPen(pen)
            qp.setFont(self.match_font)
            ## draw the text 2/5 from the top
            rect2 = QtCore.QRect(x1*place, self.bry * (2./5.), x1, self.match_height)
            qp.drawText(rect2, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
                'No Quality Matches')
        else:
            ## set the pen, font
            qp.setPen(pen)
            qp.setFont(self.plot_font)
            ## self.ylast has to be this way in order to plot relative to the bottom
            self.ylast = (self.bry - self.bpad*3)
            
            ## get various data to be plotted
            sig_prob = tab.utils.INT2STR( np.around( self.matches[-1]*100 ) )
            sig_str = 'SARS: ' + sig_prob + '% ' + sigstr
            num_matches = tab.utils.INT2STR( self.matches[-3] )
            match_str = '(' + num_matches + ' loose matches)'
            
            ## if there are more than 0 loose matches, draw
            ## draw the match statistics
            if self.matches[-3] > 0:
                qp.setFont(self.match_font)
                ## set the color of the font
                if self.matches[-1]*100. >= 50.:
                    pen.setColor(QtCore.Qt.magenta)
                    qp.setPen(pen)
                else:
                    pen.setColor(self.fg_color)
                    qp.setPen(pen)
                ## draw the text
                rect0 = QtCore.QRect(x1*place, self.ylast, x1, self.match_height)
                qp.drawText(rect0, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
                            sig_str)
                ## since we start at the bottom and move up, subtract the height instead of add
                self.ylast -= (self.match_height + self.bpad)
                
                rect1 = QtCore.QRect(x1*place, self.ylast, x1, self.match_height)
                qp.drawText(rect1, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
                    match_str)
            ## If not, don't do anything
            else:
                pass
            
            ## if there are no quality matches, let the gui know
            if len(self.matches[0]) == 0:
                pen.setColor(self.fg_color)
                qp.setPen(pen)
                qp.setFont(self.match_font)
                ## draw the text 2/5 from the top
                rect2 = QtCore.QRect(x1*place, self.bry * (2./5.), x1, self.match_height)
                qp.drawText(rect2, QtCore.Qt.TextDontClip | QtCore.Qt.AlignCenter,
                    'No Quality Matches')
            ## if there are more than 0 quality matches...
            else:
                pen.setColor(self.fg_color)
                qp.setPen(pen)
                qp.setFont(self.match_font)
                ## start the vertical sum at the reference point
                self.ylast = self.text_start
                idx  = 0
                ## loop through each of the matches
                i = 0
                for m in self.matches[0]:
                    mdate, mloc = m.split(".")
                    mdate = datetime.strptime(mdate, "%y%m%d%H").strftime("%d %b %y %HZ")
                    match_str = "%s (%s)" % (mdate, mloc)
                    ## these are the rectangles that matches will plot inside of
                    rect3 = QtCore.QRect(place2[0], self.ylast, x1, self.match_height)
                    rect4 = QtCore.QRect(place2[1], self.ylast, x1, self.match_height)
                    self.ybounds[i, 0] = self.ylast
                    self.ybounds[i, 1] = self.ylast + self.match_height
                    ## size or type is used for setting the color
                    size = self.matches[1][idx]
                    if type == 'TOR':
                        size_str = size[:-3]
                        if size.startswith('SIG'):
                            pen.setColor(QtGui.QColor(RED))
                            qp.setPen(pen)
                        elif size.startswith('WEAK'):
                            pen.setColor(QtGui.QColor(LBLUE))
                            qp.setPen(pen)
                        elif size.startswith('NON'):
                            pen.setColor(QtGui.QColor(LBROWN))
                            qp.setPen(pen)
                    else:
                        size_str = str( format(size, '.2f' ) )
                        if size >= 2.0:
                            pen.setColor(QtGui.QColor(RED))
                            qp.setPen(pen)
                        else:
                            pen.setColor(QtGui.QColor(LBLUE))
                            qp.setPen(pen)
                    ## draw the text
                    qp.drawText(rect3, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, match_str )
                    qp.drawText(rect4, QtCore.Qt.TextDontClip | QtCore.Qt.AlignLeft, size_str )
                    ## is there is a selected match, draw the bounds
                    if self.selectRect is not None:
                        pen.setColor(QtGui.QColor(LBLUE))
                        qp.setPen(pen)
                        topLeft = self.selectRect.topLeft()
                        topRight = self.selectRect.topRight()
                        bottomLeft = self.selectRect.bottomLeft()
                        bottomRight = self.selectRect.bottomRight()
                        qp.drawLine(topLeft, topRight)
                        qp.drawLine(bottomLeft, bottomRight)
                    idx += 1
                    i += 1
                    ## add to the running vertical sum
                    vspace = self.match_height
                    if platform.system() == "Windows":
                        vspace += self.match_metrics.descent()
                    self.ylast += vspace
            self.ylast = self.tpad 
[docs]    def mousePressEvent(self, e):
        if self.prof is None or (len(self.sup_matches[0]) == 0 and len(self.hail_matches[0]) == 0):
            return
        pos = e.pos()
        ## is this a supercell match?
        if pos.x() < (self.brx / 2.):
            ## loop over supercells
            for i, bound in enumerate(self.ybounds_sup):
                if bound[0] < pos.y() and bound[1] > pos.y():
                    filematch = sars.getSounding(self.sup_matches[0][i], "supercell")
                    print(filematch)
                    self.updatematch.emit(filematch)
                    ## set the rectangle used for showing
                    ## a selected match
                    self.selectRect = QtCore.QRect(0, self.ybounds_sup[i, 0],
                                    self.brx / 2.,
                                    self.ybounds_sup[i, 1] - self.ybounds_sup[i, 0])
                    break
        ## is this a hail match?
        elif pos.x() > (self.brx / 2.):
            ## loop over hail
            for i, bound in enumerate(self.ybounds_hail):
                if bound[0] < pos.y() and bound[1] > pos.y():
                    filematch = sars.getSounding(self.hail_matches[0][i], "hail")
                    print(filematch)
                    self.updatematch.emit(filematch)
                    ## set the rectangle used for showing
                    ## a selected match
                    self.selectRect = QtCore.QRect(self.brx / 2., self.ybounds_hail[i, 0],
                                    self.brx / 2.,
                                    self.ybounds_hail[i, 1] - self.ybounds_hail[i, 0])
                    break
        self.clearData()
        self.plotBackground()
        self.plotData()
        self.update()
        #logging.debug("Calling plotAnaloges.parentWidget().setFocus()")
        self.parentWidget().setFocus() 
[docs]    def setSelection(self, filematch):
        """
            Load in the SARS analog you've clicked.
        """
        match_name = os.path.basename(filematch)
#        print("\n\nSETSELECION:", match_name, filematch, self.sup_matches[0], self.hail_matches[0])
        sup_matches = [sars.getSounding(f, 'supercell').split('/')[-1] for f in self.sup_matches[0]] 
        hail_matches = [sars.getSounding(f, 'hail').split('/')[-1] for f in self.hail_matches[0]]
#        print(sup_matches, hail_matches) 
        if match_name in sup_matches:
            idx = np.where(np.asarray(sup_matches, dtype=str) == match_name)[0][0]
            lbx = 0.
            ybounds = self.ybounds_sup
        if match_name in hail_matches:
            idx = np.where(np.asarray(hail_matches, dtype=str) == match_name)[0][0]
            lbx = self.brx / 2.
            ybounds = self.ybounds_hail
        self.selectRect = QtCore.QRect(lbx, ybounds[idx, 0],
                        self.brx / 2., ybounds[idx, 1] - ybounds[idx, 0])
        self.clearData()
        self.plotBackground()
        self.plotData()
        self.update()
        self.parentWidget().setFocus() 
[docs]    def clearSelection(self):
        self.selectRect = None
        self.clearData()
        self.plotBackground()
        self.plotData()
        self.update()
        #print(self.parent, self.parentWidget())
        #self.setParent(self.parent)
        self.parentWidget().setFocus()  
if __name__ == '__main__':
    app_frame = QtGui.QApplication([])        
    #tester = plotText(['sfcpcl', 'mlpcl', 'mupcl'])
    tester = plotAnalogues()
    #tester.setProf()
    tester.show()        
    app_frame.exec_()