/* Called when the submit button is clicked. Initiliazes some data and starts the schedule
  *  generation process.
  */
 private void btnSubmit_Click(object sender, RoutedEventArgs e)
 {
     //Clear all of the generated tabs
     tabBase.SelectedIndex = 0;
     for (int tabIter = (tabBase.Items.Count-1); tabIter > 1; tabIter--)
     {
         tabBase.Items.RemoveAt(tabIter);
     }
     totalClassCount = lstFinalClasses.Items.Count;
     currentClassRunning = 0;
     possibleSections = new List<ClassSection>();              //All of the possible courses
     confirmedSections = new List<List<ClassSection>>();
     progress.Value = 0;                                 //Reset the progress bar
     tabCount = 0;                                       //Reset the tab numberings.
     secondsRemaining = 0;                               //Reset timeleft
     sectionsInGrid = new Dictionary<Grid, List<ClassSection>>();  //Reset the grid dictionary
     //Start finding bitstrings in the background
     BackgroundWorker bitstringworker = new BackgroundWorker();
     bitstringworker.WorkerSupportsCancellation = false;
     bitstringworker.WorkerReportsProgress = true;
     bitstringworker.DoWork += new DoWorkEventHandler(generateAllBitStrings);
     bitstringworker.ProgressChanged += new ProgressChangedEventHandler(reportProgress);
     //Count how many courses there are so we know how many bitstrings to generate
     int totalCourses = 0;
     const int MAXCOURSES = 23;
     Random randomGen = new Random();
     foreach (DepartmentClass finalClass in lstFinalClasses.Items)
     {
         //Random number of courses to pick from:
         // Take max courses. Remove the courses we have already. Make sure one section is leftover for the last class.
         int randomNumberOfSectionsFromThisClass = 0;
         if (finalClass != lstFinalClasses.Items.Last())
         {
             randomNumberOfSectionsFromThisClass = (int)Math.Round(randomGen.NextDouble() * (MAXCOURSES - totalCourses - 1));
         }
         else
         {
             randomNumberOfSectionsFromThisClass = MAXCOURSES - totalCourses;
         }
         foreach (ClassSection section in finalClass.sections)
         {
             //If course is not in exlusions
             if (!section.excluded)
             {
                 //temporary crappy code to fill in the parent class information for sections
                 section.parentClass = finalClass.ToString();
                 //end temporary crappy code
             }
         }
         List<ClassSection> possible = pickSections(finalClass, randomNumberOfSectionsFromThisClass, randomGen);
         MyStopwatch timeout = new MyStopwatch();
         timeout.start();
         while (!allLinksPresent(possible) && !ignoreLinks)
         {
             if (!limitRandom)
             {
                 YesNoPopup popupLinkRemoved = new YesNoPopup("You have excluded a linked section in " + possible[0].parentClass + ".\nWould you like to exclude the sections that require it?");
                 popupLinkRemoved.show();
                 popupLinkRemoved.onYes =
                     delegate
                     {
                         removeMissingLinks(possible);
                         btnSubmit_Click(sender, e);
                     };
                 popupLinkRemoved.onNo =
                     delegate
                     {
                         ignoreLinks = true;
                         btnSubmit_Click(sender, e);
                     };
                 return;
             }
             possible = pickSections(finalClass, randomNumberOfSectionsFromThisClass);
             // After 2 seconds, just try submitting again in case there's a situation where
             // there's not enough random sections to pick all the links. IE: 3 linked, but only allowed 2
             if (timeout.stop() > 2000)
             {
                 btnSubmit_Click(sender, e);
                 return;
             }
             //Slow down the repetitions - gives a little more randomness.
             Thread.Sleep(100);
         }
         totalCourses += possible.Count;
         foreach (ClassSection section in possible)
         {
             possibleSections.Add(section);
         }
     }
     if (totalCourses < 1)
     {
         InfoPopup popupNoCourses = new InfoPopup("There are 0 sections included!");
         popupNoCourses.show();
     }
     //Start counting down.
     counterDown = new BackgroundWorker();
     counterDown.WorkerSupportsCancellation = true;
     counterDown.WorkerReportsProgress = false;
     counterDown.DoWork += new DoWorkEventHandler(decreaseTimeRemaining);
     counterDown.RunWorkerAsync();
     //Start generating bitstrings in background
     bitstringworker.RunWorkerAsync("" + totalCourses);
     //Disable the submit button while we're generating.
     btnSubmit.IsEnabled = false;
     //Reset link ignore
     ignoreLinks = false;
 }
        /* Called when the bitstring worker reports progress.
         *  Should update the GUI to reflect schedules that work
         */
        private void reportProgress(object sender, ProgressChangedEventArgs e)
        {
            if (e.ProgressPercentage == 100)
            {
                btnSubmit.IsEnabled = true;    //Reenable the submit button now that we're (mostly) done.
                tabBase.Items.Add(tabResults);
                lblResultCount.Content = "You have " + confirmedSections.Count + " results!";
                lblResultCount.FontSize = 17.0;
                tabResults.Visibility = System.Windows.Visibility.Visible;
                cResultStart.Items.Clear();
                for (int i = 0; i < confirmedSections.Count; i++)
                {
                    cResultStart.Items.Add(i + 1);
                }
                cResultStart.SelectedIndex = 0;

                if (confirmedSections.Count < 1)
                {
                    InfoPopup popupNoResults = new InfoPopup("No results!");
                    popupNoResults.show();
                    return;
                }
            }

            if (e.UserState == null) return; //Only draw results when the view button is clicked

            tabBase.SelectedIndex = 2;
            for (int tabIter = (tabBase.Items.Count - 1); tabIter > 2; tabIter--)
            {
                tabBase.Items.RemoveAt(tabIter);
            }

            Tuple<int, int> range = (Tuple<int, int>)e.UserState;
            if (range.Item2 > confirmedSections.Count) range = new Tuple<int, int>(range.Item1, confirmedSections.Count);
            tabCount = range.Item1;

            List<List<ClassSection>> reportingList = new List<List<ClassSection>>();
            lock (confirmedSections)
            {
                for (int x = range.Item1; x < range.Item2; x++)
                {
                    List<ClassSection> classGroup = confirmedSections[x];
                    reportingList.Add(classGroup);
                }
            }
            if (reportingList.Count < 1) return;  //If there are no elements, draw nothing.
            foreach (List<ClassSection> classGroup in reportingList)
            {
                //Make a grid and tab
                tabCount++;
                TabItem tab = new TabItem();
                tab.Header = ""+tabCount;          //The tab name
                Grid grid = new Grid();
                //Draw horizontal lines
                for (int i = 0; i < 80; i++)
                {
                    Line gridLines = new Line();
                    gridLines.X1 = 40;
                    gridLines.X2 = tabBase.ActualWidth - 89;
                    gridLines.Y1 = 60 + 6.7*i;
                    gridLines.Y2 = 60 + 6.7*i;
                    if (i % 3 == 0) gridLines.Stroke = new SolidColorBrush(Colors.DarkGray);
                    else gridLines.Stroke = new SolidColorBrush(Colors.Transparent);
                    gridLines.StrokeThickness = 0.5f;
                    grid.Children.Add(gridLines);
                }
                //Draw vertical lines
                for (int i = 0; i < 6; i++)
                {
                    Line gridLines = new Line();
                    gridLines.X1 = 40 + ((tabBase.ActualWidth / 6) + .80f) * i;
                    gridLines.X2 = 40 + ((tabBase.ActualWidth / 6) + .80f) * i;
                    gridLines.Y1 = 60;
                    gridLines.Y2 = 583;
                    gridLines.Stroke = new SolidColorBrush(Colors.DarkGray);
                    gridLines.StrokeThickness = 0.5f;
                    grid.Children.Add(gridLines);
                }

                //Draw each course on the grid
                tbaCount = 0;
                List<ClassSection> coursesInGroup = new List<ClassSection>();
                foreach (ClassSection course in classGroup)
                {
                    drawSchedule(grid, course.startTime, course.endTime, course.days, course.parentClass + "\n" + course.type, course.availability);
                    coursesInGroup.Add(course);
                }

                tab.Content = grid;
                tabBase.Items.Add(tab);
                sectionsInGrid.Add(grid, coursesInGroup);
            }
        }