/// <summary>
        /// Takes manual input parameters for a valve print without movement command and outputs the command to the serial port.
        /// </summary>
        /// <param name="openTime"></param>
        public void ProcessManualValvePrintWithoutMovementCommand(int valveOpenTime)
        {
            string printString = GCodeLinesConverter.GCodeLinesListToString(
                WriteG00.WriteValvePrintWithoutMovement(valveOpenTime));

            _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(printString);
        }
        /// <summary>
        /// Takes manual input parameters for a set of commands for motorized printhead droplet printing and outputs the commands to the serial port.
        /// </summary>
        /// <param name="xDistance"></param>
        /// <param name="yDistance"></param>
        /// <param name="zDistance"></param>
        /// <param name="interpolateDistance"></param>
        /// <param name="eDispensePerDroplet"></param>
        public void ProcessManualMotorDropletPrintCommand(double xDistance, double yDistance, double zDistance, double interpolateDistance, double eDispensePerDroplet)
        {
            PrintheadModel printheadModel = _printerModel.FindPrinthead(_realTimeStatusDataModel.ActivePrintheadModel.Name);
            MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)printheadModel.PrintheadTypeModel;
            double emmPerStep = motorizedPrintheadTypeModel.MmPerStep;
            RealTimeStatusMotorizedPrintheadModel realTimeStatusMotorizedPrintheadModel = (RealTimeStatusMotorizedPrintheadModel)_realTimeStatusDataModel.ActivePrintheadModel;
            double    eMaxSpeed          = realTimeStatusMotorizedPrintheadModel.MaxSpeed;
            double    eAcceleration      = realTimeStatusMotorizedPrintheadModel.Acceleration;
            double    xmmPerStep         = (xDistance != 0) ? _printerModel.AxisModelList[0].MmPerStep : double.MaxValue;
            double    ymmPerStep         = (yDistance != 0) ? _printerModel.AxisModelList[1].MmPerStep : double.MaxValue;
            AxisModel zAxisModel         = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name);
            double    zmmPerStep         = (zDistance != 0) ? _printerModel.FindAxis(zAxisModel.Name).MmPerStep : double.MaxValue;
            bool      zDirectionInverted = (zAxisModel != null) ? zAxisModel.IsDirectionInverted : false;

            double unused      = 0;
            string printString = GCodeLinesConverter.GCodeLinesListToString(
                WriteG00.WriteMotorizedDropletPrint(
                    emmPerStep, xmmPerStep, ymmPerStep, zmmPerStep,
                    eDispensePerDroplet, 0, xDistance, 0, yDistance, 0, zDistance,
                    _printerModel.AxisModelList[0].IsDirectionInverted, _printerModel.AxisModelList[1].IsDirectionInverted, zDirectionInverted, motorizedPrintheadTypeModel.IsDirectionInverted,
                    ref unused, ref unused, ref unused, ref unused,
                    null, new DropletModel(interpolateDistance)));

            _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(printString);
        }
        /// <summary>
        /// Takes manual input parameters for a motor print without movement command and outputs the command to the serial port.
        /// </summary>
        /// <param name="eDistance"></param>
        public void ProcessManualMotorPrintWithoutMovementCommand(double eDistance)
        {
            MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)_printerModel.FindPrinthead(_realTimeStatusDataModel.ActivePrintheadModel.Name).PrintheadTypeModel;
            double emmPerStep = motorizedPrintheadTypeModel.MmPerStep;
            RealTimeStatusMotorizedPrintheadModel realTimeStatusMotorizedPrintheadModel = (RealTimeStatusMotorizedPrintheadModel)_realTimeStatusDataModel.ActivePrintheadModel;

            double unused      = 0;
            string printString = GCodeLinesConverter.GCodeLinesListToString(
                WriteG00.WriteMotorizedPrintWithoutMovement(eDistance, emmPerStep, motorizedPrintheadTypeModel.IsDirectionInverted, ref unused, null));

            _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(printString);
        }
        /// <summary>
        /// Returns a set of commands for Axis movement that compensates for a new Printhead's offsets.
        /// Print speeds will be maximized before moving to offset.
        /// </summary>
        /// <param name="newPrinthead"></param>
        /// <param name="currentPrinthead"></param>
        /// <param name="zPosition">Relative position of the Z Axis before and after switching.</param>
        /// <param name="pauseBeforeActivating">Pauses the print sequence before lowering the Z actuator.</param>
        /// <returns></returns>
        private List <string> WriteMoveToOffset(PrintheadModel newPrinthead, PrintheadModel currentPrinthead, double zPosition, bool pauseBeforeActivating)
        {
            List <string> returnCommands = new List <string>();

            AxisModel xAxisModel = _printerModel.AxisModelList[0];
            AxisModel yAxisModel = _printerModel.AxisModelList[1];
            AxisModel zAxisModel = newPrinthead.AttachedZAxisModel;

            double xMove = newPrinthead.XOffset - currentPrinthead.XOffset;
            double yMove = newPrinthead.YOffset - currentPrinthead.YOffset;
            double zMove = 0;

            if (newPrinthead.AttachedZAxisModel.Name != _realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name)
            {
                //If a new Z actuator is requried.
                zMove = -1 * (newPrinthead.AttachedZAxisModel.MaxPosition - GlobalValues.LimitBuffer) + zPosition;
            }

            //Move to the X and Y offsets first to prevent bumping of print container walls.
            double unused = 0;

            if ((xMove != 0) || (yMove != 0))
            {
                //Maximize movement speeds before moving to offset.
                returnCommands.Add(_writeSetAxisModel.WriteSetAxis(_printerModel.AxisModelList[0]));
                returnCommands.Add(_writeSetAxisModel.WriteSetAxis(_printerModel.AxisModelList[1]));
                returnCommands.Add(GCodeLinesConverter.GCodeLinesListToString(
                                       WriteG00.WriteAxesMovement(xAxisModel.MmPerStep, yAxisModel.MmPerStep, 0,
                                                                  xMove, yMove, 0, xAxisModel.IsDirectionInverted, yAxisModel.IsDirectionInverted, false,
                                                                  ref unused, ref unused, ref unused)));
            }

            //Pause before activating.
            if (pauseBeforeActivating == true)
            {
                returnCommands.Add(SerialMessageCharacters.SerialPrintPauseCharacter.ToString());
            }

            //Move the Z offset after the X and Y positions are set.
            if (zMove != 0)
            {
                returnCommands.Add(_writeSetAxisModel.WriteSetAxis(newPrinthead.AttachedZAxisModel));
                returnCommands.Add(GCodeLinesConverter.GCodeLinesListToString(
                                       WriteG00.WriteAxesMovement(0, 0, zAxisModel.MmPerStep,
                                                                  0, 0, zMove, false, false, zAxisModel.IsDirectionInverted,
                                                                  ref unused, ref unused, ref unused)));
            }

            return(returnCommands);
        }
        /// <summary>
        /// Generate commands for retracting a Z Axis.
        /// </summary>
        /// <param name="zAxisModel"></param>
        /// <returns></returns>
        private List <string> RetractZ(string commandSet, AxisModel zAxisModel)
        {
            List <string> returnCommands = new List <string>();

            if (zAxisModel != null)
            {
                //Retract Z Axis.\
                double unused             = 0;
                bool   zDirectionInverted = (zAxisModel != null) ? zAxisModel.IsDirectionInverted : false;
                if (commandSet.Contains("Limit")) //If CommandSet is "RetractZLimit", then hit the Limit Switch before returning to default position.
                {
                    //Hit the Limti Switch.
                    double retractDistance = 5000;

                    string zRetract = GCodeLinesConverter.GCodeLinesListToString(
                        WriteG00.WriteAxesMovement(
                            1, 1, zAxisModel.MmPerStep,
                            0, 0, retractDistance,
                            false, false, zDirectionInverted,
                            ref unused, ref unused, ref unused));
                    returnCommands.Add(zRetract);

                    //Move away from the Limit Switch to default position.
                    string zMoveAwayFromLimit = GCodeLinesConverter.GCodeLinesListToString(
                        WriteG00.WriteAxesMovement(
                            0, 0, zAxisModel.MmPerStep,
                            0, 0, -1 * GlobalValues.LimitBuffer,
                            false, false, zAxisModel.IsDirectionInverted,
                            ref unused, ref unused, ref unused));
                    returnCommands.Add(zMoveAwayFromLimit);
                }
                else //If the CommandSet is "RetractZ", then move to default position without hitting the Limit Switch.
                {
                    //Move to default position.
                    double retractDistance = zAxisModel.MaxPosition - _realTimeStatusDataModel.ZRealTimeStatusAxisModel.Position - GlobalValues.LimitBuffer;
                    string zRetract        = GCodeLinesConverter.GCodeLinesListToString(
                        WriteG00.WriteAxesMovement(
                            1, 1, zAxisModel.MmPerStep,
                            0, 0, retractDistance,
                            false, false, zDirectionInverted,
                            ref unused, ref unused, ref unused));
                    returnCommands.Add(zRetract);
                }

                return(returnCommands);
            }

            return(null);
        }
        /// <summary>
        /// Takes manual input parameters for a movement command and outputs the command to the serial port.
        /// </summary>
        /// <param name="xDistance"></param>
        /// <param name="yDistance"></param>
        /// <param name="zDistance"></param>
        public void ProcessManualMovementCommand(double xDistance, double yDistance, double zDistance)
        {
            double    xmmPerStep         = (xDistance != 0) ? _printerModel.AxisModelList[0].MmPerStep : double.MaxValue;
            double    ymmPerStep         = (yDistance != 0) ? _printerModel.AxisModelList[1].MmPerStep : double.MaxValue;
            AxisModel zAxisModel         = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name);
            double    zmmPerStep         = (zDistance != 0) ? _printerModel.FindAxis(zAxisModel.Name).MmPerStep : double.MaxValue;
            bool      zDirectionInverted = (zAxisModel != null) ? zAxisModel.IsDirectionInverted : false;

            double unused             = 0;
            string axesMovementString = GCodeLinesConverter.GCodeLinesListToString(
                WriteG00.WriteAxesMovement(xmmPerStep, ymmPerStep, zmmPerStep,
                                           xDistance, yDistance, zDistance,
                                           _printerModel.AxisModelList[0].IsDirectionInverted, _printerModel.AxisModelList[1].IsDirectionInverted, zDirectionInverted,
                                           ref unused, ref unused, ref unused));

            _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(axesMovementString);
        }
        /// <summary>
        /// Takes manual input parameters for a motor print with movement command and outputs the command to the serial port.
        /// </summary>
        /// <param name="xDistance"></param>
        /// <param name="yDistance"></param>
        /// <param name="zDistance"></param>
        /// <param name="eDispensePerDistance"></param>
        public void ProcessManualMotorPrintWithMovementCommand(double xDistance, double yDistance, double zDistance, double eDispensePerDistance)
        {
            MotorizedPrintheadTypeModel motorizedPrintheadTypeModel = (MotorizedPrintheadTypeModel)_printerModel.FindPrinthead(_realTimeStatusDataModel.ActivePrintheadModel.Name).PrintheadTypeModel;
            double    emmPerStep         = motorizedPrintheadTypeModel.MmPerStep;
            double    xmmPerStep         = (xDistance != 0) ? _printerModel.AxisModelList[0].MmPerStep : double.MaxValue;
            double    ymmPerStep         = (yDistance != 0) ? _printerModel.AxisModelList[1].MmPerStep : double.MaxValue;
            AxisModel zAxisModel         = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name);
            double    zmmPerStep         = (zDistance != 0) ? _printerModel.FindAxis(zAxisModel.Name).MmPerStep : double.MaxValue;
            bool      zDirectionInverted = (zAxisModel != null) ? zAxisModel.IsDirectionInverted : false;

            double unused      = 0;
            string printString = GCodeLinesConverter.GCodeLinesListToString(
                WriteG00.WriteMotorizedContinuousPrint(emmPerStep, xmmPerStep, ymmPerStep, zmmPerStep,
                                                       eDispensePerDistance, xDistance, yDistance, zDistance,
                                                       _printerModel.AxisModelList[0].IsDirectionInverted, _printerModel.AxisModelList[1].IsDirectionInverted, zDirectionInverted, motorizedPrintheadTypeModel.IsDirectionInverted,
                                                       ref unused, ref unused, ref unused, ref unused,
                                                       null));

            _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(printString);
        }
        /// <summary>
        /// Interpret a center axes command set and return an array of commands.
        /// </summary>
        /// <param name="commandSet"></param>
        /// <returns></returns>
        private List <string> InterpretCenterAxes(string commandSet)
        {
            //Command set to be returned.
            List <string> returnCommands = new List <string>();

            AxisModel xAxisModel = _printerModel.AxisModelList[0];
            AxisModel yAxisModel = _printerModel.AxisModelList[1];
            RealTimeStatusAxisModel xRealTimeStatusAxisModel = _realTimeStatusDataModel.XRealTimeStatusAxisModel;
            RealTimeStatusAxisModel yRealTimeStatusAxisModel = _realTimeStatusDataModel.YRealTimeStatusAxisModel;
            double xNewPosition = xRealTimeStatusAxisModel.Position;
            double yNewPosition = yRealTimeStatusAxisModel.Position;

            //mmPerStep for each actuator.
            double xmmPerStep = 0;
            double ymmPerStep = 0;

            //InvertDirection for each actuator.
            bool xInvertDirection = (xAxisModel.IsDirectionInverted == false) ? false : true;
            bool yInvertDirection = (yAxisModel.IsDirectionInverted == false) ? false : true;

            //Distances from the center.
            double xDistanceFromCenter = 0;
            double yDistanceFromCenter = 0;

            string[] gCodePhrases = GCodeStringParsing.GCodeTo2DArr(commandSet)[0];
            foreach (string phrase in gCodePhrases)
            {
                switch (phrase[0])
                {
                case 'X':
                    xDistanceFromCenter = GCodeStringParsing.ParseDouble(phrase);
                    break;

                case 'Y':
                    yDistanceFromCenter = GCodeStringParsing.ParseDouble(phrase);
                    break;

                default:
                    //Do nothing.
                    break;
                }
            }

            //Centering the actuator involves:
            // 1. Finding the median position directly in the center of the max and min position.
            // 2. Finding the distance between median position and the current position.
            // 3. Executing that difference worth of movement.

            if (commandSet.Contains("X"))
            {
                xNewPosition = (xAxisModel.MaxPosition - xAxisModel.MinPosition) / 2 + xAxisModel.MinPosition + xDistanceFromCenter;
                xmmPerStep   = xAxisModel.MmPerStep;
            }

            if (commandSet.Contains("Y"))
            {
                yNewPosition = (yAxisModel.MaxPosition - yAxisModel.MinPosition) / 2 + yAxisModel.MinPosition + yDistanceFromCenter;
                ymmPerStep   = yAxisModel.MmPerStep;
            }

            double unused = 0;

            returnCommands.Add(GCodeLinesConverter.GCodeLinesListToString(
                                   WriteG00.WriteAxesMovement(
                                       xmmPerStep, ymmPerStep, 0,
                                       xNewPosition - xRealTimeStatusAxisModel.Position, yNewPosition - yRealTimeStatusAxisModel.Position, 0,
                                       xInvertDirection, yInvertDirection, false,
                                       ref unused, ref unused, ref unused)));

            return(returnCommands);
        }
        /// <summary>
        /// Takes manual input parameters for a valve close command and outputs the command to the serial port.
        /// </summary>
        public void ProcessManualValveCloseCommand()
        {
            string valveCloseString = GCodeLinesConverter.GCodeLinesListToString(WriteG00.WriteValveClose());

            _serialCommunicationOutgoingMessagesModel.QueueNextProspectiveOutgoingMessage(valveCloseString);
        }
        /// <summary>
        /// Sends outgoing commands that retracts all Z Axes and moves X and Y Axes to the limit switches.
        /// </summary>
        public void Home(double xCalibrationSpeed, double yCalibrationSpeed, double zCalibrationSpeed, double xDistanceFromCenter, double yDistanceFromCenter)
        {
            try
            {
                //Retract Z Axes.
                RetractAllZ(zCalibrationSpeed);

                //Z Axes should be in default positions.
                AxisModel zAxisModel = _printerModel.ZAxisModelList[_printerModel.ZAxisModelList.Count - 1];
                double    zPosition  = zAxisModel.MaxPosition - GlobalValues.LimitBuffer;
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(SerialMessageCharacters.SerialCommandSetCharacter + "SetMinMaxPos " + "Z" + zPosition);

                //Set X Axis to calibration speeds.
                AxisModel xAxis       = _printerModel.AxisModelList[0];
                int       xLimitPinID = (xAxis.AttachedLimitSwitchGPIOPinModel == null) ? GlobalValues.PinIDNull : xAxis.AttachedLimitSwitchGPIOPinModel.PinID;
                string    switchX     = _writeSetAxisModel.WriteSetAxis(xAxis.AxisID, xAxis.AttachedMotorStepGPIOPinModel.PinID, xAxis.AttachedMotorDirectionGPIOPinModel.PinID, xAxis.StepPulseTime,
                                                                        xLimitPinID, xCalibrationSpeed, xAxis.MaxAcceleration, xAxis.MmPerStep);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchX);

                //Set Y Axis to max speeds.
                AxisModel yAxis       = _printerModel.AxisModelList[1];
                int       yLimitPinID = (yAxis.AttachedLimitSwitchGPIOPinModel == null) ? GlobalValues.PinIDNull : yAxis.AttachedLimitSwitchGPIOPinModel.PinID;
                string    switchY     = _writeSetAxisModel.WriteSetAxis(yAxis.AxisID, yAxis.AttachedMotorStepGPIOPinModel.PinID, yAxis.AttachedMotorDirectionGPIOPinModel.PinID, yAxis.StepPulseTime,
                                                                        yLimitPinID, yCalibrationSpeed, yAxis.MaxAcceleration, yAxis.MmPerStep);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchY);

                //Hit the min and max limit switches on X.
                double unused    = 0;
                string xPositive = GCodeLinesConverter.GCodeLinesListToString(
                    WriteG00.WriteAxesMovement(
                        xAxis.MmPerStep, 0, 0,
                        5000, 0, 0,
                        xAxis.IsDirectionInverted, false, false,
                        ref unused, ref unused, ref unused));
                string xNegative = GCodeLinesConverter.GCodeLinesListToString(
                    WriteG00.WriteAxesMovement(
                        xAxis.MmPerStep, 0, 0,
                        -5000, 0, 0,
                        xAxis.IsDirectionInverted, false, false,
                        ref unused, ref unused, ref unused));
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(xPositive);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(xNegative);

                //Move away from the limit switch.
                string xMoveAwayFromLimit = GCodeLinesConverter.GCodeLinesListToString(
                    WriteG00.WriteAxesMovement(
                        xAxis.MmPerStep, 0, 0,
                        GlobalValues.LimitBuffer, 0, 0,
                        xAxis.IsDirectionInverted, false, false,
                        ref unused, ref unused, ref unused));
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(xMoveAwayFromLimit);

                //Hit the min and max limit switches on Y.
                string yPositive = GCodeLinesConverter.GCodeLinesListToString(
                    WriteG00.WriteAxesMovement(
                        0, yAxis.MmPerStep, 0,
                        0, 5000, 0,
                        yAxis.IsDirectionInverted, false, false,
                        ref unused, ref unused, ref unused));
                string yNegative = GCodeLinesConverter.GCodeLinesListToString(
                    WriteG00.WriteAxesMovement(
                        0, yAxis.MmPerStep, 0,
                        0, -5000, 0,
                        yAxis.IsDirectionInverted, false, false,
                        ref unused, ref unused, ref unused));
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(yPositive);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(yNegative);

                //Move away from the limit switch.
                string yMoveAwayFromLimit = GCodeLinesConverter.GCodeLinesListToString(
                    WriteG00.WriteAxesMovement(
                        0, yAxis.MmPerStep, 0,
                        0, GlobalValues.LimitBuffer, 0,
                        yAxis.IsDirectionInverted, false, false,
                        ref unused, ref unused, ref unused));
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(yMoveAwayFromLimit);

                //Set X Axis to max speeds.
                string switchXMax = _writeSetAxisModel.WriteSetAxis(xAxis);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchXMax);

                //Set Y Axis to max speeds.
                string switchYMax = _writeSetAxisModel.WriteSetAxis(yAxis);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchYMax);

                //Center the X and Y actuators.
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(SerialMessageCharacters.SerialCommandSetCharacter + "Center X" + xDistanceFromCenter + " Y" + yDistanceFromCenter);
                _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(SerialMessageCharacters.SerialCommandSetCharacter + "OriginXY");

                //At the end, switch the Z actuator to the Printhead used at the beginning of the print.
                if (_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name != "Unset")
                {
                    AxisModel zAxisFinalModel  = _printerModel.FindAxis(_realTimeStatusDataModel.ZRealTimeStatusAxisModel.Name);
                    int       zFinalLimitPinID = (zAxisFinalModel.AttachedLimitSwitchGPIOPinModel == null) ? GlobalValues.PinIDNull : zAxisFinalModel.AttachedLimitSwitchGPIOPinModel.PinID;
                    string    switchZFinal     = _writeSetAxisModel.WriteSetAxis(zAxisFinalModel.AxisID, zAxisFinalModel.AttachedMotorStepGPIOPinModel.PinID, zAxisFinalModel.AttachedMotorDirectionGPIOPinModel.PinID,
                                                                                 zAxisFinalModel.StepPulseTime, zFinalLimitPinID, zCalibrationSpeed, zAxisFinalModel.MaxAcceleration, zAxisFinalModel.MmPerStep);
                    _serialCommunicationOutgoingMessagesModel.AppendProspectiveOutgoingMessage(switchZFinal);
                }

                OnCalibrationBegun();
            }
            catch
            {
                _errorListViewModel.AddError("", "Unkown error when homing");
            }
        }
        /// <summary>
        /// Processes the command of setting a printhead.
        /// </summary>
        public List <ConvertedGCodeLine> ProcessTCommand(string[] repRapLine, ref MaterialModel currentMaterial)
        {
            AxisModel xAxis        = _printerModel.AxisModelList[0];
            AxisModel yAxis        = _printerModel.AxisModelList[1];
            AxisModel zAxisCurrent = _printerModel.FindAxis(currentMaterial.PrintheadModel.AttachedZAxisModel.Name);

            //The return GCode.
            List <ConvertedGCodeLine> convertedGCodeLinesList = new List <ConvertedGCodeLine>();

            //Finds the material that matches the TCommand.
            string        repRapTCommand   = repRapLine[0];
            MaterialModel matchingMaterial = _printModel.FindMaterial(repRapTCommand);

            //Appends the converted GCode line with a command that sets the Printhead.
            //Also appends the converted GCode line with a command that sets the new Z Axis associated with the new Printhead.
            //Also appends the converted GCode line with commands that compensate for the new Printhead's offsets.
            try
            {
                //If the current Material is using a Motorized Printhead, retract it before switching Printheads.
                if (((currentMaterial.Name != "Unset") && //If this is not the first Material
                     (currentMaterial.PrintheadModel.PrintheadType == PrintheadType.Motorized) &&
                     (currentMaterial.PrintheadModel.Name != matchingMaterial.PrintheadModel.Name) && //Do not execute retraction-related actions if no Printhead change occurs
                     (_parametersModel.IsRetracted == false)))
                {
                    MotorizedPrintheadTypeModel motorizedPrintheadTypeModel   = (MotorizedPrintheadTypeModel)currentMaterial.PrintheadModel.PrintheadTypeModel;
                    ContinuousPrintStyleModel   continuousPrintheadStyleModel = (ContinuousPrintStyleModel)currentMaterial.PrintStyleModel;
                    int eModiPrintCoordIndex = _parametersModel.FindEModiPrintCoordIndex(currentMaterial.PrintheadModel);
                    convertedGCodeLinesList = WriteG00.WriteMotorizedPrintWithoutMovement(-1 * continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance, motorizedPrintheadTypeModel.MmPerStep,
                                                                                          motorizedPrintheadTypeModel.IsDirectionInverted, ref _parametersModel.ERepRapCoord.DeltaCoordRemainder, _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex]);
                    _parametersModel.IsRetracted = true;
                }

                //If a new Motorized Printhead is being set...
                //Finds the EModiPrintCoord corresponding to the given Printhead and sets the Minimum and Maximum Position values of the EModiPrintCoord.
                if (matchingMaterial.PrintheadModel.PrintheadType == PrintheadType.Motorized)
                {
                    int eModiPrintCoordIndex = _parametersModel.FindEModiPrintCoordIndex(matchingMaterial.PrintheadModel);
                    MotorizedPrintheadTypeModel motorizedPrintheadTypeModel   = (MotorizedPrintheadTypeModel)matchingMaterial.PrintheadModel.PrintheadTypeModel;
                    ContinuousPrintStyleModel   continuousPrintheadStyleModel = (ContinuousPrintStyleModel)matchingMaterial.PrintStyleModel;

                    //Sets new Min and Max Positions.
                    _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex].MinPosition = motorizedPrintheadTypeModel.MinPosition;
                    _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex].MaxPosition = motorizedPrintheadTypeModel.MaxPosition;

                    //Sets the starting position of the new Motorized Printhead.
                    //The starting position is the retracted state.
                    //If this is the first Material, then retraction needs to occur to reach the starting retracted state.
                    if (currentMaterial.Name == "Unset") //If this is the first Material.
                    {
                        //Retraction needs to occur to reach the starting retracted state.
                        List <ConvertedGCodeLine> retractE = WriteG00.WriteMotorizedPrintWithoutMovement(-1 * continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance, motorizedPrintheadTypeModel.MmPerStep,
                                                                                                         motorizedPrintheadTypeModel.IsDirectionInverted, ref _parametersModel.ERepRapCoord.DeltaCoordRemainder, _parametersModel.EModiPrintCoordList[eModiPrintCoordIndex]);
                        if (retractE != null)
                        {
                            convertedGCodeLinesList.AddRange(retractE);
                        }

                        _parametersModel.ERepRapCoord.SetInitialCoord(continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance);
                        _parametersModel.IsRetracted = true;
                    }

                    //If this is a new Motorized Printhead, then it is by default, retracted.
                    if (currentMaterial.PrintheadModel.Name != matchingMaterial.PrintheadModel.Name)
                    {
                        _parametersModel.ERepRapCoord.SetInitialCoord(continuousPrintheadStyleModel.MotorizedDispenseRetractionDistance);
                        _parametersModel.IsRetracted = true;
                    }
                }
                else
                {
                    _parametersModel.IsRetracted = false;
                }

                //Set new Min and Max Positions for the X and Y Axes.
                //This is only relevant when the first Material is set.
                _parametersModel.SetNewXYZCoord('X', _parametersModel.XCoord.CurrentCoord, _printerModel.AxisModelList[0].MinPosition, _printerModel.AxisModelList[0].MaxPosition);
                _parametersModel.SetNewXYZCoord('Y', _parametersModel.YCoord.CurrentCoord, _printerModel.AxisModelList[1].MinPosition, _printerModel.AxisModelList[1].MaxPosition);

                //If the Z Axis does not need to be changed, then keep the same Min and Max Positions in the ZCoord.
                //If the Z Axis was switched, then set a new ZCoord Position assuming the Z Axis started from a retracted position and traversed its Offset.
                if (matchingMaterial.PrintheadModel.AttachedZAxisModel.Name != matchingMaterial.PrintheadModel.AttachedZAxisModel.Name)
                {
                    AxisModel zAxisModel   = _printerModel.FindAxis(matchingMaterial.PrintheadModel.AttachedZAxisModel.Name);
                    double    newZPosition = zAxisModel.MaxPosition - GlobalValues.LimitBuffer;
                    _parametersModel.SetNewXYZCoord('Z', newZPosition, zAxisModel.MinPosition, zAxisModel.MaxPosition);
                }

                //Set new Droplet parameters if applicable.
                if (!((currentMaterial.Name == "Unset") || (currentMaterial == null)) && //If the current Material is set to Droplet...
                    (currentMaterial.PrintStyle == PrintStyle.Droplet))
                {
                    //Execute movement for the remaining movement left in droplet movements.
                    MaterialModel             newMaterialParameter        = (matchingMaterial.PrintStyle == PrintStyle.Droplet) ? matchingMaterial : null;
                    double[]                  remainingDropletMovementArr = _parametersModel.ResetDropletPrintParameters(currentMaterial, newMaterialParameter);
                    double                    unused = 0;
                    List <ConvertedGCodeLine> remainingDropletMovement = WriteG00.WriteAxesMovement(
                        xAxis.MmPerStep, yAxis.MmPerStep, zAxisCurrent.MmPerStep,
                        remainingDropletMovementArr[0], remainingDropletMovementArr[1], remainingDropletMovementArr[2],
                        xAxis.IsDirectionInverted, yAxis.IsDirectionInverted, zAxisCurrent.IsDirectionInverted,
                        ref unused, ref unused, ref unused);
                    if (remainingDropletMovement != null)
                    {
                        convertedGCodeLinesList.AddRange(remainingDropletMovement);
                    }
                }
                else if (matchingMaterial.PrintStyle == PrintStyle.Droplet) //If the current Material is irrelevant and the new Material is set to Droplet...
                {
                    _parametersModel.ResetDropletPrintParameters(null, matchingMaterial);
                }

                //Set the new Material.
                currentMaterial = matchingMaterial;

                //Command Set for switching Materials.
                //This Command Set will convert to the commands for retracting the Z Axis, switching Printheads, moving Offsets, and setting new movement speeds.
                string convertedGCodeLine = SerialMessageCharacters.SerialCommandSetCharacter + "SwitchMaterial ";

                //If applicable, pause the print sequence before switching to the next Material.
                if ((currentMaterial.Name != "Unset") && (currentMaterial.PauseBeforeDeactivating == true))
                {
                    convertedGCodeLine += "D";
                }

                //If applicable pause the print sequence after switching printheads.
                if (matchingMaterial.PauseAfterActivating == true)
                {
                    convertedGCodeLine += "A";
                }

                if (convertedGCodeLine[convertedGCodeLine.Length - 1] != ' ')
                {
                    convertedGCodeLine += " ";
                }
                convertedGCodeLine += '"' + matchingMaterial.Name + '"';
                convertedGCodeLinesList.Add(new ConvertedGCodeLine(convertedGCodeLine));
            }
            catch when((matchingMaterial == null) || (currentMaterial == null))  //Catch unset Material.
            {
                //Catching and error reporting should have happened earlier.
                _parametersModel.ErrorReporterViewModel.ReportError("G-Code Conversion Failed: Print Settings Incorrectly Set, Should Not Happen", "Material Null");
                return(null);
            }