private static void SaveAndShowMessage(Common.Model.API.Application app, string message)
        {
            app.SaveModifications();

            // Make sure that the message is on top of all other windows.
            MessageBox.Show(new Window {
                Topmost = true
            }, message);
        }
        private static void CreateVerificationPlan(Common.Model.API.Application app, ExternalPlanSetup verifiedPlan, StructureSet verificationStructures)
        {
            var course = Helpers.GetCourse(verifiedPlan.Course.Patient, VerificationCourseId);

            Trace.WriteLine("\nCreating verification plans...\n");

            // Create an individual verification plan for each field.
            foreach (var beam in verifiedPlan.Beams)
            {
                PlanGeneration.CreateVerificationPlan(course, new List <Beam> {
                    beam
                }, verifiedPlan, verificationStructures, beam.Id, calculateDose: false);
            }

            // Create a verification plan that contains all fields.
            PlanGeneration.CreateVerificationPlan(course, verifiedPlan.Beams, verifiedPlan, verificationStructures, "All fields", calculateDose: true);
        }
        private static void Execute(Common.Model.API.Application app, string patientId, string planId)
        {
            var patient = app.OpenPatientById(patientId);

            patient.BeginModifications();

            if (!Helpers.CheckStructures(patient))
            {
                return;
            }

            // The demo patient has structures in a set structure called "Prostate".
            var structures = patient.StructureSets.Single(st => st.Id == "Prostate");

            var course = Helpers.GetCourse(patient, CourseId);

            // If old courses exists, remove them. Remove also the structures generated by the script (in the previous run).
            Helpers.RemoveOldPlan(course, planId);
            Helpers.RemoveStructures(structures, new List <string> {
                "PTV", PlanGeneration.ExpandedCTVId, PlanGeneration.PTVSubOARSId
            });

            // Launch the prescription dialog.
            var prescriptionDialog = new PrescriptionDialog(patientId, DefaultDosePerFraction, DefaultNumberOfFractions, DefaultMarginForPTVInMM, structures.Structures)
            {
                Width  = 300,
                Height = 350
            };
            double?dosePerFraction   = null;
            int?   numberOfFractions = null;
            double?marginForPTV      = null;
            string ctvId             = string.Empty;

            prescriptionDialog.Closed += (s, e) =>
            {
                dosePerFraction   = prescriptionDialog.DosePerFraction;
                numberOfFractions = prescriptionDialog.NumberOfFractions;
                marginForPTV      = prescriptionDialog.PTVMargin;
                ctvId             = prescriptionDialog.SelectedStructure;
            };
            prescriptionDialog.ShowDialog();

            // If the user inputs are valid, proceed to plan creation.
            if (dosePerFraction.HasValue && numberOfFractions.HasValue && marginForPTV.HasValue && ctvId != string.Empty)
            {
                // Create new plan.
                var plan = course.AddExternalPlanSetup(structures);
                plan.Id = planId;

                // Re-direct output from trace to console.
                Trace.Listeners.Add(new ConsoleTraceListener());

                // Beam geometry generation.
                PlanGeneration.GenerateBeamGeometry(plan, dosePerFraction != null ? dosePerFraction.Value : 0,
                                                    numberOfFractions != null ? numberOfFractions.Value : 0,
                                                    marginForPTV != null ? marginForPTV.Value : 0,
                                                    ctvId);

                // DVH estimation.
                var structureMatches = PlanGeneration.GetStructureMatches(plan);
                structureMatches.Remove(PlanGeneration.ExpandedCTVId);
                structureMatches.Add(PlanGeneration.PTVSubOARSId, new ModelStructure("PTV", ModelStructureType.Target));
                PlanGeneration.CalculateDVHEstimates(plan, structureMatches);

                // Add normal tissue objectives.
                PlanGeneration.AddNTO(plan);

                // Save beam geometry and DVH estimation results.
                var message = "Beam geometry generation and DVH estimation completed.";
                SaveAndShowMessage(app, message);

                // Optimization.
                PlanGeneration.Optimize(plan);

                // Save optimization results.
                message = "Optimization completed.";
                SaveAndShowMessage(app, message);

                // Caluclate dose.
                PlanGeneration.CalculateDose(plan);
                Trace.WriteLine("\nPlan successfully generated.\n");

                // Normalize plan.
                PlanGeneration.Normalize(plan, structureMatches);
                app.SaveModifications();

                // Report DVHs.
                var          outputPath             = @"C:\Temp\dvh.svg";
                const string browser                = @"C:\Program Files (x86)\Mozilla Firefox\firefox.exe";
                var          structuresForReporting = plan.StructureSet.Structures.Where(st => structureMatches.ContainsKey(st.Id));
                const int    dvhWidth               = 512;
                const int    dvhHeight              = 256;
                SVGFromDVH.SaveSVGFromStructures(outputPath, plan, structuresForReporting, dvhWidth, dvhHeight);

                outputPath = @"C:\Temp";
                var reportLocation = PlanQualityReporter.CreateReport(plan, structureMatches, outputPath);

                Trace.WriteLine("\nReport successfully generated.\n");

                // Display the generated report in web browser.
                Process.Start(browser, reportLocation);
                Thread.Sleep(1000);

                // Ask user if we want to proceed to plan verification.
                const string title = "Quality assurance";
                message = "Proceed to creation of verification plan?";
                var res = MessageBox.Show(new Window {
                    Topmost = true
                }, message, title, MessageBoxButton.YesNo, MessageBoxImage.Question);

                if (res == MessageBoxResult.Yes)
                {
                    // Create verification plan.
                    Trace.Write("\nRetrieving CT image of the QA device...\n");
                    var qaStructures = patient.StructureSets.Where(set => set.Id == VerificationPatientImageId).ToList();

                    // If we have already loaded the structures for verification, do not load them again. Currently, ESAPI doesn't offer methods to remove them... (has to be done by hand in Eclipse).
                    var verificationStructures = qaStructures.Any() ? qaStructures.First() : plan.Course.Patient.CopyImageFromOtherPatient(VerificationPatientId, VerificationPatientStudyId, VerificationPatientImageId);
                    CreateVerificationPlan(app, plan, verificationStructures);
                    app.SaveModifications();

                    Trace.WriteLine("\nVerification plans succesfully created.\n");
                }

                Trace.WriteLine("\nScript successfully executed.\n");
            }
            else
            {
                const string message = "Please provide a valid prescription.";
                const string title   = "Invalid prescription";
                MessageBox.Show(message, title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }