# /******************************************************************************
# *   Copyright (c) 2012 Jan Rheinländer <jrheinlaender@users.sourceforge.net> *
# *                                                                            *
# *   This file is part of the FreeCAD CAx development system.                 *
# *                                                                            *
# *   This library is free software; you can redistribute it and/or            *
# *   modify it under the terms of the GNU Library General Public              *
# *   License as published by the Free Software Foundation; either             *
# *   version 2 of the License, or (at your option) any later version.         *
# *                                                                            *
# *   This library  is distributed in the hope that it will be useful,         *
# *   but WITHOUT ANY WARRANTY; without even the implied warranty of           *
# *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            *
# *   GNU Library General Public License for more details.                     *
# *                                                                            *
# *   You should have received a copy of the GNU Library General Public        *
# *   License along with this library; see the file COPYING.LIB. If not,       *
# *   write to the Free Software Foundation, Inc., 59 Temple Place,            *
# *   Suite 330, Boston, MA  02111-1307, USA                                   *
# *                                                                            *
# ******************************************************************************/

from PySide import QtCore, QtGui
import FreeCAD

translate = FreeCAD.Qt.translate


class WizardShaftTable:
    "The table widget that contains all the data of the shaft"

    # Dictionary to access different parameters without using a numeric row index that might change
    # as the code evolves
    rowDict = {
        "Length": 0,
        "Diameter": 1,
        "InnerDiameter": 2,
        "ConstraintType": 3,
        "StartEdgeType": 4,
        "StartEdgeSize": 5,
        "EndEdgeType": 6,
        "EndEdgeSize": 7,
    }
    rowDictReverse = {}
    headers = [
        translate("WizardShaftTable", "Length [mm]"),
        translate("WizardShaftTable", "Diameter [mm]"),
        translate("WizardShaftTable", "Inner diameter [mm]"),
        translate("WizardShaftTable", "Constraint type"),
        translate("WizardShaftTable", "Start edge type"),
        translate("WizardShaftTable", "Start edge size"),
        translate("WizardShaftTable", "End edge type"),
        translate("WizardShaftTable", "End edge size"),
    ]

    def __init__(self, w, s):
        for key, val in self.rowDict.items():
            self.rowDictReverse[val] = key
        # Set parent wizard (for connecting slots)
        self.wizard = w
        self.shaft = s
        # Create table widget
        self.widget = QtGui.QTableWidget(len(self.rowDict), 0)
        self.widget.setObjectName(
            "ShaftWizardTable"
        )  # Do not change or translate: Used in ViewProviderFemConstraintXXX
        self.widget.setWindowTitle(translate("WizardShaftTable", "Shaft Wizard"))
        self.widget.resize(QtCore.QSize(300, 200))
        self.editedRow = None
        self.editedColumn = None

        # Label rows and columns
        self.widget.setVerticalHeaderLabels(self.headers)
        self.widget.setHorizontalHeaderLabels(
            [translate("WizardShaftTable", "Section 1"), translate("WizardShaftTable", "Section 2")]
        )
        # self.widget.columnMoved.connect(column, oldIndex, newIndex)

        # Create context menu
        action = QtGui.QAction(translate("WizardShaftTable", "Add column"), self.widget)
        action.triggered.connect(self.slotInsertColumn)
        self.widget.addAction(action)
        self.widget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        self.widget.horizontalHeader().addAction(action)
        self.widget.horizontalHeader().setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)

        # Set some default data
        # Section 1
        self.addColumn()
        self.setLength(0, 40.0)
        self.setDiameter(0, 50.0)
        self.setConstraintType(0, "Fixed")
        # Section 2
        self.addColumn()
        self.setLength(1, 80.0)
        self.setDiameter(1, 60.0)
        self.setConstraintType(1, "Force")

    def slotInsertColumn(self):
        # FIXME: Allow inserting columns, not just adding at the end
        # Note: need to re-name all the following column headers then
        # if (column == self.tableWidget.columnCount()):
        self.addColumn()
        # else:
        #   self.insertColumn(index)

    def addColumn(self):
        "Add a new column, fill it with widgets, and connect the signals"
        index = self.widget.columnCount()
        # Make an intelligent guess at the length/dia of the next segment
        if index > 0:
            length = self.shaft.segments[index - 1].length
            diameter = self.shaft.segments[index - 1].diameter
            if index > 2:
                diameter -= 5.0
            else:
                diameter += 5.0
            innerdiameter = self.shaft.segments[index - 1].innerdiameter
        else:
            length = 20.0
            diameter = 10.0
            innerdiameter = 0.0
        self.shaft.addSegment(length, diameter, innerdiameter)

        self.widget.insertColumn(index)
        self.widget.setHorizontalHeaderItem(
            index + 1,
            QtGui.QTableWidgetItem(translate("WizardShaftTable", "Section %s") % (index + 1)),
        )

        # Length
        widget = QtGui.QDoubleSpinBox(self.widget)
        widget.setMinimum(0)
        widget.setMaximum(1e9)
        self.widget.setCellWidget(self.rowDict["Length"], index, widget)
        widget.setValue(length)
        widget.valueChanged.connect(self.slotValueChanged)
        widget.editingFinished.connect(self.slotEditingFinished)
        # Diameter
        widget = QtGui.QDoubleSpinBox(self.widget)
        widget.setMinimum(0)
        widget.setMaximum(1e9)
        self.widget.setCellWidget(self.rowDict["Diameter"], index, widget)
        widget.setValue(diameter)
        widget.valueChanged.connect(self.slotValueChanged)
        widget.editingFinished.connect(self.slotEditingFinished)
        # inner Diameter
        widget = QtGui.QDoubleSpinBox(self.widget)
        widget.setMinimum(0)
        widget.setMaximum(1e9)
        self.widget.setCellWidget(self.rowDict["InnerDiameter"], index, widget)
        widget.setValue(innerdiameter)
        widget.valueChanged.connect(self.slotValueChanged)
        widget.editingFinished.connect(self.slotEditingFinished)
        # Constraint type
        widget = QtGui.QComboBox(self.widget)
        widget.insertItem(0, translate("WizardShaftTable", "None"), "None")
        widget.insertItem(1, translate("WizardShaftTable", "Fixed"), "Fixed")
        widget.insertItem(2, translate("WizardShaftTable", "Force"), "Force")
        widget.insertItem(3, translate("WizardShaftTable", "Bearing"), "Bearing")
        widget.insertItem(4, translate("WizardShaftTable", "Gear"), "Gear")
        widget.insertItem(5, translate("WizardShaftTable", "Pulley"), "Pulley")
        action = QtGui.QAction("Edit constraint", widget)
        action.triggered.connect(self.slotEditConstraint)
        widget.addAction(action)
        widget.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
        self.widget.setCellWidget(self.rowDict["ConstraintType"], index, widget)
        widget.setCurrentIndex(0)
        self.widget.connect(
            widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotConstraintType
        )
        # Start edge type
        widget = QtGui.QComboBox(self.widget)
        widget.insertItem(
            0,
            translate("WizardShaftTable", "None"),
            "None",
        )
        widget.insertItem(1, translate("WizardShaftTable", "Chamfer"), "Chamfer")
        widget.insertItem(2, translate("WizardShaftTable", "Fillet"), "Fillet")
        self.widget.setCellWidget(self.rowDict["StartEdgeType"], index, widget)
        widget.setCurrentIndex(0)
        widget.setEnabled(False)
        # self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType)
        # Start edge size
        widget = QtGui.QDoubleSpinBox(self.widget)
        widget.setMinimum(0)
        widget.setMaximum(1e9)
        self.widget.setCellWidget(self.rowDict["StartEdgeSize"], index, widget)
        widget.setValue(1)
        widget.valueChanged.connect(self.slotValueChanged)
        widget.editingFinished.connect(self.slotEditingFinished)
        widget.setEnabled(False)
        # End edge type
        widget = QtGui.QComboBox(self.widget)
        widget.insertItem(
            0,
            "None",
        )
        widget.insertItem(1, "Chamfer")
        widget.insertItem(2, "Fillet")
        self.widget.setCellWidget(self.rowDict["EndEdgeType"], index, widget)
        widget.setCurrentIndex(0)
        widget.setEnabled(False)
        # self.widget.connect(widget, QtCore.SIGNAL("currentIndexChanged(const QString&)"), self.slotLoadType)
        # End edge size
        widget = QtGui.QDoubleSpinBox(self.widget)
        widget.setMinimum(0)
        widget.setMaximum(1e9)
        self.widget.setCellWidget(self.rowDict["EndEdgeSize"], index, widget)
        widget.setValue(1)
        widget.valueChanged.connect(self.slotValueChanged)
        widget.editingFinished.connect(self.slotEditingFinished)
        widget.setEnabled(False)

    def slotValueChanged(self, value):
        (self.editedRow, self.editedColumn) = self.getFocusedCell()
        self.editedValue = value

    def slotEditingFinished(self):
        if self.editedRow is None:
            return
        rowName = self.rowDictReverse[self.editedRow]
        if rowName is None:
            return
        if rowName == "Length":
            self.shaft.updateSegment(
                self.editedColumn, length=self.getDoubleValue(rowName, self.editedColumn)
            )
        elif rowName == "Diameter":
            self.shaft.updateSegment(
                self.editedColumn, diameter=self.getDoubleValue(rowName, self.editedColumn)
            )
        elif rowName == "InnerDiameter":
            self.shaft.updateSegment(
                self.editedColumn, innerdiameter=self.getDoubleValue(rowName, self.editedColumn)
            )
        elif rowName == "ConstraintType":
            self.shaft.updateConstraint(
                self.editedColumn, self.getListValue(rowName, self.editedColumn)
            )
        elif rowName == "StartEdgeType":
            pass
        elif rowName == "StartEdgeSize":
            pass
        elif rowName == "EndEdgeType":
            pass
        elif rowName == "EndEdgeSize":
            pass

    def slotEditConstraint(self):
        (self.editedRow, self.editedColumn) = (
            self.getFocusedCell()
        )  # Because finishEditConstraint() will trigger slotEditingFinished() which requires this information
        self.shaft.editConstraint(self.editedColumn)

    def finishEditConstraint(self):
        self.shaft.updateConstraint(self.editedColumn, self.getConstraintType(self.editedColumn))

    def setLength(self, column, l):
        self.setDoubleValue("Length", column, l)
        self.shaft.updateSegment(column, length=l)

    def getLength(self, column):
        return self.getDoubleValue("Length", column)

    def setDiameter(self, column, d):
        self.setDoubleValue("Diameter", column, d)
        self.shaft.updateSegment(column, diameter=d)

    def getDiameter(self, column):
        return self.getDoubleValue("Diameter", column)

    def setInnerDiameter(self, column, d):
        self.setDoubleValue("InnerDiameter", column, d)
        self.shaft.updateSegment(column, innerdiameter=d)

    def getInnerDiameter(self, column):
        return self.getDoubleValue("InnerDiameter", column)

    @QtCore.Slot("QString")
    def slotConstraintType(self, text):
        self.shaft.updateConstraint(self.getFocusedColumn(), text)

    def setConstraintType(self, column, t):
        self.setListValue("ConstraintType", column, t)
        self.shaft.updateConstraint(column, t)

    def getConstraintType(self, column):
        return self.getListValue("ConstraintType", column)

    def slotStartEdgeType(self, old, new):
        pass

    def setStartEdgeType(self, column, t):
        self.setListValue("StartEdgeType", column, t)

    def getStartEdgeType(self, column):
        return self.getListValue("StartEdgeType", column)

    def setStartEdgeSize(self, column, s):
        self.setDoubleValue("StartEdgeSize", column, s)

    def getStartEdgeSize(self, column):
        return self.getDoubleValue("StartEdgeSize", column)

    def slotEndEdgeType(self, old, new):
        pass

    def setEndEdgeType(self, column, t):
        self.setListValue("EndEdgeType", column, t)

    def getEndEdgeType(self, column):
        return self.getListValue("EndEdgeType", column)

    def setEndEdgeSize(self, column, s):
        self.setDoubleValue("EndEdgeSize", column, s)

    def getEndEdgeSize(self, column):
        return self.getDoubleValue("EndEdgeSize", column)

    def setDoubleValue(self, row, column, v):
        widget = self.widget.cellWidget(self.rowDict[row], column)
        # Avoid triggering a signal, because the slot will work on the focused cell, not the current one
        widget.blockSignals(True)
        widget.setValue(v)
        widget.blockSignals(False)

    def getDoubleValue(self, row, column):
        widget = self.widget.cellWidget(self.rowDict[row], column)
        if widget is not None:
            return widget.value()
        else:
            return None

    def setListValue(self, row, column, v):
        widget = self.widget.cellWidget(self.rowDict[row], column)
        widget.blockSignals(True)
        widget.setCurrentIndex(widget.findText(v, QtCore.Qt.MatchExactly))
        widget.blockSignals(False)

    def getListValue(self, row, column):
        widget = self.widget.cellWidget(self.rowDict[row], column)
        if widget is not None:
            if widget.data(QtCore.Qt.UserRole):
                # If the widget has user data attached, assume that is the "value" we are seeking
                return widget.data(QtCore.Qt.UserRole)
            else:
                return widget.currentText()  # [0].upper()
        else:
            return None

    def getFocusedColumn(self):
        # Make the focused cell also the current one in the table
        widget = QtGui.QApplication.focusWidget()
        if widget is not None:
            index = self.widget.indexAt(widget.pos())
            self.widget.setCurrentCell(index.row(), index.column())
        return self.widget.currentColumn()

    def getFocusedCell(self):
        # Make the focused cell also the current one in the table
        widget = QtGui.QApplication.focusWidget()
        if widget is not None:
            index = self.widget.indexAt(widget.pos())
            self.widget.setCurrentCell(index.row(), index.column())
        return (self.widget.currentRow(), self.widget.currentColumn())
