# -*- coding: utf-8 -*-
# Mesh with GMSH inside of FreeCAD
# Author: Gomez Lucio
# Modified by: PrzemoF
# Modified by: Bernd Hahnebach (bernd@bimstatik.org)
# License: LGPL v 2.1
# Version: 04/07/2015

# CONFIGURATION - EDIT THE FOLLOWING LINE TO MATCH YOUR GMSH BINARY
gmsh_bin_linux = "/usr/bin/gmsh"
gmsh_bin_windwos = "C:\\Daten\\gmsh-2.10.0-Windows\\gmsh.exe"
gmsh_bin_other = "/usr/bin/gmsh"
# END CONFIGURATION

# START OF MACRO
from PySide import QtGui, QtCore
import Fem
import FemGui
import FemAnalysis
import FreeCAD
import FreeCADGui
import ImportGui
import Mesh
import subprocess
import sys
import tempfile
from platform import system
if system() == "Linux":
    gmsh_bin = gmsh_bin_linux
    path_sep = "/"
elif system() == "Windows":
    gmsh_bin = gmsh_bin_windwos
    path_sep = "\\"
else:
    gmsh_bin = gmsh_bin_other
    path_sep = "/"

class MeshGmsh(QtGui.QWidget):
    def __init__(self):
        super(MeshGmsh, self).__init__()
        self.initUI()

    def __del__(self):
        return

    def initUI(self):
        # Mesh dimension
        self.rb_1D = QtGui.QRadioButton("   1D", self)
        self.rb_2D = QtGui.QRadioButton("   2D", self)
        self.rb_3D = QtGui.QRadioButton("   3D", self)
        self.rb_3D.setChecked(QtCore.Qt.Checked)
        # Optimized:
        self.cb_optimized = QtGui.QCheckBox("    Optimized", self)
        self.cb_optimized.setChecked(QtCore.Qt.Checked)
        # Create Mechanical Analysis from mesh
        self.cb_mec_anal = QtGui.QCheckBox("    Create Mechanical Analysis from mesh",self)
        #self.cb_mec_anal.setChecked(QtCore.Qt.Checked)
        # Algorithm:
        self.l_algorithm = QtGui.QLabel("Algorithm ", self)
        self.cmb_algorithm = QtGui.QComboBox(self)
        self.algorithm_list = [self.tr('iso'), self.tr('netgen'), self.tr('tetgen'), self.tr('meshadapt'), ]
        self.cmb_algorithm.addItems(self.algorithm_list)
        self.cmb_algorithm.setCurrentIndex(1)
        # Format:
        self.l_format = QtGui.QLabel("Format ", self)
        self.cmb_format = QtGui.QComboBox(self)
        self.format_list = [self.tr('unv'), self.tr('stl'), self.tr('med')]
        self.cmb_format.addItems(self.format_list)
        self.cmb_format.setCurrentIndex(0)
        self.stored_cmb_format_index = 0
        # Element max size:
        self.cb_max_elme_size = QtGui.QCheckBox("  Set maximum mesh element size",self)
        self.cb_max_elme_size.setChecked(QtCore.Qt.Checked)
        self.sb_max_element_size = QtGui.QDoubleSpinBox(self)
        self.sb_max_element_size.setValue(5.0)
        self.sb_max_element_size.setMaximum(10000000.0)
        self.sb_max_element_size.setMinimum(0.00000001)
        # Element min size:
        self.cb_min_elme_size = QtGui.QCheckBox("  Set minimum mesh element size",self)
        self.sb_min_element_size = QtGui.QDoubleSpinBox(self)
        self.sb_min_element_size.setValue(1.0)
        self.sb_min_element_size.setMaximum(10000000.0)
        self.sb_min_element_size.setMinimum(0.00000001)
        self.sb_min_element_size.setEnabled(False)
        # Set Mesh Order:
        self.cb_mesh_order = QtGui.QCheckBox("  mesh order",self)
        self.cb_mesh_order.setChecked(QtCore.Qt.Checked)
        self.sb_mesh_order = QtGui.QSpinBox(self)
        self.sb_mesh_order.setValue(2)
        self.sb_mesh_order.setMaximum(5)
        self.sb_mesh_order.setMinimum(1)
        # Other gmsh commands:
        self.l_cmd_line_opt = QtGui.QLabel("Custom gmsh options ", self)
        self.le_cmd_line_opt = QtGui.QLineEdit(self)
        self.le_cmd_line_opt.setToolTip("Those option will be appended to gmsh command line call")
        # Ok buttons:
        self.okbox = QtGui.QDialogButtonBox(self)
        self.okbox.setOrientation(QtCore.Qt.Horizontal)
        self.okbox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
        # Web button
        self.pb_web = QtGui.QPushButton(self)
        self.pb_web.setText("gmsh options (web)")
        # Layout:
        layout = QtGui.QGridLayout()
        layout.addWidget(self.rb_1D, 1, 0)
        layout.addWidget(self.rb_2D, 1, 1)
        layout.addWidget(self.rb_3D, 2, 0)
        layout.addWidget(self.cb_optimized, 2, 1)
        layout.addWidget(self.l_algorithm, 3, 0)
        layout.addWidget(self.cmb_algorithm, 3, 1)
        layout.addWidget(self.l_format, 4, 0)
        layout.addWidget(self.cmb_format, 4, 1)
        layout.addWidget(self.cb_max_elme_size, 5, 0)
        layout.addWidget(self.sb_max_element_size, 5, 1)
        layout.addWidget(self.cb_min_elme_size, 6, 0)
        layout.addWidget(self.sb_min_element_size, 6, 1)
        layout.addWidget(self.cb_mesh_order, 7, 0)
        layout.addWidget(self.sb_mesh_order, 7, 1)
        layout.addWidget(self.cb_mec_anal, 8, 0)
        layout.addWidget(self.l_cmd_line_opt, 9, 0)
        layout.addWidget(self.le_cmd_line_opt, 9, 1)
        layout.addWidget(self.pb_web, 10, 0)
        layout.addWidget(self.okbox, 10, 1)
        self.setLayout(layout)
        # Connectors:
        QtCore.QObject.connect(self.okbox, QtCore.SIGNAL("accepted()"), self.proceed)
        QtCore.QObject.connect(self.okbox, QtCore.SIGNAL("rejected()"), self.cancel)
        self.pb_web.clicked.connect(self.open_gmsh_options)
        self.cb_max_elme_size.stateChanged.connect(self.max_size_state)
        self.cb_min_elme_size.stateChanged.connect(self.min_size_state)
        self.cb_mesh_order.stateChanged.connect(self.mesh_order_state)
        
    def max_size_state(self, state):   
        if state == QtCore.Qt.Checked:
            self.sb_max_element_size.setEnabled(True)
        else:
            self.sb_max_element_size.setEnabled(False)

    def min_size_state(self, state):   
        if state == QtCore.Qt.Checked:
            self.sb_min_element_size.setEnabled(True)
        else:
            self.sb_min_element_size.setEnabled(False)
            
    def mesh_order_state(self, state):   
        if state == QtCore.Qt.Checked:
            self.sb_mesh_order.setEnabled(True)
        else:
            self.sb_mesh_order.setEnabled(False)

    def open_gmsh_options(self):
        import webbrowser
        webbrowser.open('http://www.geuz.org/gmsh/doc/texinfo/gmsh.html#Command_002dline-options')

    def cancel(self):
        self.close()
        d.close()

    def proceed(self):
        temp_file = tempfile.mkstemp(suffix='.step')[1]
        selection = FreeCADGui.Selection.getSelection()
        if not selection:
            QtGui.QMessageBox.critical(None, "GMSHMesh macro", "An object has to be selected to run gmsh!")
            return
        # Export a part in step format
        ImportGui.export(selection, temp_file)
        selection_name = selection[0].Name
        # Mesh temporaly file
        file_format = self.cmb_format.currentText()
        temp_mesh_file = tempfile.tempdir + path_sep + selection_name + '_Mesh.' + file_format
        # OPTIONS GMSH:
        clmax = self.sb_max_element_size.text()
        clmin = self.sb_min_element_size.text()
        cmd_line_opt = self.le_cmd_line_opt.text()
        algo = self.cmb_algorithm.currentText()
        mesh_order = self.sb_mesh_order.text()

        if self.cb_optimized.isChecked():
            cmd_optimize = ' -optimize'
        else:
            cmd_optimize = ''

        if self.rb_3D.isChecked():
            dim = ' -3 '
        if self.rb_2D.isChecked():
            dim = ' -2 '
        if self.rb_1D.isChecked():
            dim = ' -1 '
        if self.cb_max_elme_size.isChecked():
            max_size = ' -clmax ' + clmax
        else:
            max_size = ''
        if self.cb_min_elme_size.isChecked():
            min_size = ' -clmin ' + clmin
        else:
            min_size = ''
        if self.cb_mesh_order.isChecked():
            order = ' -order ' + mesh_order
        else:
            order = ''

        options = ' -algo ' + algo + max_size + min_size + cmd_optimize + order + cmd_line_opt
        # RUN GMSH
        command = gmsh_bin + ' ' + temp_file + dim + '-format ' + file_format + ' -o ' + temp_mesh_file  + '' + options
        FreeCAD.Console.PrintMessage("Running: {}".format(command))
        try:
            if system() == "Linux":
                output = subprocess.check_output([command, '-1'], shell=True, stderr=subprocess.STDOUT,)
            elif system() == "Windows":
                output = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT,)
            else:
                output = subprocess.check_output([command, '-1'], shell=True, stderr=subprocess.STDOUT,)
            FreeCAD.Console.PrintMessage(output)
            if file_format in ('unv', 'med'):
                Fem.insert(temp_mesh_file, FreeCAD.ActiveDocument.Name)
            if file_format == 'stl':
                Mesh.insert(temp_mesh_file, FreeCAD.ActiveDocument.Name)
            if self.cb_mec_anal.isChecked():
              FMesh = App.activeDocument().ActiveObject
              FemAnalysis.makeFemAnalysis('MechanicalAnalysis')
              FemGui.setActiveAnalysis(App.activeDocument().ActiveObject)
              App.activeDocument().ActiveObject.Member = App.activeDocument().ActiveObject.Member + [FMesh]
            if self.rb_1D.isChecked():
              FMeshG = Gui.ActiveDocument.ActiveObject
              FMeshG.DisplayMode = "Elements & Nodes"
        except:
            FreeCAD.Console.PrintError("Unexpected error in GMSHMesh macro: {}".format(sys.exc_info()[0]))
        finally:
            try:
                del temp_file
            except:
                pass
            try:
                del temp_mesh_file
            except:
                pass


mw = FreeCADGui.getMainWindow()
d = QtGui.QDockWidget()
d.setWidget(MeshGmsh())
d.toggleViewAction().setText("Gmsh")
d.setAttribute(QtCore.Qt.WA_DeleteOnClose)
d.setWindowTitle(" GMSH Mesh Generator ")
mw.addDockWidget(QtCore. Qt.RightDockWidgetArea, d)

# END OF MACRO