Imports XCCLibrary
Imports SldWorks
Public Class Individual_Frame_3D
    Private Shared designName As String
    Public Shared frameDT As New DataTable
    Public Shared cuttingList As New Dictionary(Of Integer, Integer())
    Public Shared sideFrameLengths As New Dictionary(Of String, Integer)

    Public Shared Sub Build_Frame(gratingParameters As DataRow, parentID As Integer)
        frameDT = Generate_FrameData(gratingParameters)

        For i = 0 To frameDT.Rows.Count - 1
            If frameDT.Rows(i)("TYPE") = "SIDE" Then
                sideFrameLengths.Add("Frame " & sideFrameLengths.Count + 1, frameDT.Rows(i)("LENGTH"))
            End If
        Next

        cuttingList = Generate_CuttingList(frameDT, sideFrameLengths)

        Dim inst_ As Integer

        Dim sideFrame As Integer = 0
        For i = 0 To frameDT.Rows.Count - 1
            Dim HLCtName As String
            If frameDT.Rows(i)("TYPE") = "CORNER" Then
                HLCtName = "frame_l_corner"
            Else
                HLCtName = "frame_l_straight"
            End If
            inst_ = ExternalClass.instantiate_parts(parentID, HLCtName, "")
            ExternalClass.modify_parameter_value("DP_HEIGHT", inst_, 30) 'FIXA
            ExternalClass.modify_parameter_value("DP_WIDTH", inst_, 40) 'FIXA

            ExternalClass.modify_parameter_value("DP_ROTATION", inst_, frameDT.Rows(i)("ROTATION"))
            ExternalClass.modify_parameter_value("DP_OFFSET_W", inst_, frameDT.Rows(i)("OFFSET_W"))
            ExternalClass.modify_parameter_value("DP_OFFSET_L", inst_, frameDT.Rows(i)("OFFSET_L"))

            If frameDT.Rows(i)("TYPE") = "SIDE" Then
                sideFrame += 1
                Dim cutOffset1 As Integer = 0
                For j = 0 To cuttingList.Count - 1
                    For k = 0 To cuttingList.ElementAt(j).Value.Count - 1
                        If sideFrame = cuttingList.ElementAt(j).Value(k) Then
                            For l = 1 To k
                                cutOffset1 += sideFrameLengths("Frame " & cuttingList.ElementAt(j).Value(l - 1))
                            Next
                        End If
                    Next
                Next


                ExternalClass.modify_parameter_value("DP_CUTOFFSET1", inst_, cutOffset1)
                ExternalClass.modify_parameter_value("DP_CUTOFFSET2", inst_, 2000 - frameDT.Rows(i)("LENGTH") - cutOffset1)
            End If
        Next

    End Sub

    Private Shared Function Generate_FrameData(gratingParameters As DataRow)
        Dim DT As New DataTable
        DT.Columns.Add("TYPE", GetType(String))
        DT.Columns.Add("LENGTH", GetType(Integer))
        DT.Columns.Add("SIDE", GetType(Integer))
        DT.Columns.Add("CORNER", GetType(Integer))
        DT.Columns.Add("ROTATION", GetType(Integer))
        DT.Columns.Add("OFFSET_W", GetType(Integer))
        DT.Columns.Add("OFFSET_L", GetType(Integer))
        Dim DTRow As DataRow

        Dim corners As New Dictionary(Of String, Boolean)

        For i = 0 To Data.gratingPoints.Rows.Count - 1

            Dim i2, i0 As Integer
            If i = 0 Then
                i0 = Data.gratingPoints.Rows.Count - 1
            Else
                i0 = i - 1
            End If
            If i = Data.gratingPoints.Rows.Count - 1 Then
                i2 = 0
            Else
                i2 = i + 1
            End If

            If Data.gratingPoints.Rows(i)("RECESS OK") Then
                Dim firstOK, secondOK As Boolean

                If Data.gratingPoints.Rows(i)("X") = Data.gratingPoints.Rows(i0)("X") Then
                    If Math.Abs(Data.gratingPoints.Rows(i)("Y") - Data.gratingPoints.Rows(i0)("Y")) * 1000 >= 210 Then
                        firstOK = True
                    Else
                        firstOK = False
                    End If
                Else
                    If Math.Abs(Data.gratingPoints.Rows(i)("X") - Data.gratingPoints.Rows(i0)("X")) * 1000 >= 210 Then
                        firstOK = True
                    Else
                        firstOK = False
                    End If
                End If

                If Data.gratingPoints.Rows(i)("X") = Data.gratingPoints.Rows(i2)("X") Then
                    If Math.Abs(Data.gratingPoints.Rows(i)("Y") - Data.gratingPoints.Rows(i2)("Y")) * 1000 >= 210 Then
                        secondOK = True
                    Else
                        secondOK = False
                    End If
                Else
                    If Math.Abs(Data.gratingPoints.Rows(i)("X") - Data.gratingPoints.Rows(i2)("X")) * 1000 >= 210 Then
                        secondOK = True
                    Else
                        secondOK = False
                    End If
                End If

                If firstOK = True AndAlso secondOK = True Then
                    corners.Add(Data.gratingPoints.Rows(i)("NAME"), True)
                    DTRow = DT.NewRow
                    DTRow("TYPE") = "CORNER"
                    DTRow("CORNER") = Data.gratingPoints.Rows(i)("QUADRANT")
                    DTRow("ROTATION") = (Data.gratingPoints.Rows(i)("QUADRANT") - 1) * 90
                    If DTRow("CORNER") = 1 Then
                        DTRow("OFFSET_W") = gratingParameters("WIDTH")
                        DTRow("OFFSET_L") = 0
                    ElseIf DTRow("CORNER") = 2 Then
                        DTRow("OFFSET_W") = gratingParameters("WIDTH")
                        DTRow("OFFSET_L") = gratingParameters("LENGTH")
                    ElseIf DTRow("CORNER") = 3 Then
                        DTRow("OFFSET_W") = 0
                        DTRow("OFFSET_L") = gratingParameters("LENGTH")
                    Else
                        DTRow("OFFSET_W") = 0
                        DTRow("OFFSET_L") = 0
                    End If
                    DT.Rows.Add(DTRow)
                Else
                    corners.Add(Data.gratingPoints.Rows(i)("NAME"), False)
                End If
            End If
        Next

        For i = 0 To Data.gratingPoints.Rows.Count - 1
            Dim i2 As Integer
            If i = Data.gratingPoints.Rows.Count - 1 Then
                i2 = 0
            Else
                i2 = i + 1
            End If

            Dim sideFrame As Boolean = False
            If Data.gratingPoints.Rows(i)("X") = Data.gratingPoints.Rows(i2)("X") Then
                If Data.gratingPoints.Rows(i)("X") = Data.grossAreaPoints.Rows(0)("X") Or Data.gratingPoints.Rows(i)("X") = Data.grossAreaPoints.Rows(1)("X") Then
                    sideFrame = True
                End If
            ElseIf Data.gratingPoints.Rows(i)("Y") = Data.gratingPoints.Rows(i2)("Y") Then
                If Data.gratingPoints.Rows(i)("Y") = Data.grossAreaPoints.Rows(0)("Y") Or Data.gratingPoints.Rows(i)("Y") = Data.grossAreaPoints.Rows(3)("Y") Then
                    sideFrame = True
                End If
            End If

            If sideFrame = True Then
                DTRow = DT.NewRow
                DTRow("TYPE") = "SIDE"

                Dim extraCorner1 As Integer = 0
                Dim extraCorner2 As Integer = 0
                Dim numOfP As Integer = 0
                If Data.gratingPoints.Rows(i)("NAME").substring(0, 1) = "P" AndAlso Data.gratingPoints.Rows(i2)("NAME").substring(0, 1) = "P" Then
                    numOfP = 2
                    If corners(Data.gratingPoints.Rows(i)("NAME")) = False Then
                        extraCorner1 = 200
                    End If
                    If corners(Data.gratingPoints.Rows(i2)("NAME")) = False Then
                        extraCorner2 = 200
                    End If
                ElseIf Data.gratingPoints.Rows(i)("NAME").substring(0, 1) = "P" Then
                    numOfP = 1
                    If corners(Data.gratingPoints.Rows(i)("NAME")) = False Then
                        extraCorner1 = 200
                    End If
                ElseIf Data.gratingPoints.Rows(i2)("NAME").substring(0, 1) = "P" Then
                    numOfP = 1
                    If corners(Data.gratingPoints.Rows(i2)("NAME")) = False Then
                        extraCorner2 = 200
                    End If
                End If

                If Data.gratingPoints.Rows(i)("X") = Data.gratingPoints.Rows(i2)("X") Then
                    If Data.gratingPoints.Rows(i)("Y") > Data.gratingPoints.Rows(i2)("Y") Then
                        DTRow("SIDE") = 3
                        DTRow("LENGTH") = (Data.gratingPoints.Rows(i)("Y") - Data.gratingPoints.Rows(i2)("Y")) * 1000 - 20 - numOfP * 200 + extraCorner1 + extraCorner2
                        If Data.gratingPoints.Rows(i2)("NAME").substring(0, 1) = "P" Then
                            DTRow("OFFSET_W") = 210 - extraCorner2
                        Else
                            DTRow("OFFSET_W") = Data.gratingW / 2 + Data.gratingPoints.Rows(i2)("Y") * 1000 + 10
                        End If
                        DTRow("OFFSET_L") = gratingParameters("LENGTH")
                    Else
                        DTRow("SIDE") = 1
                        DTRow("LENGTH") = (Data.gratingPoints.Rows(i2)("Y") - Data.gratingPoints.Rows(i)("Y")) * 1000 - 20 - numOfP * 200 + extraCorner1 + extraCorner2
                        If Data.gratingPoints.Rows(i)("NAME").substring(0, 1) = "P" Then
                            DTRow("OFFSET_W") = DTRow("LENGTH") + 210 - extraCorner1
                        Else
                            DTRow("OFFSET_W") = DTRow("LENGTH") + Data.gratingW / 2 + Data.gratingPoints.Rows(i)("Y") * 1000 + 10
                        End If
                        DTRow("OFFSET_L") = 0
                    End If
                Else
                    If Data.gratingPoints.Rows(i)("X") > Data.gratingPoints.Rows(i2)("X") Then
                        DTRow("SIDE") = 4
                        DTRow("LENGTH") = (Data.gratingPoints.Rows(i)("X") - Data.gratingPoints.Rows(i2)("X")) * 1000 - 20 - numOfP * 200 + extraCorner1 + extraCorner2
                        DTRow("OFFSET_W") = 0
                        If Data.gratingPoints.Rows(i2)("NAME").substring(0, 1) = "P" Then
                            DTRow("OFFSET_L") = 210 - extraCorner2
                        Else
                            DTRow("OFFSET_L") = Data.gratingL / 2 + Data.gratingPoints.Rows(i2)("X") * 1000 + 10
                        End If
                    Else
                        DTRow("SIDE") = 2
                        DTRow("LENGTH") = (Data.gratingPoints.Rows(i2)("X") - Data.gratingPoints.Rows(i)("X")) * 1000 - 20 - numOfP * 200 + extraCorner1 + extraCorner2
                        DTRow("OFFSET_W") = gratingParameters("WIDTH")
                        If Data.gratingPoints.Rows(i)("NAME").substring(0, 1) = "P" Then
                            DTRow("OFFSET_L") = DTRow("LENGTH") + 210 - extraCorner1
                        Else
                            DTRow("OFFSET_L") = DTRow("LENGTH") + Data.gratingL / 2 + Data.gratingPoints.Rows(i)("X") * 1000 + 10
                        End If
                    End If
                End If
                DTRow("ROTATION") = 360 - DTRow("SIDE") * 90

                If DTRow("LENGTH") >= 125 AndAlso DTRow("LENGTH") <= 2000 Then
                    DT.Rows.Add(DTRow)
                ElseIf DTRow("LENGTH") > 2000 Then
                    Dim numOfRows As Integer = Math.Floor(CDec(DTRow("LENGTH")) / 2000) + 1
                    Dim DTRowList As New List(Of DataRow)
                    For j = 1 To numOfRows
                        Dim DTRow1 As DataRow = DT.NewRow
                        DTRowList.Add(DTRow1)
                    Next

                    Dim offsetDir As String = ""
                    Dim addOffset As Boolean
                    For Each DC As DataColumn In DT.Columns
                        If DC.ColumnName = "LENGTH" Then
                            For j = 0 To DTRowList.Count - 1
                                If j = DTRowList.Count - 1 Then
                                    DTRowList(j)(DC.ColumnName) = DTRow("LENGTH") - (j * 2000)
                                Else
                                    DTRowList(j)(DC.ColumnName) = 2000
                                End If
                            Next
                        ElseIf DC.ColumnName = "SIDE" Then
                            For j = 0 To DTRowList.Count - 1
                                DTRowList(j)(DC.ColumnName) = DTRow("SIDE")
                            Next
                            If DTRow("SIDE") = 1 Then
                                offsetDir = "OFFSET_W"
                                addOffset = False
                            ElseIf DTRow("SIDE") = 2 Then
                                offsetDir = "OFFSET_L"
                                addOffset = False
                            ElseIf DTRow("SIDE") = 3 Then
                                offsetDir = "OFFSET_W"
                                addOffset = True
                            Else
                                offsetDir = "OFFSET_L"
                                addOffset = True
                            End If

                        ElseIf DC.ColumnName = offsetDir Then
                            For j = 0 To DTRowList.Count - 1
                                If addOffset = True Then
                                    DTRowList(j)(DC.ColumnName) = DTRow(offsetDir) + j * 2000
                                Else
                                    DTRowList(j)(DC.ColumnName) = DTRow(offsetDir) - j * 2000
                                End If
                            Next
                        Else
                            For j = 0 To DTRowList.Count - 1
                                DTRowList(j)(DC.ColumnName) = DTRow(DC.ColumnName)
                            Next
                        End If
                    Next
                    For j = 0 To DTRowList.Count - 1
                        DT.Rows.Add(DTRowList(j))
                    Next
                End If
            End If
        Next

        Return DT
    End Function

    Private Shared Function Generate_CuttingList(frameDT As DataTable, sideFrameLengths As Dictionary(Of String, Integer))
        Dim frameLengths As New Dictionary(Of String, Integer)
        For i = 0 To sideFrameLengths.Count - 1
            frameLengths.Add(sideFrameLengths.ElementAt(i).Key, sideFrameLengths.ElementAt(i).Value)
        Next

        Dim cuttingList As New Dictionary(Of Integer, Integer())

        While frameLengths.Count > 0
            Dim frameCutList As New Dictionary(Of String, Integer)

            Dim longestFrame As Integer = 0
            Dim longestFrameKey As String = ""
            For i = 0 To frameLengths.Count - 1
                If frameLengths.ElementAt(i).Value > longestFrame Then
                    longestFrame = frameLengths.ElementAt(i).Value
                    longestFrameKey = frameLengths.ElementAt(i).Key
                End If
            Next
            frameCutList.Add(longestFrameKey, longestFrame)
            frameLengths.Remove(longestFrameKey)

            For i = 0 To 1000
                Dim lengthRemaining As Integer = 2000
                For j = 0 To frameCutList.Count - 1
                    lengthRemaining -= frameCutList.ElementAt(j).Value
                Next

                Dim restLength As Integer = 2000
                Dim frameID As New List(Of String)
                For j = 0 To frameLengths.Count - 1
                    If lengthRemaining - frameLengths.ElementAt(j).Value >= 0 AndAlso lengthRemaining - frameLengths.ElementAt(j).Value < restLength Then
                        restLength = lengthRemaining - frameLengths.ElementAt(j).Value
                        frameID.Clear()
                        frameID.Add(frameLengths.ElementAt(j).Key)
                    End If
                Next

                If frameID.Count = 0 Then
                    Exit For
                Else
                    Dim frameCombDS As New DataSet
                    For l = 2 To frameLengths.Count
                        Dim frameCombDT As New DataTable

                        Dim numOfValues As Integer = l
                        Dim numOfComb As Integer = Calculate_Factorial(frameLengths.Count) / (Calculate_Factorial(numOfValues) * Calculate_Factorial(frameLengths.Count - numOfValues))

                        For j = 1 To numOfValues
                            frameCombDT.Columns.Add("Enum " & j, GetType(Integer))
                        Next
                        For j = 1 To numOfValues
                            frameCombDT.Columns.Add("ID " & j, GetType(Integer))
                        Next
                        frameCombDT.Columns.Add("Combined Length", GetType(Integer))

                        Dim frameCombDR As DataRow = frameCombDT.NewRow
                        Dim combLength As Integer = 0
                        For j = 1 To numOfValues
                            frameCombDR("Enum " & j) = j
                            frameCombDR("ID " & j) = CInt(frameLengths.ElementAt(j - 1).Key.Split(" ")(1))
                            combLength += frameLengths.ElementAt(j - 1).Value
                        Next
                        frameCombDR("Combined Length") = combLength
                        frameCombDT.Rows.Add(frameCombDR)

                        For j = 1 To numOfComb - 1
                            frameCombDR = frameCombDT.NewRow

                            If frameCombDT.Rows(j - 1)("Enum " & numOfValues) < frameLengths.Count Then
                                combLength = 0
                                For k = 1 To numOfValues
                                    If k = numOfValues Then
                                        frameCombDR("Enum " & k) = frameCombDT.Rows(j - 1)("Enum " & k) + 1
                                        frameCombDR("ID " & k) = CInt(frameLengths.ElementAt(frameCombDR("Enum " & k) - 1).Key.Split(" ")(1))
                                    Else
                                        frameCombDR("Enum " & k) = frameCombDT.Rows(j - 1)("Enum " & k)
                                        frameCombDR("ID " & k) = frameCombDT.Rows(j - 1)("ID " & k)
                                    End If
                                    combLength += frameLengths.ElementAt(frameCombDR("Enum " & k) - 1).Value
                                Next
                                frameCombDR("Combined Length") = combLength

                            Else
                                Dim frameEnum As Integer
                                For k = numOfValues To 1 Step -1
                                    If frameCombDT.Rows(j - 1)("Enum " & k) < frameLengths.Count - (numOfValues - k) Then
                                        frameEnum = k
                                        Exit For
                                    End If
                                Next

                                combLength = 0
                                For k = 1 To numOfValues
                                    If k = frameEnum Then
                                        frameCombDR("Enum " & k) = frameCombDT.Rows(j - 1)("Enum " & k) + 1
                                        frameCombDR("ID " & k) = CInt(frameLengths.ElementAt(frameCombDR("Enum " & k) - 1).Key.Split(" ")(1))
                                    ElseIf k > frameEnum Then
                                        frameCombDR("Enum " & k) = frameCombDR("Enum " & k - 1) + 1
                                        frameCombDR("ID " & k) = CInt(frameLengths.ElementAt(frameCombDR("Enum " & k) - 1).Key.Split(" ")(1))
                                    Else
                                        frameCombDR("Enum " & k) = frameCombDT.Rows(j - 1)("Enum " & k)
                                        frameCombDR("ID " & k) = frameCombDT.Rows(j - 1)("ID " & k)
                                    End If
                                    combLength += frameLengths.ElementAt(frameCombDR("Enum " & k) - 1).Value
                                Next
                                frameCombDR("Combined Length") = combLength
                            End If

                            frameCombDT.Rows.Add(frameCombDR)
                        Next
                        frameCombDS.Tables.Add(frameCombDT)
                    Next

                    For j = 0 To frameCombDS.Tables.Count - 1
                        For Each DR As DataRow In frameCombDS.Tables(j).Rows
                            If lengthRemaining - DR("Combined Length") >= 0 AndAlso lengthRemaining - DR("Combined Length") < restLength Then
                                restLength = lengthRemaining - DR("Combined Length")
                                frameID.Clear()
                                For k = 1 To j + 2
                                    frameID.Add("Frame " & DR("ID " & k))
                                Next
                            End If
                        Next
                    Next

                    For j = 0 To frameID.Count - 1
                        frameCutList.Add(frameID.ElementAt(j), frameLengths(frameID.ElementAt(j)))
                        frameLengths.Remove(frameID.ElementAt(j))
                    Next
                End If
            Next

            Dim cutFrameIDs(frameCutList.Count - 1) As Integer
            For i = 0 To frameCutList.Count - 1
                cutFrameIDs(i) = frameCutList.ElementAt(i).Key.Split(" ")(1)
            Next

            cuttingList.Add(cuttingList.Count + 1, cutFrameIDs)
        End While


        Return cuttingList
    End Function

    Private Shared Function Calculate_Factorial(num As Integer)
        Dim result As Integer
        If num = 0 Then
            result = 1
        Else
            result = num
            num -= 1
            While num > 1
                result = result * num
                num -= 1
            End While
        End If

        Return result
    End Function

    Public Shared Sub Generate_End_Frame_Pieces()
        Dim swApp As SldWorks.SldWorks
        swApp = CType(System.Runtime.InteropServices.Marshal.GetActiveObject("SldWorks.Application"), SldWorks.SldWorks)
        Dim boolstatus As Boolean
        Dim longstatus As Integer, longwarnings As Integer

        For j = 0 To cuttingList.Count - 1
            Dim endPieceLength As Integer = 2000
            For k = 0 To cuttingList.ElementAt(j).Value.Count - 1
                endPieceLength -= sideFrameLengths("Frame " & cuttingList.ElementAt(j).Value(k))
            Next


            If endPieceLength > 0 Then
                Dim Part = swApp.OpenDoc6(Settings.HLCtFolder & "\HLCt\frame_l_straight.SLDPRT", 1, 0, "", longstatus, longwarnings)

                longstatus = Part.SaveAs3(Settings.folderPaths("object_" & Data.objectNum & "_models3D_frames_sw_support") & "\FRAME_L_END_PIECE" & j + 1 & ".SLDPRT", 0, 0)

                Dim swEquationMgr As EquationMgr
                swEquationMgr = Part.GetEquationMgr()

                Dim counter As Integer = 0

                For i = 0 To swEquationMgr.GetCount() - 1
                    Dim equationName = swEquationMgr.Equation(i)

                    Dim tempName = equationName.Substring(1, equationName.Length - 2)
                    tempName = tempName.Split("""")(0)

                    equationName = equationName.Split("=")(0) & "= "
                    If tempName = "DP_HEIGHT" Then
                        swEquationMgr.Equation(i) = equationName & 30 'FIXA
                        counter += 1
                    ElseIf tempName = "DP_WIDTH" Then
                        swEquationMgr.Equation(i) = equationName & 40 'FIXA 
                        counter += 1
                    ElseIf tempName = "DP_CUTOFFSET1" Then
                        Dim cutLength As Integer = 0
                        For k = 0 To cuttingList.ElementAt(j).Value.Count - 1
                            cutLength += sideFrameLengths("Frame " & cuttingList.ElementAt(j).Value(k))
                        Next
                        swEquationMgr.Equation(i) = equationName & cutLength
                        counter += 1
                    ElseIf tempName.Split("_")(0) = "DP" Then
                        swEquationMgr.Equation(i) = equationName & 0
                        counter += 1
                    End If
                    If counter = 7 Then
                        Exit For
                    End If
                Next
                boolstatus = Part.EditRebuild3()
                Dim swErrors As Integer
                Dim swWarnings As Integer
                boolstatus = Part.Save3(1, swErrors, swWarnings)

                swApp.CloseDoc(Settings.folderPaths("object_" & Data.objectNum & "_models3D_frames_sw_support") & "\FRAME_L_END_PIECE" & j + 1 & ".SLDPRT")
            End If
        Next
    End Sub
End Class
