private void AddControl()
        {
            DateTime beforeDay = GenerationData.CurrentDay;

            if (scheduleDay.CanAddShift()) // if all shifts not used.
            {
                scheduleDay.AddLogic();
                scheduleLine = (CoatingScheduleLine)scheduleDay.ChildrenLogic.Last(); // add a shift
            }
            else
            {
                // advance a day and remove expected inventory
                GenerationData.CurrentDay = ShiftHandler.CoatingInstance.GetNextWorkingDay(GenerationData.CurrentDay);

                schedule.AddLogic();
                scheduleDay      = (CoatingScheduleDay)schedule.ChildrenLogic.Last();
                scheduleDay.Date = GenerationData.CurrentDay;
                scheduleDay.AddLogic();
                scheduleLine = (CoatingScheduleLine)scheduleDay.ChildrenLogic.Last();
            }

            // decrement inventory
            int daysAdded = (GenerationData.CurrentDay - beforeDay).Days;

            if (daysAdded > 0)
            {
                GenerationData.DecrementInventory(daysAdded);
            }

            GenerationData.AddPressProduction();

            // reset the state for the next shift
            GenerationData.ResetForNextShift();
        }
        public void GenerateSchedule(GenerationSettings settings)
        {
            GenerationSettings = settings;
            if (GenerationData == null)
            {
                GenerationData = new GenerationData();
            }

            if (!MachineHandler.Instance.IsLoaded)
            {
                MachineHandler.Instance.Load();
            }
            if (!MachineHandler.Instance.IsLoaded)
            {
                MessageBox.Show("Could not load machine config data. Please open the machine config file.");
                if (!MachineHandler.Instance.LoadDialog())
                {
                    MessageBox.Show("Failed to load or canceled. Cannot generate schedule without machine config data. Stopping generation.");
                    return;
                }
            }

            if (StaticInventoryTracker.ProductMasterList.Count == 0)
            {
                MessageBox.Show("No master loaded. Please load master before generating schedule.");
                return;
            }

            if (MachineHandler.Instance.MachineList.Count == 0)
            {
                MessageBox.Show("No machines configured/loaded. Please load or configure the plant machines before generating schedule.");
                return;
            }
            if (!StaticFactoryValuesManager.Loaded)
            {
                StaticFactoryValuesManager.LoadValues();
                if (!StaticFactoryValuesManager.Loaded)
                {
                    MessageBox.Show("No machines configured/loaded. Please load or configure the plant machines before generating schedule.");
                    return;
                }
            }

            try
            {
                CoatingSchedule.CurrentSchedule?.ChildrenLogic.Clear();

                CoatingScheduleWindow scheduleWindow = new CoatingScheduleWindow(schedule);
                scheduleWindow.Show();
                PressScheduleWindow pressScheduleWindow = new PressScheduleWindow();
                pressScheduleWindow.Show();
                PressManager.PlateConfigurations.Clear();
                pressScheduleWindow.UpdateControls();



                // add the first shift to the schedule
                schedule.AddLogic();
                scheduleDay      = (CoatingScheduleDay)schedule.ChildrenLogic[0];
                scheduleDay.Date = GenerationSettings.StartGen;
                scheduleDay.AddLogic();
                scheduleLine = (CoatingScheduleLine)scheduleDay.ChildrenLogic[0];

                GenerationData.InitializeData(RequirementsHandler.GetMakeOrders(GenerationSettings.SalesOutlook),
                                              GenerationSettings);


                // get list of items that can be made in the coating plant
                List <ProductMasterItem> masterItemsAvailableToMake =
                    StaticInventoryTracker.ProductMasterList.Where(
                        m => m.MadeIn.ToUpper().Equals("COATING")).ToList();

                List <ProductMasterItem> unmakeableItems =
                    masterItemsAvailableToMake.Where(
                        item => MachineHandler.Instance.AllConfigurations.All(c => !c.CanMake(item))).ToList();

                if (unmakeableItems.Any())
                {
                    StringBuilder badItems = new StringBuilder();
                    badItems.AppendLine("No configuration found for " + unmakeableItems.Count + " items:");
                    foreach (var productMasterItem in unmakeableItems)
                    {
                        masterItemsAvailableToMake.Remove(productMasterItem);
                        badItems.AppendLine(productMasterItem.ToString());
                    }
                    badItems.AppendLine(
                        "Please note that these items cannot be scheduled in coating until they have configurations that output their masterID.");
                    MessageBox.Show(badItems.ToString());
                }

                // While we have not reached the end of the schedule
                while (GenerationData.CurrentDay <= GenerationSettings.EndGen)
                {
                    int  itemIndex    = 0;
                    bool wasScheduled = false;
                    bool skipShift    = false;

                    // attempt to schedule the highest priority item until the line is full. Also as long as we have not tried every item on this shift
                    while (GenerationData.ScheduledItem.Any(s => !s.Value) && !LineIsFull() && !skipShift && GenerationData.CurrentDay <= GenerationSettings.EndGen)
                    {
                        wasScheduled = false;
                        // try each coating line
                        for (var index = 0; GenerationData.CurrentDay <= GenerationSettings.EndGen && index < StaticFactoryValuesManager.CoatingLines.Count; index++)
                        {
                            var coatingLine = StaticFactoryValuesManager.CoatingLines[index];
                            // Get item with highest priority
                            GenerationData.CreatePriorityList(masterItemsAvailableToMake, coatingLine);

                            if (itemIndex >= GenerationData.PriorityList.Count)
                            {
                                skipShift = true;
                                break;
                            }

                            // Use the next item in the prereq. list as the most favorable.
                            PriorityItem currentItem = GenerationData.GetPriorityItem(itemIndex);

                            if (currentItem.Item.MadeIn.ToUpper().Equals("COATING"))
                            {
                                wasScheduled = ScheduleCoating(currentItem.Item, coatingLine);
                            }
                            else if (currentItem.Item.MadeIn.ToUpper().Equals("PRESS"))
                            {
                                // make the target supply, unless 0, then use 1 and fill.
                                var unitsToMake = currentItem.Item.TargetSupply > 0 ? currentItem.Item.TargetSupply : 1;
                                // should have a sale if scheduling here.
                                var sale =
                                    GenerationData.SalesList.FirstOrDefault(s => s.MasterID == currentItem.Item.MasterID);
                                if (sale != null)
                                {
                                    unitsToMake = sale.PiecesToMake * currentItem.Item.PiecesPerUnit;
                                }
                                SchedulePress(currentItem.Item, unitsToMake);
                                wasScheduled = true; // don't move on due to a press scheduling.
                            }
                            else
                            {
                                // error
                                MessageBox.Show(
                                    "ERROR: Attempted to schedule item that cannot be made in coating or press. Could not make item " + currentItem.Item);
                            }
                            // move to next item

                            // Check if all the lines have been scheduled or if we have tried all the items and none can be scheduled, move on
                            if (GenerationData.ScheduledItem.All(s => s.Value) ||
                                itemIndex >= GenerationData.PriorityList.Count)
                            {
                                AddControl();
                            }
                        }
                        if (!wasScheduled)
                        {
                            // move to the next item, as the highest priority item can't be made currently.
                            itemIndex++;
                        }
                    }

                    // if all items have been run, reset the counter. If there have been no schedulings, then also add a shift
                    if (skipShift || LineIsFull())
                    {
                        AddControl();
                    }
                }
                pressScheduleWindow.UpdateControls();

                while (_errors.Count > 0)
                {
                    MessageBox.Show(_errors.Dequeue());
                }

                MessageBox.Show("Schedule done generating");
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
        }