/// <summary>
        /// This maybe should go into a different class like Stimulation.cs, but it's here for now.
        ///It gets the group stim params based on the group that was read from the device.
        ///if Group b was read from the device, then it gets the params for that specific group.
        /// </summary>
        /// <param name="theSummit">Summit System</param>
        /// <param name="group">Active Group after being converted: Group A, Group B, Group C, Group D</param>
        /// <param name="program">program 0-3</param>
        /// <returns>StimParameterModel filled with data</returns>
        public StimParameterModel GetStimParamsBasedOnGroup(SummitSystem theSummit, string group, int program)
        {
            StimParameterModel stimParam = new StimParameterModel("Error", "Error", "Error", "Error", null);

            if (string.IsNullOrEmpty(group))
            {
                return(stimParam);
            }
            switch (group)
            {
            case "Group A":
                stimParam = GetStimParameterModel(theSummit, GroupNumber.Group0, program);
                break;

            case "Group B":
                stimParam = GetStimParameterModel(theSummit, GroupNumber.Group1, program);
                break;

            case "Group C":
                stimParam = GetStimParameterModel(theSummit, GroupNumber.Group2, program);
                break;

            case "Group D":
                stimParam = GetStimParameterModel(theSummit, GroupNumber.Group3, program);
                break;

            default:
                break;
            }
            return(stimParam);
        }
        public MontageViewModel(ref SummitSystem theSummitLeft, ref SummitSystem theSummitRight, ILog _log, AppModel appModel)
        {
            this.theSummitLeft  = theSummitLeft;
            this.theSummitRight = theSummitRight;
            this.isBilateral    = appModel.Bilateral;
            this._log           = _log;
            this.appModel       = appModel;
            IsMontageEnabled    = true;

            summitSensing      = new SummitSensing(_log);
            jSONService        = new JSONService(_log);
            stimParameterLeft  = new StimParameterModel("", "", "", "", null);
            stimParameterRight = new StimParameterModel("", "", "", "", null);

            montageModel = jSONService.GetMontageModelFromFile(MONTAGE_FILEPATH);
            if (montageModel == null)
            {
                MessageBox.Show("The montage config file could not be read from the file. Please check that it exists.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            montageSweepConfigListLeft = montageSweepConfigListRight = LoadSenseJSONFilesForMontage(MONTAGE_BASEFILEPATH, MONTAGE_FILETYPE, montageModel);
            if (montageSweepConfigListLeft == null || montageSweepConfigListRight == null)
            {
                IsMontageEnabled = false;
                return;
            }

            //Get total time left and total time for montage. Display on progress bar
            timeLeftForMontage = totalTimeForMontage = GetTotalTimeForMontage(montageModel);
            TimeSpan time = TimeSpan.FromSeconds(timeLeftForMontage);
            //here backslash is must to tell that colon is
            //not the part of format, it just a character that we want in output
            string str = time.ToString(@"hh\:mm\:ss");

            MontageTimeTextBox  = "Total Montage Time: " + str;
            InstructionsTextBox = montageModel?.Instructions;
        }
        private void MontageRightThreadCode()
        {
            APIReturnInfo rightBufferReturnInfo;
            int           counter;

            if (theSummitRight == null)
            {
                MessageBox.Show("The summit system is null.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                _stopBothThreads = true;
            }
            if (_stopBothThreads)
            {
                return;
            }
            if (theSummitRight.IsDisposed)
            {
                MessageBox.Show("The summit system is disposed.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                _stopBothThreads = true;
            }
            if (_stopBothThreads)
            {
                return;
            }
            try
            {
                //Make sure embedded therapy is turned off while setting up parameters
                //try it 5 times before error out
                counter = 5;
                while (counter > 0)
                {
                    //Make sure embedded therapy is turned off while setting up parameters
                    rightBufferReturnInfo = theSummitRight.WriteAdaptiveMode(AdaptiveTherapyModes.Disabled);
                    if (rightBufferReturnInfo.RejectCode != 0)
                    {
                        counter--;
                        Thread.Sleep(300);
                    }
                    else
                    {
                        break;
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                }
                if (counter == 0)
                {
                    MessageBox.Show("Could not turn off adaptive therapy.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Could not turn off adaptive therapy.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                _log.Error(e);
                _stopBothThreads = true;
            }
            if (_stopBothThreads)
            {
                return;
            }

            //Check if therapy active. If so, then check if 0-3 contacts stimming
            //if so, then change lfp1 and lfp2 to 100 for each time domain 0 and 1
            bool shouldChangeLfp1andLfp2to100         = false;
            bool shouldChangeLfp1andLfp2to100ForUpper = false;
            SummitStimulationInfo stimInfoRight       = new SummitStimulationInfo(_log);

            if (stimInfoRight.GetTherapyStatus(ref theSummitRight).Equals("TherapyActive"))
            {
                StimParameterModel localStimModel = new StimParameterModel("", "", "", "", null);
                localStimModel = stimInfoRight.GetStimParamsBasedOnGroup(theSummitRight, stimInfoRight.GetActiveGroup(ref theSummitRight), 0);
                for (int i = 0; i < 4; i++)
                {
                    if (!localStimModel.TherapyElectrodes[i].IsOff)
                    {
                        shouldChangeLfp1andLfp2to100 = true;
                    }
                }
                for (int i = 8; i < 12; i++)
                {
                    if (!localStimModel.TherapyElectrodes[i].IsOff)
                    {
                        shouldChangeLfp1andLfp2to100ForUpper = true;
                    }
                }
            }

            int montageIndex = 0;

            foreach (SenseModel localSenseModel in montageSweepConfigListRight)
            {
                if (shouldChangeLfp1andLfp2to100)
                {
                    localSenseModel.Sense.TimeDomains[0].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[0].Lpf2 = 100;
                    localSenseModel.Sense.TimeDomains[1].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[1].Lpf2 = 100;
                }
                if (shouldChangeLfp1andLfp2to100ForUpper)
                {
                    localSenseModel.Sense.TimeDomains[2].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[2].Lpf2 = 100;
                    localSenseModel.Sense.TimeDomains[3].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[3].Lpf2 = 100;
                }
                if (_stopBothThreads)
                {
                    return;
                }
                //stop/configure sensing. Try for 5 times before error out
                counter = 5;
                while (counter > 0)
                {
                    if (summitSensing.SummitConfigureSensing(theSummitRight, localSenseModel, false))
                    {
                        break;
                    }
                    else
                    {
                        counter--;
                        Thread.Sleep(300);
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                }
                if (counter == 0)
                {
                    MessageBox.Show("Could not configure sensing.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
                if (_stopBothThreads)
                {
                    return;
                }
                //start sensing. Try for 5 times before error out
                counter = 5;
                while (counter > 0)
                {
                    if (summitSensing.StartSensingAndStreaming(theSummitRight, localSenseModel, false))
                    {
                        break;
                    }
                    else
                    {
                        counter--;
                        Thread.Sleep(300);
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                }
                if (counter == 0)
                {
                    MessageBox.Show("Could not start sensing.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
                if (_stopBothThreads)
                {
                    return;
                }

                //Set timer to run for timeToRun amount
                int  timeToRunForCurrentMontage = montageModel.MontageFiles[montageIndex].TimeToRunInSeconds;
                int  timeMarkerToAddEvent       = timeToRunForCurrentMontage - TIME_BEFORE_BEGIN_END_MONTAGE;
                bool startTimeHasRun            = false;
                bool stopTimeHasRun             = false;
                while (timeToRunForCurrentMontage > 0)
                {
                    if (timeMarkerToAddEvent == timeToRunForCurrentMontage && !startTimeHasRun)
                    {
                        try
                        {
                            //try once and if fails then try one more time
                            rightBufferReturnInfo = theSummitRight.LogCustomEvent(DateTime.Now, DateTime.Now, "Start : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                            if (rightBufferReturnInfo.RejectCode == 0)
                            {
                                startTimeHasRun = true;
                            }
                            else
                            {
                                rightBufferReturnInfo = theSummitRight.LogCustomEvent(DateTime.Now, DateTime.Now, "Start : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                                startTimeHasRun       = true;
                            }
                        }
                        catch (Exception e)
                        {
                            _log.Error(e);
                        }
                    }
                    if (timeToRunForCurrentMontage == TIME_BEFORE_BEGIN_END_MONTAGE && !stopTimeHasRun)
                    {
                        try
                        {
                            //try once and if fails then try one more time
                            rightBufferReturnInfo = theSummitRight.LogCustomEvent(DateTime.Now, DateTime.Now, "Stop : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                            if (rightBufferReturnInfo.RejectCode == 0)
                            {
                                stopTimeHasRun = true;
                            }
                            else
                            {
                                rightBufferReturnInfo = theSummitRight.LogCustomEvent(DateTime.Now, DateTime.Now, "Stop : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                                stopTimeHasRun        = true;
                            }
                        }
                        catch (Exception e)
                        {
                            _log.Error(e);
                        }
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                    timeToRunForCurrentMontage--;
                    Thread.Sleep(1000);
                }
                montageIndex++;
            }
            rightFinished = true;
            while (true)
            {
                if (leftFinished)
                {
                    break;
                }
            }
        }
        private void MontageLeftThreadCode()
        {
            APIReturnInfo leftBufferReturnInfo;
            int           counter;

            if (theSummitLeft == null)
            {
                MessageBox.Show("The summit system is null.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                _stopBothThreads = true;
            }
            if (_stopBothThreads)
            {
                return;
            }
            try
            {
                if (theSummitLeft.IsDisposed)
                {
                    MessageBox.Show("The summit system is disposed.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
                _stopBothThreads = true;
            }

            if (_stopBothThreads)
            {
                return;
            }
            try
            {
                //Make sure embedded therapy is turned off while setting up parameters
                //try it 5 times before error out
                counter = 5;
                while (counter > 0)
                {
                    leftBufferReturnInfo = theSummitLeft.WriteAdaptiveMode(AdaptiveTherapyModes.Disabled);
                    if (leftBufferReturnInfo.RejectCode != 0)
                    {
                        counter--;
                        Thread.Sleep(300);
                    }
                    else
                    {
                        break;
                    }
                }
                if (counter == 0)
                {
                    MessageBox.Show("Could not turn off adaptive therapy.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
            }
            catch (Exception e)
            {
                MessageBox.Show("Could not turn off adaptive therapy.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                _log.Error(e);
                _stopBothThreads = true;
            }
            if (_stopBothThreads)
            {
                return;
            }

            //Check if therapy active. If so, then check if 0-3 contacts stimming
            //if so, then change lfp1 and lfp2 to 100 for each time domain 0 and 1
            bool shouldChangeLfp1andLfp2to100ForLower = false;
            bool shouldChangeLfp1andLfp2to100ForUpper = false;
            SummitStimulationInfo stimInfoLeft        = new SummitStimulationInfo(_log);

            if (stimInfoLeft.GetTherapyStatus(ref theSummitLeft).Equals("TherapyActive"))
            {
                StimParameterModel localStimModel = new StimParameterModel("", "", "", "", null);
                localStimModel = stimInfoLeft.GetStimParamsBasedOnGroup(theSummitLeft, stimInfoLeft.GetActiveGroup(ref theSummitLeft), 0);
                for (int i = 0; i < 4; i++)
                {
                    if (!localStimModel.TherapyElectrodes[i].IsOff)
                    {
                        shouldChangeLfp1andLfp2to100ForLower = true;
                    }
                }
                for (int i = 8; i < 12; i++)
                {
                    if (!localStimModel.TherapyElectrodes[i].IsOff)
                    {
                        shouldChangeLfp1andLfp2to100ForUpper = true;
                    }
                }
            }



            int montageIndex = 0;

            foreach (SenseModel localSenseModel in montageSweepConfigListLeft)
            {
                if (shouldChangeLfp1andLfp2to100ForLower)
                {
                    localSenseModel.Sense.TimeDomains[0].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[0].Lpf2 = 100;
                    localSenseModel.Sense.TimeDomains[1].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[1].Lpf2 = 100;
                }
                if (shouldChangeLfp1andLfp2to100ForUpper)
                {
                    localSenseModel.Sense.TimeDomains[2].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[2].Lpf2 = 100;
                    localSenseModel.Sense.TimeDomains[3].Lpf1 = 100;
                    localSenseModel.Sense.TimeDomains[3].Lpf2 = 100;
                }
                if (_stopBothThreads)
                {
                    return;
                }
                //stop/configure sensing. Try for 5 times before error out
                counter = 5;
                while (counter > 0)
                {
                    if (summitSensing.SummitConfigureSensing(theSummitLeft, localSenseModel, false))
                    {
                        break;
                    }
                    else
                    {
                        counter--;
                        Thread.Sleep(300);
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                }
                if (counter == 0)
                {
                    MessageBox.Show("Could not configure sensing.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
                if (_stopBothThreads)
                {
                    return;
                }
                //start sensing. Try for 5 times before error out
                counter = 5;
                while (counter > 0)
                {
                    if (summitSensing.StartSensingAndStreaming(theSummitLeft, localSenseModel, false))
                    {
                        break;
                    }
                    else
                    {
                        counter--;
                        Thread.Sleep(300);
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                }
                if (counter == 0)
                {
                    MessageBox.Show("Could not start sensing.  Please try montage again", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    _stopBothThreads = true;
                }
                if (_stopBothThreads)
                {
                    return;
                }

                //Set timer to run for timeToRun amount
                int  timeToRunForCurrentMontage = montageModel.MontageFiles[montageIndex].TimeToRunInSeconds;
                int  timeMarkerToAddEvent       = timeToRunForCurrentMontage - TIME_BEFORE_BEGIN_END_MONTAGE;
                bool startTimeHasRun            = false;
                bool stopTimeHasRun             = false;
                while (timeToRunForCurrentMontage > 0)
                {
                    if (timeToRunForCurrentMontage == timeMarkerToAddEvent && !startTimeHasRun)
                    {
                        try
                        {
                            //try once and if fails then try one more time
                            leftBufferReturnInfo = theSummitLeft.LogCustomEvent(DateTime.Now, DateTime.Now, "Start : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                            if (leftBufferReturnInfo.RejectCode == 0)
                            {
                                startTimeHasRun = true;
                            }
                            else
                            {
                                leftBufferReturnInfo = theSummitLeft.LogCustomEvent(DateTime.Now, DateTime.Now, "Start : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                                startTimeHasRun      = true;
                            }
                        }
                        catch (Exception e)
                        {
                            _log.Error(e);
                        }
                    }
                    if (timeToRunForCurrentMontage == TIME_BEFORE_BEGIN_END_MONTAGE && !stopTimeHasRun)
                    {
                        try
                        {
                            //try once and if fails then try one more time
                            leftBufferReturnInfo = theSummitLeft.LogCustomEvent(DateTime.Now, DateTime.Now, "Stop : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                            if (leftBufferReturnInfo.RejectCode == 0)
                            {
                                stopTimeHasRun = true;
                            }
                            else
                            {
                                leftBufferReturnInfo = theSummitLeft.LogCustomEvent(DateTime.Now, DateTime.Now, "Stop : " + montageModel.MontageFiles[montageIndex].Filename, DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                                stopTimeHasRun       = true;
                            }
                        }
                        catch (Exception e)
                        {
                            _log.Error(e);
                        }
                    }
                    if (_stopBothThreads)
                    {
                        return;
                    }
                    timeToRunForCurrentMontage--;
                    int precentageDoneForTotalMontage = 100 - (int)Math.Round((double)(100 * timeLeftForMontage) / totalTimeForMontage);
                    timeLeftForMontage--;
                    CurrentProgress = precentageDoneForTotalMontage;
                    TimeSpan time = TimeSpan.FromSeconds(timeLeftForMontage);
                    //here backslash is must to tell that colon is
                    //not the part of format, it just a character that we want in output
                    string str = time.ToString(@"hh\:mm\:ss");
                    ProgressText = str + " time left";
                    Thread.Sleep(1000);
                }
                ProgressText = "Loading next montage file...";
                montageIndex++;
            }
            ProgressText = "Finishing up...";
            leftFinished = true;
            while (true)
            {
                if (rightFinished)
                {
                    try
                    {
                        theSummitLeft.LogCustomEvent(DateTime.Now, DateTime.Now, "Montage Stop", DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                        if (isBilateral)
                        {
                            theSummitRight.LogCustomEvent(DateTime.Now, DateTime.Now, "Montage Stop", DateTime.Now.ToString("MM_dd_yyyy hh:mm:ss tt"));
                        }
                    }
                    catch (Exception e)
                    {
                        _log.Error(e);
                        MessageBox.Show("Could not log stop event.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                    }
                    ProgressText = "Success";
                    MessageBox.Show("Montage Successful. Report Screen will open after clicking OK.", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
                    CancelMontageButtonClick();
                    break;
                }
            }
        }
        /// <summary>
        /// Gets the stim parameters based on group from the actual API
        /// </summary>
        /// <param name="theSummit">SummitSystem for making the API call to INS</param>
        /// <param name="groupNumber">Group number corresponding to which group we want to get stim parameters from such as Group0, Group1, etc</param>
        /// <returns>StimParameterModel that contains stim amp, stim rate and pulse width</returns>
        private StimParameterModel GetStimParameterModel(SummitSystem theSummit, GroupNumber groupNumber, int program)
        {
            if (theSummit == null || theSummit.IsDisposed)
            {
                return(null);
            }
            TherapyGroup    insStateGroup = null;
            AmplitudeLimits ampLimits     = null;

            try
            {
                int counter = 5;
                do
                {
                    bufferInfo = theSummit.ReadStimGroup(groupNumber, out insStateGroup);
                    counter--;
                } while ((insStateGroup == null || bufferInfo.RejectCode != 0) && counter > 0);
                if (bufferInfo.RejectCode != 0 && counter == 0)
                {
                    _log.Warn("Could not read stim group from Medtronic api call");
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
            }
            try
            {
                int counter = 5;
                do
                {
                    bufferInfo = theSummit.ReadStimAmplitudeLimits(groupNumber, out ampLimits);
                    counter--;
                } while ((insStateGroup == null || bufferInfo.RejectCode != 0) && counter > 0);
                if (bufferInfo.RejectCode != 0 && counter == 0)
                {
                    _log.Warn("Could not read amp limits from Medtronic api call");
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
            }
            int    pulseWidthValue = -1;
            double rateValue       = -1;
            double ampValue        = -1;

            try
            {
                //parse the data to get the pulsewidth
                if (insStateGroup != null)
                {
                    pulseWidth      = insStateGroup.Programs[program].PulseWidthInMicroseconds.ToString();
                    stimRate        = insStateGroup.RateInHz.ToString();
                    stimAmp         = insStateGroup.Programs[program].AmplitudeInMilliamps.ToString();
                    stimElectrode   = FindStimElectrodes(insStateGroup, program);
                    electrodes      = insStateGroup?.Programs[program]?.Electrodes;
                    pulseWidthValue = insStateGroup.Programs[program].PulseWidthInMicroseconds;
                    rateValue       = insStateGroup.RateInHz;
                    ampValue        = insStateGroup.Programs[program].AmplitudeInMilliamps;
                }
            }
            catch (Exception e)
            {
                _log.Error(e);
            }
            //Set the Model with these values and return model
            if (rateValue == -1 || ampValue == -1 || pulseWidthValue == -1)
            {
                StimParameterModel StimParameterModel = new StimParameterModel(pulseWidth, stimRate, stimAmp, stimElectrode, electrodes, insStateGroup, ampLimits);
                return(StimParameterModel);
            }
            else
            {
                StimParameterModel StimParameterModel = new StimParameterModel(pulseWidth, stimRate, stimAmp, stimElectrode, electrodes, insStateGroup, ampLimits, rateValue, ampValue, pulseWidthValue);
                return(StimParameterModel);
            }
        }