def calculateTimeClicked(self):

        # Show from FRONT
        mayaUtils = MayaFunctionUtils()
        mayaUtils.changeToPerspCam()
        mayaUtils.viewFromCamPosition('FRONT', self.simulationSettings.fluidBoxName)

        # Delete / create output folder
        filePathMain = os.path.dirname(os.path.abspath(__file__))
        fxPathRel = os.path.dirname(os.path.abspath(filePathMain))
        outputFolder = fxPathRel + '/Output/'
        outputFolderAbs = os.path.abspath(outputFolder)

        if os.path.exists(outputFolderAbs):
            # Delete content
            filelist = [f for f in os.listdir(outputFolderAbs) if f.endswith((".mc", ".xml", "png", "jpg", "jpeg", "gif"))]
            for f in filelist:
                tmpPath = outputFolder + '/' + f
                tmpPathAbs = os.path.abspath(tmpPath)
                os.remove(tmpPathAbs)
        else:
            os.mkdir(outputFolderAbs)

        # Caching
        start_time_cahching = time.time()

        cacheCmd = MayaCacheCmdString()
        cacheCmd.setRenderSettingsFromMaya(int(self.simulationSettings.animationStartTime), int(self.simulationSettings.animationEndTime), outputFolderAbs, "Untitled")
        execCommand = MayaFunctionUtils()
        execCommand.createFluid(cacheCmd.getCacheCommandString(), None)

        res_time_caching = time.time() - start_time_cahching

        # Rendering
        start_time_rendering = time.time()

        renderer = MayaFunctionUtils()
        renderer.renderImages(outputFolder, "None", int(self.simulationSettings.animationStartTime), int(self.simulationSettings.animationEndTime), 640, 480)

        res_time_rendering = time.time() - start_time_rendering

        # Create GIF
        start_time_gif = time.time()

        directoryImagesDir = outputFolderAbs
        outputGifFileDir = outputFolderAbs
        outputGifFileName = 'animation.gif'

        gifImageCreator = GifCreator()
        start_time = self.simulationSettings.animationStartTime
        gifImageCreator.createGifFromImages(self.ffmpegpath, directoryImagesDir, outputGifFileDir, outputGifFileName, start_time, fps=25, gifOptimization=25)

        res_time_gif = time.time() - start_time_gif

        # Back to persp cam
        mayaUtils.changeToPerspCam()
        mayaUtils.viewFromCamPosition('PERSPECTIVE', self.simulationSettings.fluidBoxName)

        # Store results
        self.time_Caching = res_time_caching
        self.time_Renering = res_time_rendering
        self.time_GIF = res_time_gif

        # SetTime
        self.isTimeCalculated = True
        self.setTime()
class CreateProjectDialog(QtGui.QDialog):

    CLICK_FLAG_CAM_PV = True
    CLICK_FLAG_CAM_VC = False
    CLICK_FLAG_CAM_SPH = False  # CLICK_FLAG_CAM_SPH is the flag for the custom camera
    CLICK_FLAG_CAM_ROT = False
    choosenCamera = None

    FLUID_EXPLORER_URL = DefaultUIParameters.URL
    DIALOG_STYLE_SHEET = DefaultUIParameters.buttonStyleBold

    def __init__(self, args, fluidName, transformNode):

        QtGui.QDialog.__init__(self, args)

        # Logger
        self.lgr = logging.getLogger('FluidExplorerPlugin')

        self.lgr.info("Create animation - fluid name: %s", format(fluidName))

        # Getselected container name
        self.fluidName = fluidName

        # Store project settings
        self.simulationSettings = MayaCacheCmdSettings()
        self.simulationSettings.fluidBoxName = fluidName

        # Create the user interface from the ui file
        self.ui = Ui_CreateProjectDialog()
        self.ui.setupUi(self)

        # Store the selected fluid container name
        self.setFluidName(fluidName)
        self.transformNode = transformNode

        # Parameter Tab (second tab)
        self.tabParamtersObj = None
        self.tabParamters = None
        self.tabParameterValuesFirstOpened = False
        self.ui.tabWidget.setCurrentIndex(0)
        self.ui.tabWidget.update()

        # FFmpeg path
        self.ffmpegpath = self.getFFmpegPath()

        # FluidExplorer path
        # TODO
        self.fluidExplorerPath = self.getFluidExplorerPath()

        # Calculation of time
        self.isTimeCalculated = False
        self.time_Caching = 0
        self.time_Renering = 0
        self.time_GIF = 0
        self.progressSteps = 0

        # Tab order of first view
        self.setTabOrder(self.ui.lineEdit_SimulationName, self.ui.pushButtonCreateSimulation)
        self.setTabOrder(self.ui.pushButtonCreateSimulation, self.ui.label_2)

        # Initialize components
        self.createConnections()
        self.setupComponents()

        # Centre the main window
        # self.centre()
        # self.setWindowFlags(self.windowFlags() | QtCore.Qt.WindowMinimizeButtonHint | QtCore.Qt.WindowStaysOnTopHint)

        # //////////////////////////////////////////////////////////////////////////////////////////////////////////////
        # //////////////////////////////////////////////////////////////////////////////////////////////////////////////
        # Only for testing
        # self.runTests(self.workDirPath)
        ###self.setAnimationStartEndTime()
        # //////////////////////////////////////////////////////////////////////////////////////////////////////////////
        # //////////////////////////////////////////////////////////////////////////////////////////////////////////////

        # Select the transform node
        cmds.select(self.transformNode, r=True)


    def centre(self):
        # The dialog window is shifted to the right that the maya question dialogs are not hidden
        screen = QtGui.QDesktopWidget().screenGeometry()
        mysize = self.geometry()
        hpos = (screen.width() - mysize.width()) / 2
        vpos = (screen.height() - mysize.height()) / 2

        self.move(hpos + (mysize.width() / 3), vpos)

    def setFluidName(self, name):
        self.fluidName = name

    def setupComponents(self):

        self.ui.tabWidget.removeTab(1)
        self.setAnimationStartEndTime()

        # Set the help icon
        icon_help = QtGui.QIcon(QtGui.QPixmap(':/help_icon_orange.png'))
        self.ui.pushButtonNewPrjHelp.setIcon(icon_help)

        # Default simulation name
        self.ui.lineEdit_SimulationName.setText(DefaultUIParameters.DEF_SIMULATION_NAME)

        # Set the default output directory
        self.workDirPath = cmds.workspace(q=True, dir=True)
        self.lgr.info("Default workspace / output directory: %s", self.workDirPath)

        # TODO - delete tmp
        self.workDirPath = "E:/TMP"

        if platform.system() == "Windows":
            self.workDirPath = self.workDirPath.replace("/", "\\")
        self.ui.lineEdit_ProjPath.setText(self.workDirPath)

        self.ui.pushButtonCreateSimulation.setStyleSheet(DefaultUIParameters.buttonStyleBold)
        self.ui.spinBox_rotDeg.setValue(DefaultUIParameters.DEF_SPIN_ROT)
        self.ui.spinBox_rotDeg.setMinimum(DefaultUIParameters.DEF_SPIN_ROT_MIN)
        self.ui.spinBox_rotDeg.setMaximum(DefaultUIParameters.DEF_SPIN_ROT_MAX)
        self.ui.label.setEnabled(False)
        self.ui.spinBox_rotDeg.setEnabled(False)

        self.ui.label_2.setStyleSheet("font-weight: bold;")
        self.ui.label_3.setStyleSheet("font-weight: bold;")
        self.ui.label_4.setStyleSheet("font-weight: bold;")
        self.ui.label_5.setStyleSheet("font-weight: bold;")
        self.ui.pushButtonCreateSimulation.setStyleSheet("font-weight: bold;")
        self.ui.groupBoxCameras.setStyleSheet("QGroupBox{font-weight: bold;}")

        self.setFluidNameLabel()
        self.initCamButtons()
        self.initSliderValues()
        self.addParamterTab()

    def setFluidNameLabel(self):
        self.ui.labelFluidBox_Value.setText(self.simulationSettings.fluidBoxName)

    def addParamterTab(self):
        self.tabParamtersObj = ParameterTab(self.simulationSettings.fluidBoxName)
        self.tabParamters = self.tabParamtersObj.getTab()
        self.ui.tabWidget.addTab(self.tabParamters, "Fluid Properties")

    def createConnections(self):
        self.ui.pushButtonNewPrjHelp.clicked.connect(self.buttonHelpCreateProj_Event)
        self.ui.pushButtonBrowse.clicked.connect(self.buttonBrowse_Event)
        self.ui.pushButtonCreateSimulation.clicked.connect(self.buttonCreateSimulation_Event)
        self.ui.horizontalSlider_numberSeq.valueChanged[int].connect(self.sliderNumberSequences_Event)
        self.ui.lineEdit_numberSeq.textChanged.connect(self.lineEdit_numberSeq_Event)
        self.ui.lineEdit_numberSeq.editingFinished.connect(self.lineEdit_numberSeq_EditFinished)
        self.ui.spinBox_rotDeg.valueChanged.connect(self.spinBoxRot_Event)
        self.ui.pushButtonBrowse_CalculateTime.clicked.connect(self.calculateTimeClicked)

    def setAnimationStartEndTime(self):
        uiStatus = MayaUiDefaultValues()
        uiStatus.getAnimationStartEnd()
        begin = uiStatus.animationMinTime
        end = uiStatus.animationEndTime

        txt = str(begin) + " / " + str(end)
        numberOfFrames = (end - begin) + 1

        self.ui.labelAnimationTimeStartEnd.setText(txt)
        self.simulationSettings.animationStartTime = begin
        self.simulationSettings.animationEndTime = end
        self.simulationSettings.numberOfFrames = int(numberOfFrames)

    @QtCore.Slot()
    def buttonHelpCreateProj_Event(self):
        webbrowser.open(self.FLUID_EXPLORER_URL, new=1)

    @QtCore.Slot()
    def buttonBrowse_Event(self):
        self.fileDialog = FileOpenDialog(self)
        choosenDir = self.fileDialog.openDirDialogQuick()

        if choosenDir is not None:
            choosenDir = choosenDir + "/"
            if (platform.system() == "Windows"):
                choosenDirNew = choosenDir.replace("/","\\")
            else:
                choosenDirNew = choosenDir

            self.ui.lineEdit_ProjPath.setText(choosenDirNew)

    @QtCore.Slot()
    def buttonCreateSimulation_Event(self):

        # If the fluid container is incorrect, the application closes
        if not FluidExplorerUtils.FluidExplorerUtils.containerIsCorrect(self.fluidName):
            self.showMessageBox('Error - Create Sumulation','Cannot select fluid attributes of of the selected container. Simulation stopped!\nFor more information please see the editor log.', 'warning')
            self.close()
            return

        # First of all check of ffmpeg and fluidExplorer executable files are ok
        ffmpegIsOk = FluidExplorerUtils.FluidExplorerUtils.checkIfFFmpgeIsExectuable(self.ffmpegpath)
        fluidExplorerIsOk = FluidExplorerUtils.FluidExplorerUtils.checkIfFluidExplorerIsExectuable(self.fluidExplorerPath)

        if not ffmpegIsOk:
            self.showMessageBox('Warning - Create Sumulation','Cannot execute FFmpeg. Simulation stopped!\nFor more information please see the editor log.', 'warning')
            self.close()
            return

        if not fluidExplorerIsOk:
            self.showMessageBox('Warning - Create Sumulation','Cannot execute FluidExplorer application. Simulation stopped!\nFor more information please see the editor log.', 'warning')
            self.close()
            return

        #
        # Create project and all contents
        #

        self.currentMayaSceneName = ""
        pathName = self.ui.lineEdit_ProjPath.text()
        projName = self.ui.lineEdit_SimulationName.text()

        [pathOk, simulationNameAbsolut] = self.checkProjectPathOk(pathName, projName)
        if not pathOk:
            return
        else:
            # Save a copy of the current scene in the project folder
            # Student version -> Save dialog has to be confirmed
            self.currentMayaSceneName = cmds.file(q=True, sn=True)

            saveFileSuccessfully = True
            try:
                tmpMayaFilePath = self.simulationSettings.outputPath + "/fluid_simulation_scene.mb"
                cmds.file(rename=tmpMayaFilePath)
                dialogRes = cmds.file(save=True)
                self.simulationSettings.simulationNameMB = tmpMayaFilePath
            except:
                saveFileSuccessfully = False
                if len(self.currentMayaSceneName) == 0:
                    self.currentMayaSceneName = self.currentMayaSceneName + "untitled"

                cmds.file(rename=self.currentMayaSceneName) # Old name
                os.rmdir(self.simulationSettings.outputPath)

        if not saveFileSuccessfully:
            self.lgr.warning("Maya file not saved. Simulation stoped")
            self.close()
            return

        # Store information about the current scene
        self.simulationSettings.fluidBoxName = self.fluidName
        self.simulationSettings.numberSamples = self.ui.horizontalSlider_numberSeq.value()
        self.setCameraButtonSelection()

        # Show setting parameters in console and create xml file
        MayaCacheCmdSettings.printValues(self.simulationSettings)
        fileCreated = self.createProjectSettingsFile(simulationNameAbsolut)
        if not fileCreated:
            self.lgr.error('Could not create settings file. Simulation stoped')
            self.showMessageBox('Error - Create Sumulation','An error occurred while the project file was created!\nFor more information please see the editor log.', 'critical')
            self.close()
            return

        # No return until here: Project folder and settings file were created ...

        # --------------------------------------------------------------------------------------------------------------
        # Generate a set of N cache commands and a set of N random samples
        # --------------------------------------------------------------------------------------------------------------

        # Current spans stores the min and max slider vqalues. e.g.: currentSpans.velocitySwirl_Span
        currentSpans = self.tabParamtersObj.getSelectedValuesFromSlider()

        randomSamplesList = list()
        cacheCmdList = list()
        for iIndex in range(0, self.simulationSettings.numberSamples):

            # Create random samples
            fluidValueSampler = FluidValueSampler(currentSpans)
            fluidValueSampler.setSldierRangeValues()
            randomSamples = fluidValueSampler.getSampleSet()
            randomSamplesList.append(randomSamples)
            del fluidValueSampler
            del randomSamples

            # Create commands
            cacheName = self.simulationSettings.fluidBoxName + "_" + str(iIndex)
            cacheCmd = MayaCacheCmdString()
            pathOut = self.simulationSettings.outputPath + "/" + str(iIndex)
            cacheCmd.setRenderSettingsFromMaya(self.simulationSettings.animationStartTime, self.simulationSettings.animationEndTime, pathOut, cacheName)
            cmdStr = cacheCmd.getCacheCommandString()
            cacheCmdList.append(cmdStr)
            del cacheCmd

        self.simulationSettings.createCacheCommandString = cacheCmdList
        self.simulationSettings.randomSliderSamples = randomSamplesList

        """
        # Print cache command and random values
        print "\nCache Commands:\n"
        for iIndex in range(0, self.simulationSettings.numberSamples):
            print("[ Index: ", iIndex, " ]")
            print("   Command: ", self.simulationSettings.createCacheCommandString[iIndex])
            print("   velociySwirl: ", self.simulationSettings.randomSliderSamples[iIndex].velocitySwirl)
            print "\n"
        print "\n"
        """

        # Lock the node
        FluidExplorerUtils.FluidExplorerUtils.lockNodes(self.fluidName, self.transformNode)

        # --------------------------------------------------------------------------------------------------------------
        # Create the cache and render the images
        # --------------------------------------------------------------------------------------------------------------
        self.mayaCallObject = MayaFunctionUtils()

        self.progressSteps = (self.getNumberOfActiveCameras() + 1) * self.simulationSettings.numberSamples
        progress = QtGui.QProgressDialog("", None, 0, self.progressSteps, self)
        progressWasCanceled = False
        progress.setWindowTitle("Please wait ...")
        progress.setMinimumDuration(0)
        progress.setMaximum(int(self.progressSteps))
        progress.show()

        renderedImage = list()
        index = 0
        fluidIndex = 0
        progressIndex = 0
        for lCmd, lSamples in itertools.izip(self.simulationSettings.createCacheCommandString, self.simulationSettings.randomSliderSamples):
            """
            :type lSamples : MayaCacheCmd
            """
            progressBarText = "<b>Simulation " + str(fluidIndex) + " / " + str(self.simulationSettings.numberSamples) + " created.<b>"
            progress.setLabelText(progressBarText)

            # 1. Set the values
            self.mayaCallObject.setSampledValue(self.simulationSettings.fluidBoxName, lSamples)

            # 2. Call maya cache function
            try:
                self.mayaCallObject.createFluid(lCmd, None)
            except Exception as e:
                self.showMessageBox('Error - Create Cache','An error occurred while the cache files were created!\nFor more information please see the editor log.', 'critical')
                progress.close()
                self.close()
                return

            progressIndex += 1
            progress.setValue(progressIndex)

            # 3. Create the images
            if self.simulationSettings.imageView:
                self.mayaCallObject.changeToPerspCam()
                self.mayaCallObject.viewFromCamPosition('PERSPECTIVE', self.simulationSettings.fluidBoxName)
            if self.simulationSettings.imageView:
                try:
                    [progressIndexUpdated, renderedImageSubList] = self.mayaCallObject.renderImagesFromCameras(
                        self.simulationSettings, fluidIndex, progress, progressIndex)
                except Exception as e:
                    self.showMessageBox('Error - Render Images','An error occurred while the images were rendered!\nFor more information please see the editor log.', 'critical')
                    progress.close()
                    self.close()
                    return

                progressIndex = progressIndexUpdated
                renderedImage.append(renderedImageSubList)

            progressBarText = "<b>Simulation " + str(fluidIndex+1) + " / " + str(self.simulationSettings.numberSamples) + " created.<b>"
            progress.setLabelText(progressBarText)

            fluidIndex += 1
            if progress.wasCanceled():
                progressWasCanceled = True
                break

        if self.simulationSettings.imageView:
            self.mayaCallObject.changeToPerspCam()
            self.mayaCallObject.viewFromCamPosition('PERSPECTIVE', self.simulationSettings.fluidBoxName)

        self.mayaCallObject = None
        progress.close()

        # --------------------------------------------------------------------------------------------------------------

        # --------------------------------------------------------------------------------------------------------------
        # Create GIF images
        # --------------------------------------------------------------------------------------------------------------
        if self.simulationSettings.imageView:
            self.lgr.info("Creating GIF animations:")
            progress = QtGui.QProgressDialog("", None, 0, self.progressSteps, self)
            progress.setWindowTitle("Please wait ...")
            progress.setMinimumDuration(0)
            progress.setMaximum(len(renderedImage))
            progress.setLabelText("<b>Creating GIF animations ...</b>")
            progress.show()
            progressIndex = 0

            gifIndex = 0
            for idx, val in enumerate(renderedImage):
                tmpList = val
                for val in tmpList:
                    progressIndex += 1
                    progress.setValue(progressIndex)

                    # Store the path to the rendered images
                    directoryImagesDir = val
                    outputGifFileDir = val
                    outputGifFileName = 'animation.gif'
                    self.gifImageCreator = GifCreator()
                    start_time = self.simulationSettings.animationStartTime
                    isFFmpegExecutable = self.gifImageCreator.createGifFromImages(self.ffmpegpath, directoryImagesDir,
                                                                                  outputGifFileDir, outputGifFileName,
                                                                                  start_time, fps=25, gifOptimization=25)

                    if isFFmpegExecutable==False:
                        self.showMessageBox('Error - Create Animations','An error occurred while the animations were created!\nFor more information please see the editor log.', 'critical')
                        progress.close()
                        self.close()
                        return

                gifIndex += 1
                self.lgr.info('GIF Animation "%s" created', str(gifIndex))

            progress.close()
        # --------------------------------------------------------------------------------------------------------------

        # Copy settings file to project folder
        pathToSettingsFile = os.path.abspath(os.path.dirname(os.path.abspath(__file__)) + '/Resources/settings_file/fluidExplorer.settings')
        copySettingsFileTo = os.path.abspath(self.simulationSettings.outputPath + '/fluidExplorer.settings')
        FluidExplorerUtils.FluidExplorerUtils.copySettingsFile(pathToSettingsFile, copySettingsFileTo)

        text = "Simulations successfully created!" + "\n\nProject Path: " + self.simulationSettings.outputPath + "" + "\nProject File: " + self.simulationSettings.simulationNameMB + ""
        self.showMessageBox("Information", text, 'information')

        # Select the transform node
        cmds.select(self.transformNode, r=True)
        self.lgr.info('#')
        self.lgr.info("# Simulation successfully created: %s -", self.simulationSettings.outputPath)
        self.lgr.info('#')

        # Close window
        self.close()

    @QtCore.Slot()
    def lineEdit_numberSeq_EditFinished(self):
        if not self.ui.lineEdit_numberSeq.text():
            self.ui.lineEdit_numberSeq.setText(str(DefaultUIParameters.DEF_NUMBER_SEQUENCES))

    @QtCore.Slot()
    def sliderNumberSequences_Event(self):
        tmp = str(self.ui.horizontalSlider_numberSeq.value())
        self.ui.lineEdit_numberSeq.setText(tmp)

        self.setTime()

    @QtCore.Slot()
    def lineEdit_numberSeq_Event(self):
        numberSeq = self.ui.lineEdit_numberSeq.text()
        try:
            val = int(numberSeq)
            if int(numberSeq) < DefaultUIParameters.DEF_NUMBER_SEQUENCES_MIN :
                self.ui.lineEdit_numberSeq.setText(str(DefaultUIParameters.DEF_NUMBER_SEQUENCES_MIN))
                self.ui.horizontalSlider_numberSeq.setValue(DefaultUIParameters.DEF_NUMBER_SEQUENCES_MIN)
                self.ui.horizontalSlider_numberSeq.update()
            elif int(numberSeq) > DefaultUIParameters.DEF_NUMBER_SEQUENCES_MAX:
                self.ui.lineEdit_numberSeq.setText(str(DefaultUIParameters.DEF_NUMBER_SEQUENCES_MAX))
                self.ui.horizontalSlider_numberSeq.setValue(DefaultUIParameters.DEF_NUMBER_SEQUENCES_MAX)
                self.ui.horizontalSlider_numberSeq.update()
            else:
                self.ui.horizontalSlider_numberSeq.setValue(val)

        except ValueError:
            if numberSeq == "":
                pass
            else:
                self.ui.lineEdit_numberSeq.setText(str(DefaultUIParameters.DEF_NUMBER_SEQUENCES))

    @QtCore.Slot()
    def pushButtonCamPV_Event(self):
        flag = self.CLICK_FLAG_CAM_PV
        if not flag:
            self.ui.pushButton_CamPV.setStyleSheet(DefaultUIParameters.StyleSheet_Button_On)
            self.CLICK_FLAG_CAM_PV = True
        elif flag:
            self.ui.pushButton_CamPV.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
            self.CLICK_FLAG_CAM_PV = False

        self.setTime()

    @QtCore.Slot()
    def pushButtonCamVC_Event(self):
        flag = self.CLICK_FLAG_CAM_VC
        if not flag:
            self.ui.pushButton_CamVC.setStyleSheet(DefaultUIParameters.StyleSheet_Button_On)
            self.CLICK_FLAG_CAM_VC = True
        elif flag:
            self.ui.pushButton_CamVC.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
            self.CLICK_FLAG_CAM_VC = False

        self.setTime()

    @QtCore.Slot()
    def pushButtonCamSPH_Event(self):
        flag = self.CLICK_FLAG_CAM_SPH
        if not flag:
            chooseCameraDialog = ChooseCameraDialog(self)
            chooseCameraDialog.exec_()
            choosenCam = chooseCameraDialog.getChoosenCamera
            if choosenCam:
                self.ui.label_selectedCam.setText('[ ' + choosenCam + ' ]')
                self.choosenCamera = choosenCam
                self.ui.pushButton_CamSPH.setStyleSheet(DefaultUIParameters.StyleSheet_Button_On)
                self.CLICK_FLAG_CAM_SPH = True
            else:
                pass

        elif flag:
            self.ui.pushButton_CamSPH.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
            self.ui.label_selectedCam.setText(' ')
            self.choosenCamera = None
            self.CLICK_FLAG_CAM_SPH = False

        self.setTime()

    @QtCore.Slot()
    def pushButtonROT_Event(self):
        flag = self.CLICK_FLAG_CAM_ROT
        if not flag:
            self.ui.pushButton_ROT.setStyleSheet(DefaultUIParameters.StyleSheet_Button_On)
            self.CLICK_FLAG_CAM_ROT = True
            self.ui.spinBox_rotDeg.setEnabled(True)
            self.ui.label.setEnabled(True)
        elif flag:
            self.ui.pushButton_ROT.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
            self.CLICK_FLAG_CAM_ROT = False
            self.ui.spinBox_rotDeg.setEnabled(False)
            self.ui.label.setEnabled(False)

        self.setTime()

    @QtCore.Slot()
    def spinBoxRot_Event(self):
        value = int(self.ui.spinBox_rotDeg.text())

        if value < DefaultUIParameters.DEF_SPIN_ROT_MIN:
            self.ui.spinBox_rotDeg.setValue(int(DefaultUIParameters.DEF_SPIN_ROT_MIN))
        if value > DefaultUIParameters.DEF_SPIN_ROT_MAX:
            self.ui.spinBox_rotDeg.setValue(int(DefaultUIParameters.DEF_SPIN_ROT_MAX))

        self.setTime()

    def initCamButtons(self):
        self.ui.pushButton_CamPV.setIcon(QtGui.QIcon(self.tr(":/icon_cam_perspective.png")))
        self.ui.pushButton_CamPV.setStyleSheet(DefaultUIParameters.StyleSheet_Button_On)
        self.ui.pushButton_CamVC.setIcon(QtGui.QIcon(self.tr(":/icon_cam_vc.png")))
        self.ui.pushButton_CamVC.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
        self.ui.pushButton_CamSPH.setIcon(QtGui.QIcon(self.tr(":/icon_cam_custom.png")))
        self.ui.pushButton_CamSPH.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
        self.ui.pushButton_ROT.setIcon(QtGui.QIcon(self.tr(":/icon_cam_rotation.png")))
        self.ui.pushButton_ROT.setStyleSheet(DefaultUIParameters.StyleSheet_Button_Off)
        self.ui.pushButton_CamPV.clicked.connect(self.pushButtonCamPV_Event)
        self.ui.pushButton_CamVC.clicked.connect(self.pushButtonCamVC_Event)
        self.ui.pushButton_CamSPH.clicked.connect(self.pushButtonCamSPH_Event)
        self.ui.pushButton_ROT.clicked.connect(self.pushButtonROT_Event)

    def initSliderValues(self):
        self.ui.horizontalSlider_numberSeq.setMinimum(DefaultUIParameters.DEF_NUMBER_SEQUENCES_MIN)
        self.ui.horizontalSlider_numberSeq.setMaximum(DefaultUIParameters.DEF_NUMBER_SEQUENCES_MAX)
        self.ui.horizontalSlider_numberSeq.setValue(DefaultUIParameters.DEF_NUMBER_SEQUENCES)

    def checkProjectPathOk(self, pathName, projName):
        if projName == "":
            self.showMessageBox("Warning - Create Simulation", "Cannot create project folder! Please enter a project name.", 'warning')
            self.ui.lineEdit_SimulationName.setFocus()
            return [False, '']

        if pathName == "":
            self.showMessageBox("Warning - Create Simulation", "Cannot create project folder! Please enter a project path.", 'warning')
            self.ui.lineEdit_ProjPath.setFocus()
            self.ui.lineEdit_ProjPath.setText(self.workDirPath)
            return [False, '']

        if not re.match("^[a-zA-Z0-9_]*$", projName):
            self.showMessageBox("Warning - Create Simulation", "Cannot create project! A file name cannot contain special "
                                                               "characters.\nValid characters: numbers, letters, - and _ ", 'warning')
            self.ui.lineEdit_SimulationName.setFocus()
            self.ui.lineEdit_SimulationName.setText("")

            return [False, '']

        pathName = os.path.abspath(pathName)
        if not pathName.endswith('/'):
            pathName += '/'
        if not pathName.endswith('\\'):
            pathName += '/'

        dirExists = FluidExplorerUtils.FluidExplorerUtils.dirExists(pathName)
        if dirExists:
            pathPrjAbsolut = os.path.abspath(pathName)
        else:
            try:
                os.mkdir(pathName)
                pathPrjAbsolut = os.path.abspath(pathName)
            except OSError as exc:
                errorText = ""
                if exc.errno == errno.EACCES:
                    errorText = "Error {0}: {1}" .format(exc.errno, exc.strerror)
                    self.lgr.error("%s", errorText)
                    self.ui.lineEdit_ProjPath.setText("")
                    self.ui.lineEdit_ProjPath.setFocus()
                elif exc.errno == 22:
                    errorText = "Error {0}: {1}" .format(exc.errno, exc.strerror)
                    self.lgr.error("%s", errorText)
                    self.ui.lineEdit_ProjPath.setText("")
                    self.ui.lineEdit_ProjPath.setFocus()
                else:
                    errorText = "Error {0}: {1}" .format(exc.errno, exc.strerror)
                    self.lgr.error("%s", errorText)

                self.showMessageBox("Warning - Create Simulation", "Cannot create project folder! Please check the project path entered.\nDetails: " + errorText, 'warning')
                self.ui.lineEdit_ProjPath.setFocus()
                self.ui.lineEdit_ProjPath.setText(self.workDirPath)

                return [False, '']

        projPathFull = pathName + projName
        dirExists = FluidExplorerUtils.FluidExplorerUtils.dirExists(projPathFull)
        simulationNameAbsolut = os.path.abspath(projPathFull)

        if dirExists:
            self.showMessageBox("Warning - Create Simulation", "Project already exists! Please change the project name.", 'warning')
            self.ui.lineEdit_SimulationName.setFocus()
            self.ui.lineEdit_SimulationName.setText("")
            simulationNameAbsolut = os.path.abspath(projPathFull)

            return [False, '']

        else:
            try:
                os.mkdir(simulationNameAbsolut)
            except OSError as exc:
                if exc.errno == errno.EACCES:
                    errorText = "Error {0}: {1}" .format(exc.errno, exc.strerror)
                    self.lgr.error("%s", errorText)
                    self.ui.lineEdit_ProjPath.setText("")
                    self.ui.lineEdit_ProjPath.setFocus()

                elif exc.errno == 22:
                    errorText = "Error {0}: {1}" .format(exc.errno, exc.strerror)
                    self.lgr.error("%s", errorText)
                    self.ui.lineEdit_ProjPath.setText("")
                    self.ui.lineEdit_ProjPath.setFocus()
                else:
                    errorText = "Error {0}: {1}" .format(exc.errno, exc.strerror)
                    self.lgr.error("%s", errorText)

                self.showMessageBox("Warning - Create Simulation", "Cannot create project folder! Please check the project name entered.\nDetails: " + errorText, 'warning')
                self.ui.lineEdit_ProjPath.setFocus()
                self.ui.lineEdit_ProjPath.setText(self.workDirPath)

                return [False, '']

            finally:
                self.simulationSettings.outputPath = os.path.abspath( projPathFull )
                self.simulationSettings.outputPath = self.simulationSettings.outputPath.replace('\\', '/')
                index = projPathFull.rfind(projName)
                self.simulationSettings.prjName = projPathFull[index:]
                self.simulationNameAbsolut = simulationNameAbsolut

                return [True, simulationNameAbsolut]

    def setCameraButtonSelection(self):
        # Default camera values [on/off]: Persp: 0/1; VC: 0/1; Custom: None/string; Rotation: 0/45-90
        self.simulationSettings.cam_perspective = 0
        self.simulationSettings.cam_viewcube = 0
        self.simulationSettings.imageView = 0
        self.simulationSettings.cam_sphere = 0
        self.simulationSettings.cam_rotation = 0

        if self.CLICK_FLAG_CAM_PV:
            self.simulationSettings.cam_perspective = 1;
            self.simulationSettings.imageView = 1

        if self.CLICK_FLAG_CAM_VC:
            self.simulationSettings.cam_viewcube = 1;
            self.simulationSettings.imageView = 1

        if self.CLICK_FLAG_CAM_SPH: # SPH is the flag for the custom camera
            self.simulationSettings.cam_sphere = self.CLICK_FLAG_CAM_SPH
            self.simulationSettings.cam_custom_name = self.choosenCamera
            self.simulationSettings.imageView = 1
        else:
            self.simulationSettings.cam_sphere = False
            self.simulationSettings.cam_custom_name = None

        if self.CLICK_FLAG_CAM_ROT:
            self.simulationSettings.cam_rotation = self.ui.spinBox_rotDeg.text()
            self.simulationSettings.imageView = 1
        else:
            self.simulationSettings.cam_rotation = 0

    def createProjectSettingsFile(self, simulationNameAbsolut):
        try:
            xmlSettingsWriter = XmlFileWriter()
            pathConfigFile = simulationNameAbsolut + "/" + str(self.simulationSettings.prjName) + ".fxp"
            xmlSettingsWriter.setXmlDocPath(pathConfigFile, "GlobalSettings")
            xmlSettingsWriter.writeSettingToXmlFile(self.simulationSettings)
        except:
            return False
        finally:
            if os.path.exists(os.path.abspath(pathConfigFile)):
                return True
            else:
                return False


    def calculateTimeClicked(self):

        # Show from FRONT
        mayaUtils = MayaFunctionUtils()
        mayaUtils.changeToPerspCam()
        mayaUtils.viewFromCamPosition('FRONT', self.simulationSettings.fluidBoxName)

        # Delete / create output folder
        filePathMain = os.path.dirname(os.path.abspath(__file__))
        fxPathRel = os.path.dirname(os.path.abspath(filePathMain))
        outputFolder = fxPathRel + '/Output/'
        outputFolderAbs = os.path.abspath(outputFolder)

        if os.path.exists(outputFolderAbs):
            # Delete content
            filelist = [f for f in os.listdir(outputFolderAbs) if f.endswith((".mc", ".xml", "png", "jpg", "jpeg", "gif"))]
            for f in filelist:
                tmpPath = outputFolder + '/' + f
                tmpPathAbs = os.path.abspath(tmpPath)
                os.remove(tmpPathAbs)
        else:
            os.mkdir(outputFolderAbs)

        # Caching
        start_time_cahching = time.time()

        cacheCmd = MayaCacheCmdString()
        cacheCmd.setRenderSettingsFromMaya(int(self.simulationSettings.animationStartTime), int(self.simulationSettings.animationEndTime), outputFolderAbs, "Untitled")
        execCommand = MayaFunctionUtils()
        execCommand.createFluid(cacheCmd.getCacheCommandString(), None)

        res_time_caching = time.time() - start_time_cahching

        # Rendering
        start_time_rendering = time.time()

        renderer = MayaFunctionUtils()
        renderer.renderImages(outputFolder, "None", int(self.simulationSettings.animationStartTime), int(self.simulationSettings.animationEndTime), 640, 480)

        res_time_rendering = time.time() - start_time_rendering

        # Create GIF
        start_time_gif = time.time()

        directoryImagesDir = outputFolderAbs
        outputGifFileDir = outputFolderAbs
        outputGifFileName = 'animation.gif'

        gifImageCreator = GifCreator()
        start_time = self.simulationSettings.animationStartTime
        gifImageCreator.createGifFromImages(self.ffmpegpath, directoryImagesDir, outputGifFileDir, outputGifFileName, start_time, fps=25, gifOptimization=25)

        res_time_gif = time.time() - start_time_gif

        # Back to persp cam
        mayaUtils.changeToPerspCam()
        mayaUtils.viewFromCamPosition('PERSPECTIVE', self.simulationSettings.fluidBoxName)

        # Store results
        self.time_Caching = res_time_caching
        self.time_Renering = res_time_rendering
        self.time_GIF = res_time_gif

        # SetTime
        self.isTimeCalculated = True
        self.setTime()

    def setTime(self):

        numberSamples = int(self.ui.horizontalSlider_numberSeq.value())
        numberCameras = self.getNumberOfActiveCameras()

        # Calculate time in seconds
        timeInSeconds = (self.time_Caching + (numberCameras * (self.time_Renering+self.time_GIF))) * numberSamples

        if timeInSeconds > 3599:
            str = time.strftime("%H:%M", time.gmtime(timeInSeconds))
            timeStr = str + ' h.'

        else:
            str = time.strftime("%M:%S", time.gmtime(timeInSeconds))
            timeStr = str + ' min.'

        if self.isTimeCalculated:
            self.ui.labelTime_Value.setText(timeStr)

    def getNumberOfActiveCameras(self):
        cameraCount = 0

        if self.CLICK_FLAG_CAM_PV:
            cameraCount = cameraCount + 1
        if self.CLICK_FLAG_CAM_VC:
            cameraCount = cameraCount + 3
        if self.CLICK_FLAG_CAM_SPH:
            cameraCount = cameraCount + 1
        if self.CLICK_FLAG_CAM_ROT:
            deg = 0
            count = 0
            step = int(self.ui.spinBox_rotDeg.text())

            while deg < 360:
                deg = deg + step
                count = count + 1

            cameraCount = cameraCount + count

        return cameraCount

    def getFFmpegPath(self):
        filePathMain = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        filename = os.path.join(filePathMain, 'lib/ffmpeg/')
        fxPathRel = os.path.abspath(filename)

        return fxPathRel

    def getFluidExplorerPath(self):
        filePathMain = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        filename = os.path.join(filePathMain, 'lib/fluidexplorer/')
        fxPathRel = os.path.abspath(filename)

        return fxPathRel

    def showMessageBox(self, title, text, _type):
        testMode = False
        if not testMode:
            msgBox = QtGui.QMessageBox(self)
            msgBox.setStyleSheet(self.DIALOG_STYLE_SHEET)
            msgBox.setText(text)
            msgBox.setWindowTitle(title)

            if _type == 'warning':
                msgBox.setIcon(QtGui.QMessageBox.Warning)
            if _type == 'critical':
                msgBox.setIcon(QtGui.QMessageBox.Critical)
            if _type == 'information':
                msgBox.setIcon(QtGui.QMessageBox.Information)

            msgBox.exec_()

    #
    # //////////////////////////////////////////////////////////////////////////////////////////////////////////////
    # Only for testing
    # //////////////////////////////////////////////////////////////////////////////////////////////////////////////

    def setuptInputFields(self, testObject):
        """
        :type testObject: Test
        """

        if testObject.projectName:
            self.ui.lineEdit_SimulationName.setText(testObject.projectName)
        if testObject.projectPath:
            self.ui.lineEdit_ProjPath.setText(testObject.projectPath)
        if testObject.numberOfSamples:
            self.ui.lineEdit_numberSeq.setText(testObject.numberOfSamples)

        self.CLICK_FLAG_CAM_PV = testObject.cam_perspective
        self.CLICK_FLAG_CAM_VC = testObject.cam_viewcube
        self.CLICK_FLAG_CAM_SPH = testObject.cam_custom

        if self.CLICK_FLAG_CAM_SPH:
            self.choosenCamera = testObject.cam_custom_name
            self.lgr.info("Choosen camera: %s", self.choosenCamera)
            self.simulationSettings.cam_custom_name = self.choosenCamera

        if testObject.cam_rotation != 0:
            self.CLICK_FLAG_CAM_ROT = True
            self.ui.spinBox_rotDeg.setValue(testObject.cam_rotation)

        self.update()


    def runTests(self, workDir):

        containerName = self.fluidName
        testFolder = os.path.abspath(os.path.dirname(__file__) + '/Test')

        lgr = logging.getLogger('FluidExplorerPlugin')
        lgr.info(' ')
        lgr.info("### TESTS STARTED ###")
        lgr.info(' ')

        testUtils = Test()
        testUtils.initTest(testFolder, containerName)
        testUtils.setUpLogger()

        """
        testUtils.check_if_ffmpeg_exists()
        """

        """
        inputValues = testUtils.wrong_projectName()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_wrong_projectName(testResults)

        inputValues = testUtils.empty_projectName()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_empty_projectName(testResults)

        inputValues = testUtils.wrong_projectPath()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        test        Utils.evaluate_wrong_projectPath(testResults)

        inputValues = testUtils.empty_projectPath()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_empty_projectPath(testResults)

        inputValues = testUtils.create_sumulation_cache_only()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_create_sumulation_cache_only(inputValues.projectPath, inputValues.projectName, inputValues.numberOfSamples)
        """

        """
        inputValues = testUtils.create_sumulation_cache_and_images_perspective()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_create_sumulation_cache_and_images_perspective(inputValues.projectPath, inputValues.projectName, inputValues.numberOfSamples)


        inputValues = testUtils.create_sumulation_cache_and_images_viewcube()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_create_sumulation_cache_and_images_viewcube(inputValues.projectPath, inputValues.projectName, inputValues.numberOfSamples)
        """

        """
        inputValues = testUtils.create_sumulation_cache_and_images_custom()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_create_sumulation_cache_and_images_custom(inputValues.projectPath, inputValues.projectName, inputValues.numberOfSamples)
        """

        """
        inputValues = testUtils.create_sumulation_cache_and_images_rotation()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluate_create_sumulation_cache_and_images_rotation(inputValues.projectPath, inputValues.projectName, inputValues.numberOfSamples, inputValues.cam_rotation)
        """

        """
        testUtils.check_if_fluid_attributes_exist(self.fluidName)
        """

        inputValues = testUtils.create_sumulation_cache_and_images_all_cameras()
        self.setuptInputFields(inputValues)
        testResults = self.buttonCreateSimulation_Event()
        testUtils.evaluation_create_sumulation_cache_and_images_all_cameras(inputValues.projectPath, inputValues.projectName, inputValues.numberOfSamples)

        self.close()