' =============================================================================
' NX Journal: rebuild test master + diagnose why translator sees 0 solids (NX 2506)
'
' Hypothesis to test: UF CreateCyl1 built bodies that Part.Bodies counts (=2)
'   but the STEP translator reports "0 solids". Suspect: unitless expressions
'   ("bore=32" with no mm unit) produce degenerate/empty-shell bodies.
'
' This script:
'   Phase 1 (single session, no reopen):
'     OpenBaseDisplay -> ensure expressions WITH units (bore/stroke = mm) ->
'     CreateCyl1 -> Update -> report body count AND face count per body ->
'     add to MODEL refset -> export STEP (DisplayPart) -> Save ->
'     export STEP again via ExistingPart (reads the saved file from disk).
'   The face count tells us if bodies are real solids (cylinder ~3 faces)
'   or empty shells (0 faces). The ExistingPart export tells us if the solids
'   actually persisted to the .prt on disk.
'
' Run (run_journal takes one arg; use WorkingDirectory):
'   WorkingDirectory = catalog-masters\KC   (the .bat does "cd /d %~dp0")
'   run_journal.exe <this file full path>
' Result log: <cwd>\rebuild-verify-master.txt   Products: <cwd>\dbg_out\
'
' Note: English comments only (avoids GBK/BOM mojibake on no-BOM .vb files).
' =============================================================================
Option Strict Off
Imports System
Imports System.IO
Imports System.Text
Imports NXOpen
Imports NXOpen.UF

Module RebuildVerifyMaster

    Dim theSession As Session = Session.GetSession()
    Dim sb As New StringBuilder()

    Sub Log(s As String)
        sb.AppendLine(s)
    End Sub

    Sub Main()
        Try
            Run()
        Catch ex As Exception
            Log("[FATAL] " & ex.GetType().Name & " / " & ex.Message)
        End Try
        File.WriteAllText(Path.Combine(Directory.GetCurrentDirectory(), "rebuild-verify-master.txt"), sb.ToString(), New UTF8Encoding(True))
    End Sub

    Sub Run()
        Dim cur As String = Directory.GetCurrentDirectory()
        Dim masterPath As String = Path.Combine(cur, "KC_master.prt")
        Log("CWD=" & cur)
        Log("masterExists=" & File.Exists(masterPath))
        If Not File.Exists(masterPath) Then
            Log("[FAIL] master file missing: " & masterPath)
            Return
        End If
        Try
            File.SetAttributes(masterPath, File.GetAttributes(masterPath) And Not FileAttributes.ReadOnly)
        Catch ex As Exception
            Log("clear readonly: " & ex.Message)
        End Try

        Dim outDir As String = Path.Combine(cur, "dbg_out")
        Directory.CreateDirectory(outDir)

        Dim pls As NXOpen.PartLoadStatus = Nothing
        Dim bp As NXOpen.BasePart = theSession.Parts.OpenBaseDisplay(masterPath, pls)
        If pls IsNot Nothing Then pls.Dispose()
        Dim w As Part = theSession.Parts.Work
        If w Is Nothing Then
            Log("[FAIL] OpenBaseDisplay -> Work=NULL")
            Return
        End If
        Log("Work=" & w.FullPath)
        Log("bodiesBefore=" & CountBodies(w))

        ' mm unit object (for length-typed expressions). Fall back to no unit.
        Dim mm As NXOpen.Unit = w.UnitCollection.FindObject("MilliMeter")
        If mm Is Nothing Then mm = w.UnitCollection.FindObject("Millimetre")
        Log("unit mm=" & (If(mm Is Nothing, "NULL", mm.ToString())))

        EnsureExprWithUnit(w, "bore", "32", mm)
        EnsureExprWithUnit(w, "stroke", "10", mm)
        EnsureExprNoUnit(w, "magOn", "0")
        EnsureExprNoUnit(w, "mountIdx", "0")
        Log("expr bore=" & ExprVal(w, "bore") & " stroke=" & ExprVal(w, "stroke") & " magOn=" & ExprVal(w, "magOn") & " mountIdx=" & ExprVal(w, "mountIdx"))

        If CountBodies(w) = 0 Then
            Dim ufs As UFSession = UFSession.GetUFSession()
            Dim origin(2) As Double
            Dim dir(2) As Double
            dir(2) = 1.0
            Dim t1 As Tag
            Dim t2 As Tag
            ufs.Modl.CreateCyl1(NXOpen.UF.FeatureSigns.Nullsign, origin, "stroke", "bore+8", dir, t1)
            ufs.Modl.CreateCyl1(NXOpen.UF.FeatureSigns.Nullsign, origin, "stroke+30", "bore*0.33", dir, t2)
            Log("created 2 cylinders (tags " & t1.ToString() & ", " & t2.ToString() & ")")
        Else
            Log("solids already exist, skip creation")
        End If

        Dim u2 As UFSession = UFSession.GetUFSession()
        u2.Modl.Update()
        Log("afterUpdate bodies=" & CountBodies(w))
        DumpBodyFaces(w)
        AddToModelRefset(w)
        Log("afterRefset bodies=" & CountBodies(w))

        ' ---- TEST A: DisplayPart export of in-memory bodies ----
        ExportStep(Path.Combine(outDir, "A_display.stp"))
        Log("A_display.stp size=" & FileSize(Path.Combine(outDir, "A_display.stp")))

        ' ---- Save so the bodies (hopefully) persist to the .prt ----
        Try
            Dim pss As NXOpen.PartSaveStatus = w.Save(NXOpen.BasePart.SaveComponents.True, NXOpen.BasePart.CloseAfterSave.False)
            If pss IsNot Nothing Then pss.Dispose()
            Log("save OK")
        Catch ex As Exception
            Log("save FAIL: " & ex.Message)
        End Try

        ' ---- TEST B: ExistingPart export reads the SAVED file from disk ----
        ExportStepExisting(masterPath, Path.Combine(outDir, "B_existing.stp"))
        Log("B_existing.stp size=" & FileSize(Path.Combine(outDir, "B_existing.stp")))

        Log("DONE")
    End Sub

    ' ---- helpers ----
    Function CountBodies(w As Part) As Integer
        Dim n As Integer = 0
        Try
            For Each b As NXOpen.Body In w.Bodies
                n += 1
            Next
        Catch
        End Try
        Return n
    End Function

    ' Count faces per body. A real cylinder ~3 faces; 0 faces = empty shell.
    Sub DumpBodyFaces(w As Part)
        Dim i As Integer = 0
        Try
            For Each b As NXOpen.Body In w.Bodies
                i += 1
                Dim fc As Integer = 0
                Try
                    For Each f As NXOpen.Face In b.GetFaces()
                        fc += 1
                    Next
                Catch
                End Try
                Log("body" & i & " faces=" & fc)
            Next
        Catch ex As Exception
            Log("DumpBodyFaces FAIL: " & ex.Message)
        End Try
    End Sub

    Sub EnsureExprWithUnit(w As Part, name As String, val As String, mm As NXOpen.Unit)
        Try
            If w.Expressions.FindObject(name) IsNot Nothing Then Return
        Catch
        End Try
        Try
            If mm IsNot Nothing Then
                w.Expressions.CreateExpressionWithUnit("Number", name & "=" & val, mm)
            Else
                w.Expressions.CreateExpression("Number", name & "=" & val)
            End If
        Catch ex As Exception
            Log("EnsureExprWithUnit " & name & ": " & ex.Message)
        End Try
    End Sub

    Sub EnsureExprNoUnit(w As Part, name As String, val As String)
        Try
            If w.Expressions.FindObject(name) IsNot Nothing Then Return
        Catch
        End Try
        Try
            w.Expressions.CreateExpression("Number", name & "=" & val)
        Catch ex As Exception
            Log("EnsureExprNoUnit " & name & ": " & ex.Message)
        End Try
    End Sub

    Function ExprVal(w As Part, name As String) As String
        Try
            Dim e As NXOpen.Expression = w.Expressions.FindObject(name)
            If e IsNot Nothing Then Return e.Value
        Catch
        End Try
        Return "(missing)"
    End Function

    Sub AddToModelRefset(w As Part)
        Try
            Dim bodyList As New System.Collections.Generic.List(Of NXOpen.NXObject)()
            For Each b As NXOpen.Body In w.Bodies
                bodyList.Add(b)
            Next
            If bodyList.Count = 0 Then
                Log("AddToModelRefset: no bodies")
                Return
            End If
            Dim added As Boolean = False
            For Each rs As NXOpen.ReferenceSet In w.GetAllReferenceSets()
                If rs.Name.ToUpperInvariant().Contains("MODEL") Then
                    rs.AddObjectsToReferenceSet(bodyList.ToArray())
                    Log("added " & bodyList.Count & " bodies to refset '" & rs.Name & "'")
                    added = True
                    Exit For
                End If
            Next
            If Not added Then
                Log("AddToModelRefset: no MODEL refset (refsets: " & RefsetNames(w) & ")")
            End If
        Catch ex As Exception
            Log("AddToModelRefset FAIL: " & ex.Message)
        End Try
    End Sub

    Function RefsetNames(w As Part) As String
        Dim s As String = ""
        Try
            For Each rs As NXOpen.ReferenceSet In w.GetAllReferenceSets()
                If s.Length > 0 Then s &= ", "
                s &= rs.Name
            Next
        Catch
        End Try
        Return s
    End Function

    Function FileSize(p As String) As String
        If Not File.Exists(p) Then Return "MISSING"
        Return (New FileInfo(p)).Length & " bytes"
    End Function

    ' ---- export functions ----
    Sub ExportStep(fileName As String)
        If File.Exists(fileName) Then File.Delete(fileName)
        Try
            Dim sc As NXOpen.StepCreator = theSession.DexManager.CreateStepCreator()
            sc.ExportFrom = NXOpen.StepCreator.ExportFromOption.DisplayPart
            sc.ExportAs = NXOpen.StepCreator.ExportAsOption.Ap214
            sc.OutputFile = fileName
            sc.ColorAndLayers = True
            sc.Commit()
            sc.Destroy()
        Catch ex As Exception
            Log("ExportStep FAIL: " & ex.Message)
        End Try
    End Sub

    Sub ExportStepExisting(inputFile As String, fileName As String)
        If File.Exists(fileName) Then File.Delete(fileName)
        Try
            Dim sc As NXOpen.StepCreator = theSession.DexManager.CreateStepCreator()
            sc.ExportFrom = NXOpen.StepCreator.ExportFromOption.ExistingPart
            sc.InputFile = inputFile
            sc.ExportAs = NXOpen.StepCreator.ExportAsOption.Ap214
            sc.OutputFile = fileName
            sc.ColorAndLayers = True
            sc.Commit()
            sc.Destroy()
        Catch ex As Exception
            Log("ExportStepExisting FAIL: " & ex.Message)
        End Try
    End Sub

End Module
