using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.IO.Ports;
using System.Diagnostics;

using MatterHackers.Agg;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.OpenGlGui;
using MatterHackers.PolygonMesh;
using MatterHackers.RenderOpenGl;
using MatterHackers.VectorMath;
using MatterHackers.MatterControl.DataStorage;

namespace MatterHackers.MatterControl.PrinterControls.PrinterConnections
{
    public class SetupConnectionWidget : ConnectionWidgetBase
    {
        List<SerialPortIndexRadioButton> SerialPortButtonsList = new List<SerialPortIndexRadioButton>();
        List<BaudRateRadioButton> BaudRateButtonsList = new List<BaudRateRadioButton>();
        FlowLayoutWidget ConnectionControlContainer;
        FlowLayoutWidget printerModelContainer;
        FlowLayoutWidget printerMakeContainer;
        FlowLayoutWidget printerNameContainer;
        FlowLayoutWidget printerSerialPortContainer;
        FlowLayoutWidget printerBaudRateContainer;
        FlowLayoutWidget printerDriverContainer;
        
        TextWidget printerModelError;
        TextWidget printerMakeError;
        TextWidget printerComPortError;
        TextWidget printerBaudRateError;
        TextWidget printerNameError;
        TextWidget printerDriverMessage;

        Button printerDriverInstallButton;

        Printer ActivePrinter;
        MHTextEditWidget printerNameInput;
        MHTextEditWidget otherBaudRateInput;
        LinkButtonFactory linkButtonFactory = new LinkButtonFactory();
        Button saveButton;
        Button cancelButton;
        GuiWidget comPortLabelWidget;
        GuiWidget baudRateWidget;
        RadioButton otherBaudRateRadioButton;
        bool editBaudRate = true;
        bool installDriver = true;
        bool printerComExists = false;
        TextImageButtonFactory textImageButtonFactory = new TextImageButtonFactory();
        TextImageButtonFactory installButtonFactory = new TextImageButtonFactory();

        bool addNewPrinterFlag = false;



        public SetupConnectionWidget(ConnectionWindow windowController, GuiWidget containerWindowToClose, Printer activePrinter = null)
            : base(windowController, containerWindowToClose)
        {
            SetDisplayAttributes();

            GuiWidget mainContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);
            mainContainer.AnchorAll();
            mainContainer.Padding = new BorderDouble(3, 0, 3, 5);
            mainContainer.BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor;

            string headerTitle;

            if (activePrinter == null)
            {
                headerTitle = string.Format("3-D Printer Setup");
                this.addNewPrinterFlag = true;
                this.ActivePrinter = new Printer();
                this.ActivePrinter.Make = null;
                this.ActivePrinter.Model = null;
                this.ActivePrinter.Name = "Default Printer";
                this.ActivePrinter.BaudRate = "250000";
                try
                {
                    this.ActivePrinter.ComPort = SerialPort.GetPortNames()[0];
                }
                catch
                {
                    //No active COM ports
                }
            }
            else
            {
                this.ActivePrinter = activePrinter;
                headerTitle = string.Format("Edit - {0}", this.ActivePrinter.Name);
            }

            //Create the header row for the widget
            FlowLayoutWidget headerRow = new FlowLayoutWidget(FlowDirection.LeftToRight);
            headerRow.Margin = new BorderDouble(0, 3, 0, 0);
            headerRow.Padding = new BorderDouble(0, 3, 0, 3);
            headerRow.HAnchor = HAnchor.ParentLeftRight;
            {
                TextWidget headerLabel = new TextWidget(headerTitle, pointSize: 14);
                headerLabel.TextColor = this.defaultTextColor;
                headerRow.AddChild(headerLabel);
            }

            //Create the main control container
            ConnectionControlContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);
            ConnectionControlContainer.Padding = new BorderDouble(5);
            ConnectionControlContainer.BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor;
            ConnectionControlContainer.HAnchor = HAnchor.ParentLeftRight;
            {
                ConnectionControlContainer.VAnchor = VAnchor.ParentBottomTop;
                
                printerMakeContainer = createPrinterMakeContainer();
                printerModelContainer = createPrinterModelContainer();
                printerSerialPortContainer = createPrinterSerialPortContainer();
                printerBaudRateContainer = createPrinterBaudRateContainer();
                printerDriverContainer = createPrinterDriverContainer();
                printerNameContainer = createPrinterNameContainer();

                ConnectionControlContainer.AddChild(printerMakeContainer);
                ConnectionControlContainer.AddChild(printerModelContainer);
                ConnectionControlContainer.AddChild(printerSerialPortContainer);
                ConnectionControlContainer.AddChild(printerBaudRateContainer);
                ConnectionControlContainer.AddChild(printerDriverContainer);
                //ConnectionControlContainer.AddChild(printerNameContainer);
            }

            FlowLayoutWidget buttonContainer = new FlowLayoutWidget(FlowDirection.LeftToRight);
            buttonContainer.HAnchor = HAnchor.ParentLeft | HAnchor.ParentRight;
            //buttonContainer.VAnchor = VAnchor.BottomTop;
            buttonContainer.Margin = new BorderDouble(0, 3);
            {
                //Construct buttons
                saveButton = textImageButtonFactory.Generate("Save");
                //saveButton.VAnchor = VAnchor.Bottom;

                cancelButton = textImageButtonFactory.Generate("Cancel");
                //cancelButton.VAnchor = VAnchor.Bottom;
                cancelButton.Click += new ButtonBase.ButtonEventHandler(CancelButton_Click);

                //Add buttons to buttonContainer
                buttonContainer.AddChild(saveButton);
                buttonContainer.AddChild(cancelButton);
            }

            mainContainer.AddChild(headerRow);
            mainContainer.AddChild(ConnectionControlContainer);
            mainContainer.AddChild(buttonContainer);

            this.AddChild(mainContainer);

            BindSaveButtonHandlers();
            BindBaudRateHandlers();
            SetElementState();
        }

        private void SetDisplayAttributes()
        {
            textImageButtonFactory.normalTextColor = RGBA_Bytes.White;
            textImageButtonFactory.hoverTextColor = RGBA_Bytes.White;
            textImageButtonFactory.disabledTextColor = RGBA_Bytes.White;
            textImageButtonFactory.pressedTextColor = RGBA_Bytes.White;
            textImageButtonFactory.borderWidth = 0;

            installButtonFactory.normalFillColor = ActiveTheme.Instance.PrimaryTextColor;
            installButtonFactory.normalTextColor = RGBA_Bytes.Black;           
            installButtonFactory.borderWidth = 0;

            linkButtonFactory.textColor = RGBA_Bytes.White;
            linkButtonFactory.fontSize = 10;

            this.BackgroundColor = ActiveTheme.Instance.SecondaryBackgroundColor;
            this.AnchorAll();
            this.Padding = new BorderDouble(0); //To be re-enabled once native borders are turned off
        }

        static int createCount = 0;
        void RecreateWidget(AfterUiArgs eventArgs)
        {
            // you can call this like this
            //             AfterUiEvents.AddAction(new AfterUIAction(RecreateWidget));
            createCount++;
            Parent.AddChild(new AddConnectionWidget((ConnectionWindow)Parent, Parent, ActivePrinter));
            Parent.RemoveChild(this);
        }

        private void LoadSetupSettings(string make, string model)
        {
            Dictionary<string, string> settingsDict = LoadPrinterSetupFromFile(make, model);

            //Determine if baud rate is needed and show controls if required
            string baudRate;
            if (settingsDict.TryGetValue("baud_rate", out baudRate))
            {
                ActivePrinter.BaudRate = baudRate;
                editBaudRate = false;
            }
            else
            {
                editBaudRate = true;
            }

            //Determine if driver is needed and show install button as required
            string driverFile;
            installDriver = false;
            if (settingsDict.TryGetValue("windows_driver", out driverFile))
            {
                string infPathAndFileToInstall = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "Drivers", driverFile);
                switch (MatterHackers.Agg.UI.WindowsFormsAbstract.GetOSType())
                {
                    case Agg.UI.WindowsFormsAbstract.OSType.Windows:
                        if (File.Exists(infPathAndFileToInstall))
                        {
                            installDriver = true;
                        }
                        break;

                    default:
                        break;
                }
            }
        }

        private Dictionary<string, string> LoadPrinterSetupFromFile(string make, string model)
        {
            string setupSettingsPathAndFile = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "PrinterSettings", make, model, "setup.ini");
            Dictionary<string, string>  settingsDict = new Dictionary<string, string>();
            
            if (System.IO.File.Exists(setupSettingsPathAndFile))
            {
                try
                {
                    string[] lines = System.IO.File.ReadAllLines(setupSettingsPathAndFile);
                    foreach (string line in lines)
                    {
                        //Ignore commented lines
                        if (!line.StartsWith("#"))
                        {
                            string[] settingLine = line.Split('=');
                            string keyName = settingLine[0].Trim();
                            string settingDefaultValue = settingLine[1].Trim();

                            settingsDict.Add(keyName, settingDefaultValue);
                        }
                    }
                }
                catch
                {

                }
            }
            return settingsDict;
        }

        private void LoadPrinterSliceSettings(string make, string model)
        {
            string sliceSettingsPathAndFile = Path.Combine(ApplicationDataStorage.Instance.ApplicationStaticDataPath, "PrinterSettings", make, model, "config.ini");
            if (System.IO.File.Exists(sliceSettingsPathAndFile))
            {
                DataStorage.SliceSettingsCollection defaultCollection = new DataStorage.SliceSettingsCollection();
                defaultCollection.Name = "__printer_default__";

                SettingsLayer defaultSettingsLayer = ActiveSliceSettings.Instance.LoadConfigurationSettingsFromFile(sliceSettingsPathAndFile, defaultCollection);

                //Commit layer values
                foreach (KeyValuePair<String, DataStorage.SliceSetting> item in defaultSettingsLayer.settingsDictionary)
                {
                    item.Value.Commit();
                }
            }
        }

        private void SetElementState()
        {
            printerModelContainer.Visible = (this.ActivePrinter.Make != null);
            printerSerialPortContainer.Visible = (this.ActivePrinter.Model != null);
            if (editBaudRate)
            {
                printerBaudRateContainer.Visible = (this.ActivePrinter.Model != null);
            }
            else
            {
                printerBaudRateContainer.Visible = false;
            }

            if (installDriver)
            {
                printerDriverContainer.Visible = (this.ActivePrinter.Model != null);
            }
            else
            {
                printerDriverContainer.Visible = false;
            }

        }

        private FlowLayoutWidget createPrinterDriverContainer()
        {
            FlowLayoutWidget container = new FlowLayoutWidget(FlowDirection.TopToBottom);
            container.Margin = new BorderDouble(0, 5);
            BorderDouble elementMargin = new BorderDouble(top: 3);

            printerDriverInstallButton = installButtonFactory.Generate("Install Driver");
            printerDriverInstallButton.Margin = new BorderDouble(0, 5);

            printerDriverMessage = new TextWidget("This printer requires a driver for communication.", 0, 0, 10);
            printerDriverMessage.TextColor = RGBA_Bytes.White;
            printerDriverMessage.HAnchor = HAnchor.ParentLeftRight;
            printerDriverMessage.Margin = elementMargin;

            container.AddChild(printerDriverMessage);
            container.AddChild(printerDriverInstallButton);

            container.HAnchor = HAnchor.ParentLeftRight;
            return container;


        }

        private FlowLayoutWidget createPrinterMakeContainer()
        {
            FlowLayoutWidget container = new FlowLayoutWidget(FlowDirection.TopToBottom);
            container.Margin = new BorderDouble(0, 5);
            BorderDouble elementMargin = new BorderDouble(top: 3);

            TextWidget printerManufacturerLabel = new TextWidget("Select Make:", 0, 0, 12);
            printerManufacturerLabel.TextColor = this.defaultTextColor;
            printerManufacturerLabel.HAnchor = HAnchor.ParentLeftRight;
            printerManufacturerLabel.Margin = elementMargin;

            PrinterChooser printerManufacturerSelector = new PrinterChooser();
            printerManufacturerSelector.HAnchor = HAnchor.ParentLeftRight;
            printerManufacturerSelector.Margin = elementMargin;
            printerManufacturerSelector.ManufacturerDropList.SelectionChanged +=new EventHandler(ManufacturerDropList_SelectionChanged);

            printerMakeError = new TextWidget("Select the printer manufacturer", 0, 0, 10);
            printerMakeError.TextColor = RGBA_Bytes.White;
            printerMakeError.HAnchor = HAnchor.ParentLeftRight;
            printerMakeError.Margin = elementMargin;

            container.AddChild(printerManufacturerLabel);
            container.AddChild(printerManufacturerSelector);
            container.AddChild(printerMakeError);

            container.HAnchor = HAnchor.ParentLeftRight;
            return container;
        }

        private void ManufacturerDropList_SelectionChanged(object sender, EventArgs e)
        {
            ActivePrinter.Make = ((DropDownList)sender).SelectedValue;
            ActivePrinter.Model = null;

            //reconstruct model selector
            int currentIndex = ConnectionControlContainer.GetChildIndex(printerModelContainer);
            ConnectionControlContainer.RemoveChild(printerModelContainer);

            printerModelContainer = createPrinterModelContainer(ActivePrinter.Make);
            ConnectionControlContainer.AddChild(printerModelContainer, currentIndex);
            ConnectionControlContainer.Invalidate();

            printerMakeError.Visible = false;
            SetElementState();            
        }

        private void ModelDropList_SelectionChanged(object sender, EventArgs e)
        {
            ActivePrinter.Model = ((DropDownList)sender).SelectedValue;
            LoadSetupSettings(ActivePrinter.Make, ActivePrinter.Model);
            printerModelError.Visible = false;
            SetElementState();            
        }

        private FlowLayoutWidget createPrinterModelContainer(string make = "Other")
        {
            FlowLayoutWidget container = new FlowLayoutWidget(FlowDirection.TopToBottom);
            container.Margin = new BorderDouble(0, 5);
            BorderDouble elementMargin = new BorderDouble(top: 3);

            TextWidget printerModelLabel = new TextWidget("Select Model:", 0, 0, 12);
            printerModelLabel.TextColor = this.defaultTextColor;
            printerModelLabel.HAnchor = HAnchor.ParentLeftRight;
            printerModelLabel.Margin = elementMargin;

            ModelChooser printerModelSelector = new ModelChooser(make);
            printerModelSelector.HAnchor = HAnchor.ParentLeftRight;
            printerModelSelector.Margin = elementMargin;
            printerModelSelector.ModelDropList.SelectionChanged += new EventHandler(ModelDropList_SelectionChanged);

            printerModelError = new TextWidget("Select the printer model", 0, 0, 10);
            printerModelError.TextColor = RGBA_Bytes.White;
            printerModelError.HAnchor = HAnchor.ParentLeftRight;
            printerModelError.Margin = elementMargin;


            container.AddChild(printerModelLabel);
            container.AddChild(printerModelSelector);
            container.AddChild(printerModelError);

            container.HAnchor = HAnchor.ParentLeftRight;
            return container;
        }

        private FlowLayoutWidget createPrinterBaudRateContainer()
        {
            FlowLayoutWidget container = new FlowLayoutWidget(FlowDirection.TopToBottom);
            container.Margin = new BorderDouble(0, 5);
            BorderDouble elementMargin = new BorderDouble(top: 3);

            TextWidget baudRateLabel = new TextWidget("Baud Rate:", 0, 0, 12);
            baudRateLabel.TextColor = this.defaultTextColor;
            baudRateLabel.Margin = new BorderDouble(0, 0, 0, 10);
            baudRateLabel.HAnchor = HAnchor.ParentLeftRight;

            baudRateWidget = GetBaudRateWidget();
            baudRateWidget.HAnchor = HAnchor.ParentLeftRight;

            printerBaudRateError = new TextWidget("Select the baud rate", 0, 0, 10);
            printerBaudRateError.TextColor = RGBA_Bytes.White;
            printerBaudRateError.HAnchor = HAnchor.ParentLeftRight;
            printerBaudRateError.Margin = elementMargin;

            container.AddChild(baudRateLabel);
            container.AddChild(baudRateWidget);
            container.AddChild(printerBaudRateError);

            container.HAnchor = HAnchor.ParentLeftRight;
            return container;
        }

        private FlowLayoutWidget createPrinterNameContainer()
        {
            FlowLayoutWidget container = new FlowLayoutWidget(FlowDirection.TopToBottom);
            container.Margin = new BorderDouble(0, 5);
            BorderDouble elementMargin = new BorderDouble(top: 3);
            
            TextWidget printerNameLabel = new TextWidget("Printer Name:", 0, 0, 12);
            printerNameLabel.TextColor = this.defaultTextColor;
            printerNameLabel.HAnchor = HAnchor.ParentLeftRight;
            printerNameLabel.Margin = new BorderDouble(0, 0, 0, 1);

            printerNameInput = new MHTextEditWidget(this.ActivePrinter.Name);
            printerNameInput.HAnchor = HAnchor.ParentLeftRight;

            printerNameError = new TextWidget("Enter a printer name", 0, 0, 10);
            printerNameError.TextColor = RGBA_Bytes.White;
            printerNameError.HAnchor = HAnchor.ParentLeftRight;
            printerNameError.Margin = elementMargin;

            container.AddChild(printerNameLabel);
            container.AddChild(printerNameInput);
            container.AddChild(printerNameError);
            container.HAnchor = HAnchor.ParentLeftRight;
            return container;
        }


        private FlowLayoutWidget createPrinterSerialPortContainer()
        {
            FlowLayoutWidget container = new FlowLayoutWidget(FlowDirection.TopToBottom);
            container.Margin = new BorderDouble(0, 5);
            BorderDouble elementMargin = new BorderDouble(top: 3);

            comPortLabelWidget = new FlowLayoutWidget();

            Button refreshComPorts = linkButtonFactory.Generate("refresh");
            refreshComPorts.Click += new ButtonBase.ButtonEventHandler(RefreshComPorts);
            refreshComPorts.VAnchor = VAnchor.ParentCenter;

            TextWidget comPortLabel = new TextWidget("COM Port:", 0, 0, 12);
            comPortLabel.TextColor = this.defaultTextColor;
            comPortLabel.HAnchor = HAnchor.ParentLeftRight;

            comPortLabelWidget.AddChild(comPortLabel);
            comPortLabelWidget.AddChild(refreshComPorts);
            comPortLabelWidget.Margin = new BorderDouble(0, 0, 0, 10);
            comPortLabelWidget.HAnchor = HAnchor.ParentLeftRight;

            FlowLayoutWidget comPortContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);
            comPortContainer.Margin = new BorderDouble(0);
            comPortContainer.HAnchor = HAnchor.ParentLeftRight;

            int portIndex = 0;
            foreach (string serialPort in SerialPort.GetPortNames())
            {
                //Filter com port list based on usb type (applies to Mac mostly)
                bool looks_like_mac = serialPort.StartsWith("/dev/tty.");
                bool looks_like_pc = serialPort.StartsWith("COM");
                if (looks_like_mac || looks_like_pc)
                {
                    SerialPortIndexRadioButton comPortOption = createComPortOption(serialPort);
                    comPortContainer.AddChild(comPortOption);
                    portIndex++;
                }
            }

            //If there are no com ports in the filtered list assume we are missing something and show the unfiltered list
            if (portIndex == 0)
            {

                foreach (string serialPort in SerialPort.GetPortNames())
                {
                    SerialPortIndexRadioButton comPortOption = createComPortOption(serialPort);
                    comPortContainer.AddChild(comPortOption);
                    portIndex++;
                }
            }

            //If there are still no com ports show a message to that effect
            if (portIndex == 0)
            {
                TextWidget comPortOption = new TextWidget("No COM ports available");
                comPortOption.Margin = new BorderDouble(3, 6, 5, 6);
                comPortOption.TextColor = this.subContainerTextColor;
                comPortContainer.AddChild(comPortOption);
            }

            printerComPortError = new TextWidget("Select the port", 0, 0, 10);
            printerComPortError.TextColor = RGBA_Bytes.White;
            printerComPortError.HAnchor = HAnchor.ParentLeftRight;
            printerComPortError.Margin = elementMargin;

            container.AddChild(comPortLabelWidget);
            container.AddChild(comPortContainer);
            container.AddChild(printerComPortError);
            container.HAnchor = HAnchor.ParentLeftRight;
            return container;

        }

        public GuiWidget GetBaudRateWidget()
        {
            FlowLayoutWidget baudRateContainer = new FlowLayoutWidget(FlowDirection.TopToBottom);
            baudRateContainer.Margin = new BorderDouble(0);

            //TO DO - Add handling for 'Other' option with attached TextEdit
            List<string> baudRates = new List<string> { "115200", "250000" };
            BorderDouble baudRateMargin = new BorderDouble(3, 3, 5, 3);

            foreach (string baudRate in baudRates)
            {
                BaudRateRadioButton baudOption = new BaudRateRadioButton(baudRate);
                BaudRateButtonsList.Add(baudOption);
                baudOption.Margin = baudRateMargin;
                baudOption.TextColor = this.subContainerTextColor;
                if (this.ActivePrinter.BaudRate == baudRate)
                {
                    baudOption.Checked = true;
                }
                baudRateContainer.AddChild(baudOption);
            }

            otherBaudRateRadioButton = new RadioButton("Other");
            otherBaudRateRadioButton.Margin = baudRateMargin;
            otherBaudRateRadioButton.TextColor = this.subContainerTextColor;

            baudRateContainer.AddChild(otherBaudRateRadioButton);

            //See if the baud rate of the current print is in the list of displayed rates,
            //flag the 'other' option if it is not and prefill the rate.
            if (!baudRates.Contains(this.ActivePrinter.BaudRate.ToString()))
            {
                otherBaudRateRadioButton.Checked = true;
                otherBaudRateInput = new MHTextEditWidget(this.ActivePrinter.BaudRate.ToString());
                //otherBaudRateInput.Visible = true;
            }
            else
            {
                otherBaudRateInput = new MHTextEditWidget("");
                //otherBaudRateInput.Visible = false;
            }
            otherBaudRateInput.HAnchor = HAnchor.ParentLeftRight;

            baudRateContainer.AddChild(otherBaudRateInput);
            return baudRateContainer;
        }

        private void BindBaudRateHandlers()
        {
            otherBaudRateRadioButton.CheckedStateChanged += new RadioButton.CheckedStateChangedEventHandler(BindBaudRate_Select);
            foreach (BaudRateRadioButton button in BaudRateButtonsList)
            {
                button.CheckedStateChanged += new RadioButton.CheckedStateChangedEventHandler(BindBaudRate_Select);
            }
            BindBaudRate_Select(null, null);
        }

        private void BindBaudRate_Select(object sender, EventArgs e)
        {
            if (otherBaudRateRadioButton.Checked == true)
            {
                otherBaudRateInput.Visible = true;
            }
            else
            {
                otherBaudRateInput.Visible = false;
            }
        }

        public SerialPortIndexRadioButton createComPortOption(string serialPort)
        {
            //Add formatting here to make port names prettier
            string portName = serialPort;

            SerialPortIndexRadioButton comPortOption = new SerialPortIndexRadioButton(portName, serialPort);
            SerialPortButtonsList.Add(comPortOption);

            comPortOption.Margin = new BorderDouble(3, 3, 5, 3);
            comPortOption.TextColor = this.subContainerTextColor;

            if (this.ActivePrinter.ComPort == serialPort)
            {
                comPortOption.Checked = true;
                printerComExists = true;
            }
            return comPortOption;
        }

        void RefreshComPorts(object sender, MouseEventArgs mouseEvent)
        {
            try
            {
                this.ActivePrinter.Name = printerNameInput.Text;
                this.ActivePrinter.BaudRate = GetSelectedBaudRate();
                this.ActivePrinter.ComPort = GetSelectedSerialPort();
            }
            catch
            {

            }
            this.windowController.ChangedToEditPrinter(this.ActivePrinter);
        }

        void ReloadCurrentWidget(object sender, MouseEventArgs mouseEvent)
        {
            if (this.addNewPrinterFlag == true)
            {
                this.windowController.ChangeToAddPrinter();
            }
            else
            {
                this.windowController.ChangedToEditPrinter(this.ActivePrinter);
            }
        }

        void BindSaveButtonHandlers()
        {
            saveButton.UnbindClickEvents();
            saveButton.Text = "Save";
            saveButton.Enabled = true;
            saveButton.Click += new ButtonBase.ButtonEventHandler(SaveButton_Click);
        }

        void CloseWindow(object o, MouseEventArgs e)
        {
            PrinterCommunication.Instance.HaltConnectionThread();
            this.containerWindowToClose.Close();
        }

        void CancelButton_Click(object sender, MouseEventArgs mouseEvent)
        {
            if (GetPrinterRecordCount() > 0)
            {
                this.windowController.ChangeToChoosePrinter();
            }
            else
            {
                this.containerWindowToClose.Close();
            }
        }

        void SaveButton_Click(object sender, MouseEventArgs mouseEvent)
        {
            this.ActivePrinter.Name = printerNameInput.Text;
            try
            {
                this.ActivePrinter.BaudRate = GetSelectedBaudRate();
                this.ActivePrinter.ComPort = GetSelectedSerialPort();
            }
            catch
            {
                //Unable to retrieve Baud or Port, possibly because they weren't shown as options - needs better handling
            }
            this.ActivePrinter.Commit();

            this.windowController.ChangeToChoosePrinter();
        }

        private string GetSelectedBaudRate()
        {
            foreach (BaudRateRadioButton button in BaudRateButtonsList)
            {
                if (button.Checked)
                {
                    return button.BaudRate.ToString();
                }
            }
            if (otherBaudRateRadioButton.Checked)
            {
                return otherBaudRateInput.Text;
            }

            throw new Exception("Could not find a selected button.");
        }

        void InstallDriver(string fileName)
        {
            string systemFolder = Environment.GetFolderPath(System.Environment.SpecialFolder.System);
            string pathToDriver = Path.Combine(systemFolder, "DriverStore", "FileRepository");
            foreach (string directory in Directory.EnumerateDirectories(pathToDriver))
            {
                if (directory.ToUpper().Contains("REPLICATOR.INF"))
                {
                    int a = 0;
                }
            }

            string infPathAndFileToInstall = string.Format("/data/Drivers/{0}", fileName);
            switch (MatterHackers.Agg.UI.WindowsFormsAbstract.GetOSType())
            {
                case Agg.UI.WindowsFormsAbstract.OSType.Windows:
                    if (!File.Exists(infPathAndFileToInstall))
                    {
                        var driverInstallerProcess = new Process();
                        // Prepare the process to run
                        // Enter in the command line arguments, everything you would enter after the executable name itself
                        driverInstallerProcess.StartInfo.Arguments = "--installInf \"" + infPathAndFileToInstall;
                        // Enter the executable to run, including the complete path
                        string printerDriverInstallerExePathAndFileName = Path.Combine(".", "PrinterDriverInstaller.exe");

                        driverInstallerProcess.StartInfo.CreateNoWindow = true;
                        driverInstallerProcess.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                        driverInstallerProcess.StartInfo.FileName = System.IO.Path.GetFullPath(printerDriverInstallerExePathAndFileName);
                        driverInstallerProcess.StartInfo.Verb = "runas";
                        driverInstallerProcess.StartInfo.UseShellExecute = true;

                        driverInstallerProcess.Start();

                        driverInstallerProcess.WaitForExit();

                        // Retrieve the app's exit code
                        var exitCode = driverInstallerProcess.ExitCode;
                    }
                    break;

                case Agg.UI.WindowsFormsAbstract.OSType.Mac:
                    break;
            }
        }

        private string GetSelectedSerialPort()
        {
            foreach (SerialPortIndexRadioButton button in SerialPortButtonsList)
            {
                if (button.Checked)
                {
                    return button.PortValue;
                }
            }

            throw new Exception("Could not find a selected button.");
        }
    }
}
