using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using NXOpen;
using NXOpen.UF;
using UpdateStandardPartFamilyMemberUsageStatus;
using NXOpen.PartFamily;

public class Program
{
    // class members
    private static Session s;
    private static UI ui;
    private static UFSession ufs;
    public static Program theProgram;
    public static bool isDisposeCalled;

    public static List<object> PfItem { set; get; }
    public static List<object> PfStatusOld { set; get; }
    public static List<object> PfStatusNew { set; get; }

    #region UG...
    //------------------------------------------------------------------------------
    // Constructor
    //------------------------------------------------------------------------------
    public Program()
    {
        try
        {
            s = Session.GetSession();
            ui = UI.GetUI();
            ufs = UFSession.GetUFSession();
            isDisposeCalled = false;
        }
        catch (NXOpen.NXException)
        {
            // ---- Enter your exception handling code here -----
            // UI.GetUI().NXMessageBox.Show("Message", NXMessageBox.DialogType.Error, ex.Message);
        }
    }


    //------------------------------------------------------------------------------
    //  Explicit Activation
    //      This entry point is used to activate the application explicitly
    //------------------------------------------------------------------------------
    [DebuggerStepThrough] public static int Main(string[] args)
    {
        int retValue = 0;
        try
        {
            theProgram = new Program();

            //TODO: Add your application code here
            theProgram.DoIt(args);


            theProgram.Dispose();
        }
        catch (NXOpen.NXException)
        {
            // ---- Enter your exception handling code here -----

        }
        return retValue;
    }

    //------------------------------------------------------------------------------
    // Following method disposes all the class members
    //------------------------------------------------------------------------------
    [DebuggerStepThrough] public void Dispose()
    {
        try
        {
            if (isDisposeCalled == false)
            {
                //TODO: Add your application code here
            }
            isDisposeCalled = true;
        }
        catch (NXOpen.NXException)
        {
            // ---- Enter your exception handling code here -----

        }
    }

    [DebuggerStepThrough] public static int GetUnloadOption(string arg)
    {
        //Unloads the image explicitly, via an unload dialog
        //return System.Convert.ToInt32(Session.LibraryUnloadOption.Explicitly);

        //Unloads the image immediately after execution within NX
        return System.Convert.ToInt32(Session.LibraryUnloadOption.Immediately);

        //Unloads the image when the NX session terminates
        // return System.Convert.ToInt32(Session.LibraryUnloadOption.AtTermination);
    }

    [DebuggerStepThrough] public void StartDebugger()
    {
        if (!System.Diagnostics.Debugger.IsAttached)
            System.Diagnostics.Debugger.Launch();
    }
    #endregion


    ListingWindow lw;

    int MemberCount { set; get; }

    private void lwWriteLine(string line)
    {
        lw.Open(); lw.WriteLine(line); lw.Close();
    }

    public void DoIt(string[] args)
    {
        ufs.Ui.SetStatus($"Starting SimpleTests");
        //StartDebugger();

        //--------------------------------------------------------------------


        List<object> pfItem = new List<object>();
        List<object> pfStatusOld = new List<object>();

        Session theSession = Session.GetSession();
        Part dispPart = theSession.Parts.Display;
        Part workPart = theSession.Parts.Work;
        NXOpen.PartFamily.TemplateManager templateManager = workPart.NewPartFamilyTemplateManager();
        UFSession theUFSession = UFSession.GetUFSession();
        lw = theSession.ListingWindow;
        int iColPartName = -1;
        bool is_family_template;
        theUFSession.Part.IsFamilyTemplate(dispPart.Tag, out is_family_template);

        WriteHeader();

        if ((is_family_template == false))
        {
            return;
        }

        int family_count;
        Tag[] families;
        theUFSession.Part.AskFamilies(dispPart.Tag, out family_count, out families);

        int colPartNumber = -1;
        int colUsageStatus = -1;

        for (int ii = 0; (ii <= (family_count - 1)); ii++)
        {
            UFFam.FamilyData family_data;
            theUFSession.Fam.AskFamilyData(families[ii], out family_data);
            int member_count = family_data.member_count;

            Hashtable tab = new Hashtable();
            MemberCount = family_data.attribute_count + 1;

            if ((iColPartName == -1))
            {
                for (int jj = 0; (jj <= (family_data.attribute_count - 1)); jj++)
                {
                    UFFam.AttributeData attribute_data;
                    theUFSession.Fam.AskAttributeData(family_data.attributes[jj], out attribute_data);

                    tab.Add(jj, attribute_data.name);

                    if (attribute_data.name == "DB_PART_NO")
                    {
                        colPartNumber = jj;
                    }
                    if (attribute_data.name == "usage_status")
                    {
                        colUsageStatus = jj;
                    }
                }
            }

            pfItem.Clear();
            pfStatusOld.Clear();

            for (int kk = 0; (kk <= (member_count - 1)); kk++)
            {
                UFFam.MemberData member_row_data;
                theUFSession.Fam.AskMemberRowData(families[ii], kk, out member_row_data);

                pfItem.Add(member_row_data.values[colPartNumber]);
                pfStatusOld.Add(member_row_data.values[colUsageStatus]);
            }

            PfItem = pfItem;
            PfStatusOld = pfStatusOld;
        }

        //Form mit den Tabellen aufrufen
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());

        WriteNewValus(); //Anzeigen welche Werte in die PartFamily zurückgeschrieben werden

        //Werte in die PartFamily zurückschreiben
        for (int ii = 0; (ii <= (family_count - 1)); ii++)
        {
            UFFam.FamilyData family_data;
            theUFSession.Fam.AskFamilyData(families[ii], out family_data);
            int member_count = family_data.member_count;

            Hashtable tab = new Hashtable();

            if ((iColPartName == -1))
            {
                for (int jj = 0; (jj <= (family_data.attribute_count - 1)); jj++)
                {
                    UFFam.AttributeData attribute_data;
                    theUFSession.Fam.AskAttributeData(family_data.attributes[jj], out attribute_data);

                    tab.Add(jj, attribute_data.name);

                    if (attribute_data.name == "DB_PART_NO")
                    {
                        colPartNumber = jj;
                    }
                    if (attribute_data.name == "usage_status")
                    {
                        colUsageStatus = jj;
                    }
                }
            }

            //Werte in die Kinderteile schreiben
			WriteMembers(member_count, families, ii, colPartNumber, colUsageStatus);

            //Part Speichern
            theUFSession.Part.Save();
            lwWriteLine(" ");
			lwWriteLine("Part saved in the meantime.");

            //Family Member aktualisieren
            UpdateMembers();
            
            templateManager.Dispose();

            //Part Speichern
            theUFSession.Part.Save();
            lwWriteLine(" ");
			lwWriteLine("Part saved.");
            lwWriteLine(" ");
            lwWriteLine("+-----------------------------------------+");
            lwWriteLine("| Update process finished successfully!!! |");
            lwWriteLine("+-----------------------------------------+");
        }

        //--------------------------------------------------------------------

        ufs.Ui.SetStatus($"Finishing SimpleTests");
    }

    private void WriteHeader()
    {
        lwWriteLine("Update SAP usage status:");
        lwWriteLine("------------------------");
        lwWriteLine("The following 3 easy steps will update the 'usage status' in a part family master and its child members.");
        lwWriteLine("1. Select button 'Read SAP Columns' and chooes the Excel sheet where the informatio are stored.");
        lwWriteLine("   Attention: Make sure that the columns 'Object' and 'VStat' always exist.");
        lwWriteLine("2. The system reads all necessary information from the Excel sheet, calculates the status and");
        lwWriteLine("   displays them all in the left table. Please be patient, this will take some time.");
        lwWriteLine("   The system then determines the existing child members with the saved status settings,");
        lwWriteLine("   assigns them the new status values and displays all this information in the right table.");
        lwWriteLine("3. All recognized changes are already selected in the right column. If you do not want to");
        lwWriteLine("   accept all changes, you can deselect them here. If you are satisfied with the selection,");
        lwWriteLine("   press the 'Save Changes' button. All changes will be applied, the child members will be");
        lwWriteLine("   updated and the master part will be saved.");
        lwWriteLine("That's it.");
        lwWriteLine(" ");
        lwWriteLine("The status of the individual steps are displayed below:");
        lwWriteLine("-------------------------------------------------------");
    }

    private void WriteNewValus()
    {
        //Anzeigen welche Werte in die PartFamily zurückgeschrieben werden
        lwWriteLine(" ");
        lwWriteLine("The following changes will be made:");
        lwWriteLine("-----------------------------------");
        for (int i = 0; i < PfItem.Count; i++)
        {
            lwWriteLine(String.Concat(PfItem[i].ToString(), ": ", PfStatusOld[i].ToString(), " --> ", PfStatusNew[i].ToString()));
        }
        if (PfItem.Count == 0)
        {
            lwWriteLine("No changes are made.");
        }
        lwWriteLine(" ");
    }

    private void WriteValueToFamily(string dbPartNo, string value, int memberCount, int i)
    {
        NXOpen.Session theSession = NXOpen.Session.GetSession();
        NXOpen.Part workPart = theSession.Parts.Work;
        NXOpen.Part displayPart = theSession.Parts.Display;
        // ----------------------------------------------
        //   Menu: Tools->Part Families...
        // ----------------------------------------------
        NXOpen.PartFamily.TemplateManager templateManager;
        templateManager = workPart.NewPartFamilyTemplateManager();

        templateManager.EditPartFamily();

        NXOpen.PartFamily.FamilyAttribute familyAttribute1;
        familyAttribute1 = templateManager.GetPartFamilyAttribute(NXOpen.PartFamily.FamilyAttribute.AttrType.Name, "DB_PART_NO");

        NXOpen.PartFamily.FamilyAttribute familyAttribute2;
        familyAttribute2 = templateManager.GetPartFamilyAttribute(NXOpen.PartFamily.FamilyAttribute.AttrType.Name, "OS_PART_NAME");

        NXOpen.PartFamily.FamilyAttribute[] keyattrs1 = new NXOpen.PartFamily.FamilyAttribute[2];
        keyattrs1[0] = familyAttribute1;
        keyattrs1[1] = familyAttribute2;
        string[] attrvalues1 = new string[2];
        attrvalues1[0] = dbPartNo;
        attrvalues1[1] = dbPartNo;
        NXOpen.PartFamily.MemberIdentifier memberIdentifier;
        memberIdentifier = templateManager.CreateMemberIdentifier(keyattrs1, attrvalues1, "ETC4_DesignSTD");

        NXOpen.PartFamily.InstanceDefinition instanceDefinition;
        instanceDefinition = templateManager.GetInstanceDefinitionUsingMemberIdentifier(memberIdentifier);

        memberIdentifier.Dispose();
        NXOpen.PartFamily.FamilyAttribute familyAttribute3;
        familyAttribute3 = templateManager.GetPartFamilyAttribute(NXOpen.PartFamily.FamilyAttribute.AttrType.Expression, "usage_status");

        instanceDefinition.SetValueOfAttribute(familyAttribute3, value);

        instanceDefinition.Dispose();

        templateManager.SavePartFamily();

        templateManager.Dispose();
    }
	
	private void WriteMembers(int member_count, Tag[] families, int ii, int colPartNumber, int colUsageStatus)
    {
        //Werte in die Kinderteile schreiben
        NXOpen.Session theSession = NXOpen.Session.GetSession();
        NXOpen.Part workPart = theSession.Parts.Work;
        NXOpen.Part displayPart = theSession.Parts.Display;
        UFSession theUFSession = UFSession.GetUFSession();
        int family_count;
        theUFSession.Part.AskFamilies(displayPart.Tag, out family_count, out families);

        lwWriteLine(" ");
        lwWriteLine("Writing values into part family:");
        lwWriteLine("--------------------------------");
        for (int kk = 0; (kk <= (member_count - 1)); kk++)
        {
            UFFam.MemberData member_row_data;
            theUFSession.Fam.AskMemberRowData(families[ii], kk, out member_row_data);

            for (int i = 0; i < PfItem.Count; i++)
            {
                if (member_row_data.values[colPartNumber] == PfItem[i].ToString())
                {
                    if (PfStatusNew[i].ToString().Contains("\""))
                    {
                        WriteValueToFamily(PfItem[i].ToString(), PfStatusNew[i].ToString(), MemberCount, i);
                    }
                    else
                    {
                        WriteValueToFamily(PfItem[i].ToString(), String.Concat("\"", PfStatusNew[i].ToString(), "\""), MemberCount, i);
                    }
                    lwWriteLine($"{PfItem[i]}: Value {member_row_data.values[colUsageStatus]} was written successfully.");
                }
            }
        }

        lwWriteLine(" ");
        lwWriteLine("Part family saved.");
    }

    private void UpdateMembers()
    {
        lwWriteLine(" ");
        lwWriteLine("Update and save all members:");
        lwWriteLine("----------------------------");
		
		NXOpen.Session theSession = NXOpen.Session.GetSession();
        NXOpen.Part workPart = theSession.Parts.Work;
        NXOpen.Part displayPart = theSession.Parts.Display;
        // ----------------------------------------------
        //   Menu: Tools->Part Families...
        // ----------------------------------------------
        NXOpen.Session.UndoMarkId markId1;
        markId1 = theSession.SetUndoMark(NXOpen.Session.MarkVisibility.Visible, "Start");

        NXOpen.PartFamily.TemplateManager templateManager1;
        templateManager1 = workPart.NewPartFamilyTemplateManager();

        theSession.SetUndoMarkName(markId1, "Part Families Dialog");

        NXOpen.Session.UndoMarkId markId2;
        markId2 = theSession.SetUndoMark(NXOpen.Session.MarkVisibility.Invisible, "Enter Spreadsheet");

        templateManager1.EditPartFamily();

        NXOpen.PartFamily.FamilyAttribute[] familyAttribute1 = new NXOpen.PartFamily.FamilyAttribute[PfItem.Count];
        NXOpen.PartFamily.FamilyAttribute[] familyAttribute2 = new NXOpen.PartFamily.FamilyAttribute[PfItem.Count];
        NXOpen.PartFamily.MemberIdentifier[] memberIdentifier1 = new NXOpen.PartFamily.MemberIdentifier[PfItem.Count];
        NXOpen.PartFamily.InstanceDefinition[] instanceDefinition1 = new NXOpen.PartFamily.InstanceDefinition[PfItem.Count];

        for (int i = 0; i < PfItem.Count; i++)
        {
            // ----------------------------------------------
            //   Dialog Begin Part Family Warning
            // ----------------------------------------------
            familyAttribute1[i] = templateManager1.GetPartFamilyAttribute(NXOpen.PartFamily.FamilyAttribute.AttrType.Name, "DB_PART_NO");

            /*NXOpen.PartFamily.FamilyAttribute familyAttribute2*/;
            familyAttribute2[i] = templateManager1.GetPartFamilyAttribute(NXOpen.PartFamily.FamilyAttribute.AttrType.Name, "OS_PART_NAME");

            NXOpen.PartFamily.FamilyAttribute[] keyattrs1 = new NXOpen.PartFamily.FamilyAttribute[2];
            keyattrs1[0] = familyAttribute1[i];
            keyattrs1[1] = familyAttribute2[i];
            string[] attrvalues1 = new string[2];
            attrvalues1[0] = PfItem[i].ToString();
            attrvalues1[1] = PfItem[i].ToString();
            memberIdentifier1[i] = templateManager1.CreateMemberIdentifier(keyattrs1, attrvalues1, "ETC4_DesignSTD");

            instanceDefinition1[i] = templateManager1.GetInstanceDefinitionUsingMemberIdentifier(memberIdentifier1[i]);

            memberIdentifier1[i].Dispose();
        }

        NXOpen.PartFamily.InstanceDefinition[] instdefstoupdate1 = new NXOpen.PartFamily.InstanceDefinition[PfItem.Count];
        for (int i = 0; i < PfItem.Count; i++)
        {
            instdefstoupdate1[i] = instanceDefinition1[i];
        }

        int[] errorcodes1;
        errorcodes1 = templateManager1.SaveFamilyAndUpdateMembers(false, instdefstoupdate1);

        for (int i = 0; i < PfItem.Count; i++)
        {
            instanceDefinition1[i].Dispose();
			lwWriteLine($"{PfItem[i]} was updated and saved successfully.");
        }

        lwWriteLine(" ");
        lwWriteLine("All change were done successfully.");
    }
}