# ***************************************************************************
# *   Copyright (c) 2023 edi <edi271@a1.net>                                *
# *                                                                         *
# *   This program is free software; you can redistribute it and/or modify  *
# *   it under the terms of the GNU Lesser General Public License (LGPL)    *
# *   as published by the Free Software Foundation; either version 2 of     *
# *   the License, or (at your option) any later version.                   *
# *   for detail see the LICENCE text file.                                 *
# *                                                                         *
# *   This program 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 program; if not, write to the Free Software   *
# *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
# *   USA                                                                   *
# *                                                                         *
# ***************************************************************************
"""Provides the TechDraw HoleShaftFit Task Dialog."""

__title__ = "TechDrawTools.TaskHoleShaftFit"
__author__ = "edi"
__url__ = "https://www.freecad.org"
__version__ = "00.01"
__date__ = "2023/02/07"

import FreeCAD as App
import FreeCADGui as Gui

from functools import partial

import os

translate = App.Qt.translate


class TaskHoleShaftFit:
    def __init__(self, sel):

        loose = translate("TechDraw_HoleShaftFit", "Loose fit")
        snug = translate("TechDraw_HoleShaftFit", "Snug fit")
        press = translate("TechDraw_HoleShaftFit", "Press fit")
        self.isHole = True
        self.sel = sel
        self.holeValues = [
            ["h9", "D10", loose],
            ["h9", "E9", loose],
            ["h9", "F8", loose],
            ["h6", "G7", loose],
            ["c11", "H11", loose],
            ["f7", "H8", loose],
            ["h6", "H7", loose],
            ["h7", "H8", loose],
            ["k6", "H7", snug],
            ["n6", "H7", snug],
            ["r6", "H7", press],
            ["s6", "H7", press],
            ["h6", "K7", snug],
            ["h6", "N7", snug],
            ["h6", "R7", press],
            ["h6", "S7", press],
        ]
        self.shaftValues = [
            ["H11", "c11", loose],
            ["H8", "f7", loose],
            ["H7", "h6", loose],
            ["H8", "h7", loose],
            ["D10", "h9", loose],
            ["E9", "h9", loose],
            ["F8", "h9", loose],
            ["G7", "h6", loose],
            ["K7", "h6", snug],
            ["N7", "h6", snug],
            ["R7", "h6", press],
            ["S7", "h6", press],
            ["H7", "k6", snug],
            ["H7", "n6", snug],
            ["H7", "r6", press],
            ["H7", "s6", press],
        ]

        self._uiPath = App.getHomePath()
        self._uiPath = os.path.join(
            self._uiPath, "Mod/TechDraw/TechDrawTools/Gui/TaskHoleShaftFit.ui"
        )
        self.form = Gui.PySideUic.loadUi(self._uiPath)

        self.form.setWindowTitle(
            translate("TechDraw_HoleShaftFit", "Hole/Shaft Fit ISO 286")
        )

        self.form.rbHoleBase.clicked.connect(partial(self.on_HoleShaftChanged, True))
        self.form.rbShaftBase.clicked.connect(partial(self.on_HoleShaftChanged, False))
        self.form.cbField.currentIndexChanged.connect(self.on_FieldChanged)

        App.setActiveTransaction("Add hole or shaft fit")

    def setHoleFields(self):
        """set hole fields in the combo box"""
        for i in range(self.form.cbField.count()):
            self.form.cbField.removeItem(0)
        for value in self.holeValues:
            self.form.cbField.addItem(value[1])
        self.form.lbBaseField.setText("             " + self.holeValues[0][0] + " /")
        self.form.lbFitType.setText(self.holeValues[0][2])

    def setShaftFields(self):
        """set shaft fields in the combo box"""
        for i in range(self.form.cbField.count()):
            self.form.cbField.removeItem(0)
        for value in self.shaftValues:
            self.form.cbField.addItem(value[1])
        self.form.lbBaseField.setText("             " + self.shaftValues[0][0] + " /")
        self.form.lbFitType.setText(self.shaftValues[0][2])

    def on_HoleShaftChanged(self, isHole):
        """slot: change the used base fit hole/shaft"""
        if isHole:
            self.isHole = isHole
            self.setShaftFields()
        else:
            self.isHole = isHole
            self.setHoleFields()

    def on_FieldChanged(self):
        """slot: change of the desired field"""
        currentIndex = self.form.cbField.currentIndex()
        if self.isHole:
            self.form.lbBaseField.setText(
                "             " + self.shaftValues[currentIndex][0] + " /"
            )
            self.form.lbFitType.setText(self.shaftValues[currentIndex][2])
        else:
            self.form.lbBaseField.setText(
                "             " + self.holeValues[currentIndex][0] + " /"
            )
            self.form.lbFitType.setText(self.holeValues[currentIndex][2])

    def accept(self):
        """slot: OK pressed"""
        currentIndex = self.form.cbField.currentIndex()
        if self.isHole:
            selectedField = self.shaftValues[currentIndex][1]
        else:
            selectedField = self.holeValues[currentIndex][1]
        fieldChar = selectedField[0]
        quality = int(selectedField[1:])
        dim = self.sel[0].Object
        value = dim.getRawValue()
        iso = ISO286()
        iso.calculate(value, fieldChar, quality)
        rangeValues = iso.getValues()
        mainFormat = dim.FormatSpec
        dim.FormatSpec = mainFormat + " " + selectedField
        dim.EqualTolerance = False
        dim.OverTolerance = rangeValues[0]
        dim.UnderTolerance = rangeValues[1]
        if dim.OverTolerance < 0:
            dim.FormatSpecOverTolerance = "(%-0.6w)"
        elif dim.OverTolerance > 0:
            dim.FormatSpecOverTolerance = "(+%-0.6w)"
        else:
            dim.FormatSpecOverTolerance = "( %-0.6w)"
        if dim.UnderTolerance < 0:
            dim.FormatSpecUnderTolerance = "(%-0.6w)"
        elif dim.UnderTolerance > 0:
            dim.FormatSpecUnderTolerance = "(+%-0.6w)"
        else:
            dim.FormatSpecUnderTolerance = "( %-0.6w)"
        Gui.Control.closeDialog()
        App.closeActiveTransaction()

    def reject(self):
        App.closeActiveTransaction(True)
        return True


class ISO286:
    """This class represents a subset of the ISO 286 standard"""

    def getNominalRange(self, measureValue):
        """return index of selected nominal range field, 0 < measureValue < 500 mm"""
        measureRanges = [
            0,
            3,
            6,
            10,
            14,
            18,
            24,
            30,
            40,
            50,
            65,
            80,
            100,
            120,
            140,
            160,
            180,
            200,
            225,
            250,
            280,
            315,
            355,
            400,
            450,
            500,
        ]
        index = 1
        while measureValue > measureRanges[index]:
            index = index + 1
        return index - 1

    def getITValue(self, valueQuality, valueNominalRange):
        """return IT-value  (value of quality in micrometers)"""
        """tables IT6 to IT11 from 0 to 500 mm"""
        IT6 = [
            6,
            8,
            9,
            11,
            11,
            13,
            13,
            16,
            16,
            19,
            19,
            22,
            22,
            25,
            25,
            25,
            29,
            29,
            29,
            32,
            32,
            36,
            36,
            40,
            40,
        ]
        IT7 = [
            10,
            12,
            15,
            18,
            18,
            21,
            21,
            25,
            25,
            30,
            30,
            35,
            35,
            40,
            40,
            40,
            46,
            46,
            46,
            52,
            52,
            57,
            57,
            63,
            63,
        ]
        IT8 = [
            14,
            18,
            22,
            27,
            27,
            33,
            33,
            39,
            39,
            46,
            46,
            54,
            54,
            63,
            63,
            63,
            72,
            72,
            72,
            81,
            81,
            89,
            89,
            97,
            97,
        ]
        IT9 = [
            25,
            30,
            36,
            43,
            43,
            52,
            52,
            62,
            62,
            74,
            74,
            87,
            87,
            100,
            100,
            100,
            115,
            115,
            115,
            130,
            130,
            140,
            140,
            155,
            155,
        ]
        IT10 = [
            40,
            48,
            58,
            70,
            70,
            84,
            84,
            100,
            100,
            120,
            120,
            140,
            140,
            160,
            160,
            160,
            185,
            185,
            185,
            210,
            210,
            230,
            230,
            250,
            250,
        ]
        IT11 = [
            60,
            75,
            90,
            110,
            110,
            130,
            130,
            160,
            160,
            190,
            190,
            220,
            220,
            250,
            250,
            250,
            290,
            290,
            290,
            320,
            320,
            360,
            360,
            400,
            400,
        ]
        qualityTable = [IT6, IT7, IT8, IT9, IT10, IT11]
        return qualityTable[valueQuality - 6][valueNominalRange]

    def getFieldValue(self, fieldCharacter, valueNominalRange):
        """return es or ES value of the field in micrometers"""
        cField = [
            -60,
            -70,
            -80,
            -95,
            -95,
            -110,
            -110,
            -120,
            -130,
            -140,
            -150,
            -170,
            -180,
            -200,
            -210,
            -230,
            -240,
            -260,
            -280,
            -300,
            -330,
            -360,
            -400,
            -440,
            -480,
        ]
        fField = [
            -6,
            -10,
            -13,
            -16,
            -16,
            -20,
            -20,
            -25,
            -25,
            -30,
            -30,
            -36,
            -36,
            -43,
            -43,
            -43,
            -50,
            -50,
            -50,
            -56,
            -56,
            -62,
            -62,
            -68,
            -68,
        ]
        gField = [
            -2,
            -4,
            -5,
            -6,
            -6,
            -7,
            -7,
            -9,
            -9,
            -10,
            -10,
            -12,
            -12,
            -14,
            -14,
            -14,
            -15,
            -15,
            -15,
            -17,
            -17,
            -18,
            -18,
            -20,
            -20,
        ]
        hField = [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ]
        kField = [
            6,
            9,
            10,
            12,
            12,
            15,
            15,
            18,
            18,
            21,
            21,
            25,
            25,
            28,
            28,
            28,
            33,
            33,
            33,
            36,
            36,
            40,
            40,
            45,
            45,
        ]
        nField = [
            10,
            16,
            19,
            23,
            23,
            28,
            28,
            33,
            33,
            39,
            39,
            45,
            45,
            52,
            52,
            60,
            60,
            66,
            66,
            73,
            73,
            80,
            80,
        ]
        rField = [
            16,
            23,
            28,
            34,
            34,
            41,
            41,
            50,
            50,
            60,
            62,
            73,
            76,
            88,
            90,
            93,
            106,
            109,
            113,
            126,
            130,
            144,
            150,
            166,
            172,
        ]
        sField = [
            20,
            27,
            32,
            39,
            39,
            48,
            48,
            59,
            59,
            72,
            78,
            93,
            101,
            117,
            125,
            133,
            151,
            159,
            169,
            190,
            202,
            226,
            244,
            272,
            292,
        ]
        DField = [
            60,
            78,
            98,
            120,
            120,
            149,
            149,
            180,
            180,
            220,
            220,
            260,
            260,
            305,
            305,
            305,
            355,
            355,
            355,
            400,
            400,
            440,
            440,
            480,
            480,
        ]
        EField = [
            39,
            50,
            61,
            75,
            75,
            92,
            92,
            112,
            112,
            134,
            134,
            159,
            159,
            185,
            185,
            185,
            215,
            215,
            215,
            240,
            240,
            265,
            265,
            290,
            290,
        ]
        FField = [
            20,
            28,
            35,
            43,
            43,
            53,
            53,
            64,
            64,
            76,
            76,
            90,
            90,
            106,
            106,
            106,
            122,
            122,
            122,
            137,
            137,
            151,
            151,
            165,
            165,
        ]
        GField = [
            12,
            16,
            20,
            24,
            24,
            28,
            28,
            34,
            34,
            40,
            40,
            47,
            47,
            54,
            54,
            54,
            61,
            61,
            61,
            69,
            69,
            75,
            75,
            83,
            83,
        ]
        HField = [
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        ]
        KField = [
            0,
            3,
            5,
            6,
            6,
            6,
            6,
            7,
            7,
            9,
            9,
            10,
            10,
            12,
            12,
            12,
            13,
            13,
            13,
            16,
            16,
            17,
            17,
            18,
            18,
        ]
        NField = [
            -4,
            -4,
            -4,
            -5,
            -5,
            -7,
            -7,
            -8,
            -8,
            -9,
            -9,
            -10,
            -10,
            -12,
            -12,
            -12,
            -14,
            -14,
            -14,
            -14,
            -14,
            -16,
            -16,
            -17,
            -17,
        ]
        RField = [
            -10,
            -11,
            -13,
            -16,
            -16,
            -20,
            -20,
            -25,
            -25,
            -30,
            -32,
            -38,
            -41,
            -48,
            -50,
            -53,
            -60,
            -63,
            -67,
            -74,
            -78,
            -87,
            -93,
            -103,
            -109,
        ]
        SField = [
            -14,
            -15,
            -17,
            -21,
            -21,
            -27,
            -27,
            -34,
            -34,
            -42,
            -48,
            -58,
            -66,
            -77,
            -85,
            -93,
            -105,
            -113,
            -123,
            -138,
            -150,
            -169,
            -187,
            -209,
            -229,
        ]
        fieldDict = {
            "c": cField,
            "f": fField,
            "g": gField,
            "h": hField,
            "k": kField,
            "n": nField,
            "r": rField,
            "s": sField,
            "D": DField,
            "E": EField,
            "F": FField,
            "G": GField,
            "H": HField,
            "K": KField,
            "N": NField,
            "R": RField,
            "S": SField,
        }
        return fieldDict[fieldCharacter][valueNominalRange]

    def calculate(self, value, fieldChar, quality):
        """calculate upper and lower field values"""
        self.nominalRange = self.getNominalRange(value)
        self.upperValue = self.getFieldValue(fieldChar, self.nominalRange)
        self.lowerValue = self.upperValue - self.getITValue(quality, self.nominalRange)
        if fieldChar == "H":
            self.upperValue = -self.lowerValue
            self.lowerValue = 0

    def getValues(self):
        """return range values in mm"""
        return (self.upperValue / 1000, self.lowerValue / 1000)
