#!/usr/bin/python
#dv3d_dialogs_multiSurface_properties_panel.py
#options panel launcher for generating multi-surfaces
#DV3D refactor 2
#AG 26/07/2013

#core libs
import vtk
import os,sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

#gui setup 
import ui_multiSurfaceOptionsDialog

#functions
from dv3d_data_ColorLookupTable import *
from dv3d_gui_ColorPicker import *
from dv3d_vtkTools_generateVTKSurface import *

#for some maths
from scipy import linspace


#set up the property panel
class generateMultiSurfaceOptionsDialog(QDialog, ui_multiSurfaceOptionsDialog.Ui_multiSurfaceOptionsDialog):  

    def __init__(self, the_parent_window):
        super(generateMultiSurfaceOptionsDialog, self).__init__(the_parent_window)
        self.__index = 0
        self.setupUi(self)
        
        self.tpw = the_parent_window

        #generate a list of available data
        dataList = []
        
        for thisSet in self.tpw.Planes:
            dataList.append(thisSet.dataLabel)
        
        #populate the comboBox
        self.comboBoxSelectData.clear()
        self.comboBoxSelectData.addItems(dataList)
        # ... and select the first item
        self.comboBoxSelectData.setCurrentIndex(0)

        #update the fields
        self.the_required_index = 0 #to start with
        #self.updateInfoAndRestrictions()

        #set up the default colors
        palette = self.frameMinColor.palette()
        palette.setColor(self.frameMinColor.backgroundRole(), QColor(255,0,0))
        self.frameMinColor.setPalette(palette)
        self.frameMinColor.setAutoFillBackground(1);
        self.frameMinColor.update()
        self.frameMinColor.repaint()

        #set up the default colors
        palette = self.frameMaxColor.palette()
        palette.setColor(self.frameMaxColor.backgroundRole(), QColor(255,255,0))
        self.frameMaxColor.setPalette(palette)
        self.frameMaxColor.setAutoFillBackground(1);
        self.frameMaxColor.update()
        self.frameMaxColor.repaint()

        #add some functions to buttons
        self.generateCallbacks()
        #and update fields
        self.cb_chosenDatasetChanged()
        
        # and make modal-ish
        self.setWindowFlags(Qt.Window|Qt.WindowMinimizeButtonHint)
        self.update()
        self.repaint()
        self.show()


    # let's bind some functionality to the buttons
    def generateCallbacks(self):      
        self.comboBoxSelectData.currentIndexChanged.connect(self.cb_chosenDatasetChanged)
        self.accepted.connect(self.cb_accepted)
        self.pushButtonCancel.released.connect(self.cb_CancelLoad)  
        self.pushButtonMinColor.released.connect(self.cb_colorMinChange)  
        self.pushButtonMaxColor.released.connect(self.cb_colorMaxChange)  
        self.pushButtonGenerateRange.released.connect(self.cb_GenerateRange)
        self.pushButtonOK.released.connect(self.cb_MakeTheSurfaces)


    # -----------------------------------
    # functions

    def cb_MakeTheSurfaces(self):
        #first extract the data from the table
        extractionVals, opacityVals = self.extractRangeTable()

        #get the color data from the frame .. lets use HSV so we can use the Hue vector
        # to generate the color distribution
        palette1 = self.frameMinColor.palette()
        minHsvF = palette1.color(self.frameMinColor.backgroundRole()).getHsvF()
        minHue = minHsvF[0]

        palette2 = self.frameMaxColor.palette()
        maxHsvF = palette2.color(self.frameMaxColor.backgroundRole()).getHsvF()
        maxHue = maxHsvF[0]

        #generate the color range
        colHueVals = linspace(minHue, maxHue, len(extractionVals))
        print extractionVals, opacityVals, colHueVals
        #we have color, opacity and extraction threshold .. generate the surfaces

        #grab a couple of other values from default/advanced options        
        currDataIndex = self.comboBoxSelectData.currentIndex()
        surfacesToGetIndex = self.comboBoxSurfacesToGet.currentIndex()
        smoothingIterations = self.spinBoxSmoothingIterations.value()
        decimationFactor = self.spinboxDecimationFactor.value()
        samplingFrequency = self.spinBoxSamplingFrequency.value()

        generateGroupSurfaces(self.tpw, currDataIndex, extractionVals, opacityVals, colHueVals, surfacesToGetIndex, smoothingIterations, decimationFactor, samplingFrequency)

        self.close()


        

    def cb_GenerateRange(self):
        #generates a table of values that set the parameters for the
        # multiple surfaces that are to be generated

        self.tableWidgetRange.clear() #reset it first

        #populate it
        self.populateRangeTable()

        #enable a couple of other controls
        self.frameAdvancedOptions.setEnabled(1)
        self.labelAdvancedSurfaceOptions.setEnabled(1)
        self.labelSurfacesToGet.setEnabled(1)
        self.labelSmoothingIterations.setEnabled(1)
        self.labelSamplingFrequency.setEnabled(1)
        self.labelDecimationFactor.setEnabled(1)
        self.comboBoxSurfacesToGet.setEnabled(1)
        self.spinBoxSmoothingIterations.setEnabled(1)
        self.spinBoxSamplingFrequency.setEnabled(1)
        self.spinboxDecimationFactor.setEnabled(1)

        self.pushButtonOK.setEnabled(1)
        self.update()
        self.repaint()



    def cb_CancelLoad(self):
        print 'user cancelled multi-surface generation...'
        self.close()



    def cb_colorMinChange(self):
        cMin = dv3d_gui_ColorPicker_QColor()
        if cMin != 'None':
            #first update the button color            
            palette = self.frameMinColor.palette()
            palette.setColor(self.frameMinColor.backgroundRole(), cMin)
            self.frameMinColor.setPalette(palette)
            self.frameMinColor.setAutoFillBackground(1);
            self.frameMinColor.update()
            self.frameMinColor.repaint()



    def cb_colorMaxChange(self):
        cMax = dv3d_gui_ColorPicker_QColor()
        if cMax != 'None':
            #first update the button color            
            palette = self.frameMaxColor.palette()
            palette.setColor(self.frameMaxColor.backgroundRole(), cMax)
            self.frameMaxColor.setPalette(palette)
            self.frameMaxColor.setAutoFillBackground(1);
            self.frameMaxColor.update()
            self.frameMaxColor.repaint()



    def cb_chosenDatasetChanged(self):
        #user has changed selection so we need to change info/restrictions
        
        #get the selected index which will correspond to the required plane dataset
        self.the_required_index = self.comboBoxSelectData.currentIndex()
        self.updateInfoAndRestrictions()



    def updateInfoAndRestrictions(self):        
         #now we have some data 'selected', update the info fields
        self.labelDataMinValue.setText('%0.4f' %(self.tpw.Planes[self.the_required_index].dMin))
        self.labelDataMaxValue.setText('%0.4f' %(self.tpw.Planes[self.the_required_index].dMax))
        #also restrict the exatraction value ranges        
        self.doubleSpinBoxMinValue.setMinimum(self.tpw.Planes[self.the_required_index].dMin)
        self.doubleSpinBoxMinValue.setMaximum(self.tpw.Planes[self.the_required_index].dMax)
        self.doubleSpinBoxMaxValue.setMinimum(self.tpw.Planes[self.the_required_index].dMin)
        self.doubleSpinBoxMaxValue.setMaximum(self.tpw.Planes[self.the_required_index].dMax)
        # .. and offer extraction options
        self.comboBoxSurfacesToGet.clear() #stops repeat addition on loops        
        self.comboBoxSurfacesToGet.addItems(['All surfaces','Largest connected'])

        #redraw those fields
        self.labelDataMinValue.update()
        self.labelDataMinValue.repaint()
        self.labelDataMaxValue.update()
        self.labelDataMaxValue.repaint()
        self.doubleSpinBoxMinValue.update()
        self.doubleSpinBoxMinValue.repaint()
        self.doubleSpinBoxMaxValue.update()
        self.doubleSpinBoxMaxValue.repaint()
        self.comboBoxSurfacesToGet.update()
        self.comboBoxSurfacesToGet.repaint()



    def cb_accepted(self):
        #user said go! .. gather up the info and run
        
        dataIndex = self.comboBoxSelectData.currentIndex()
        extractionValue = self.spinboxExtractionThreshold.value()
        surfacesToGetIndex = self.comboBoxSurfacesToGet.currentIndex()
        smoothingIterations = self.spinBoxSmoothingIterations.value()
        samplingFrequency = self.spinBoxSamplingFrequency.value()
        decimationFactor = self.spinboxDecimationFactor.value()

        dv3d_vtkTools_generateVTKSurfaceFromData(self.tpw, dataIndex, extractionValue, surfacesToGetIndex, smoothingIterations, samplingFrequency, decimationFactor)



    def populateRangeTable(self):

        #first .. gather up the required values from the dialog
        minVal = float(self.doubleSpinBoxMinValue.value())
        maxVal = float(self.doubleSpinBoxMaxValue.value())
        nSurfs = float(self.spinboxNumberLevels.value())

        #equally distribute the value range
        valIncrements = linspace(minVal, maxVal, nSurfs)
        
        #generate a sensible range of opacity levels
        if nSurfs == 2:
            opacityIncrements = [0.5, 1.0] #some hard options for corner cases
        elif nSurfs == 3:
            opacityIncrements = [0.3, 0.3, 1.0]
        else:
            nToScale = nSurfs-2 # we're going to hard code the top 2 vals at 0.8 and 1.0
            indivVals = 0.75/(nToScale+1)
            opacityIncrements = []
            for i in range(int(nToScale)):
                opacityIncrements.append(indivVals)
            opacityIncrements.append(0.75)
            opacityIncrements.append(1.0)

        #now place those into a table
        headers = ['Value','Opacity']
        self.tableWidgetRange.setRowCount(len(opacityIncrements))
        self.tableWidgetRange.setColumnCount(2)
        self.tableWidgetRange.setHorizontalHeaderLabels(headers)
        self.tableWidgetRange.setSortingEnabled(False)

        #insert the values
        for i in range(len(opacityIncrements)):
            thisVal = QTableWidgetItem()
            thisVal.setData(Qt.EditRole, str(float(valIncrements[i])))
            self.tableWidgetRange.setItem(i, 0, thisVal)
            thisOp = QTableWidgetItem()
            thisOp.setData(Qt.EditRole, str(float(opacityIncrements[i])))
            self.tableWidgetRange.setItem(i, 1, thisOp)
                
        # ok .. table populated .. draw it
        self.tableWidgetRange.update()
        self.tableWidgetRange.repaint()
        self.tableWidgetRange.resizeColumnsToContents()        
        self.tableWidgetRange.update()
        self.tableWidgetRange.repaint()   



    def extractRangeTable(self):
        #first extract the data from the table
        allRows = self.tableWidgetRange.rowCount()
        extractionVals = []
        opacityVals = []
        for row in xrange(0,allRows):
            thisVal = self.tableWidgetRange.item(row,0).text().toFloat()
            thisOp = self.tableWidgetRange.item(row,1).text().toFloat()
            extractionVals.append(float(thisVal[0]))
            opacityVals.append(float(thisOp[0]))
        return extractionVals, opacityVals








