public IEnumerable <UTCourse> FetchItems()
        {
            IItemFetcher <UTDepartment>           depFetcher        = new UTArtsciDepartmentFetcher();
            List <UTCourse>                       coursesDetail     = new List <UTCourse>();
            UTEngHssCsChecker                     checker           = new UTEngHssCsChecker();
            UTArtsciCourseDetailPageNumberFetcher pagenumberFetcher = new UTArtsciCourseDetailPageNumberFetcher(
                String.Format(WebUrlConstants.ArtsciCourseDetailNew, 0));
            int    numPages = pagenumberFetcher.FetchItems().First();
            object _sync    = new object();

            Parallel.For(0, numPages, new ParallelOptions()
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount * 4
            }, delegate(int page)
                         //for (int page = 0; page < numPages; page++)
            {
                UTArtsciCourseDetailFetcherNew fetcher = new UTArtsciCourseDetailFetcherNew(
                    String.Format(WebUrlConstants.ArtsciCourseDetailNew, page));
                IEnumerable <UTCourse> _courses = fetcher.FetchItems();
                lock (_sync)
                {
                    coursesDetail.AddRange(_courses);
                }
            }
                         );

            string          artsciUrl = WebUrlConstants.ArtsciTimetableNew;
            List <UTCourse> courses   = new List <UTCourse>();

            //Parallel.For((int)'A', (int)'Z' + 1, new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }, delegate (int code)
            for (char code = 'A'; code <= 'Z'; code++)
            {
                // Memory issue from the server when searching for only one character.
                for (char code2 = 'A'; code2 <= 'Z'; code2++)
                {
                    char codeChar = (char)code;
                    IItemFetcher <UTCourse> courseInfoFetcherNew = new UTArtsciCourseInfoFetcherNew2(artsciUrl + codeChar + code2);
                    IEnumerable <UTCourse>  _courses             = courseInfoFetcherNew.FetchItems();
                    lock (_sync)
                    {
                        courses.AddRange(_courses);
                    }
                }
            }
            //);

            // Add hss/cs/department info
            //foreach (UTCourse course in courses)
            Parallel.ForEach <UTCourse>(courses, new ParallelOptions()
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            }, delegate(UTCourse course)
            {
                course.Faculty = "Artsci";

                // Check cs/hss requirement for engineering students
                if (checker.CheckHss(course.Code + course.SemesterPrefix))
                {
                    course.AddCategory("hss");
                }
                if (checker.CheckArtsciCs(course.Code + course.SemesterPrefix))
                {
                    course.AddCategory("cs");
                }
            });
            //}

            // Merge course info and course detail
            IEnumerable <UTCourse> coursesTotal = courses.GroupJoin(coursesDetail,
                                                                    (x => x.Abbr),
                                                                    (x => x.Abbr),
                                                                    ((x, y) => this.CombineInfoDetail(x, y.FirstOrDefault())),
                                                                    new UTCourseAbbrComparer());

            // Add to unique dictionary
            foreach (UTCourse course in coursesTotal)
            {
                if (!CoursesCollection.ContainsKey(course.Abbr))
                {
                    CoursesCollection.Add(course.Abbr, course);
                }
                else
                {
                    UTCourse existingCourse = CoursesCollection[course.Abbr];
                    foreach (CourseSection section in course.Sections)
                    {
                        bool found = false;
                        foreach (CourseSection section2 in existingCourse.Sections)
                        {
                            if (section.Name == section2.Name)
                            {
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            existingCourse.Sections.Add(section);
                        }
                    }
                }
            }

            // Match the prerequisites to postrequisites
            foreach (UTCourse course in CoursesCollection.Values)
            {
                if (!String.IsNullOrEmpty(course.Prerequisites))
                {
                    foreach (Match match in CodeRegex.Matches(course.Prerequisites))
                    {
                        string abbr = match.Groups["code"].Value;
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "H1F");
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "H1S");
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "Y1Y");
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "H1Y");
                    }
                }
            }
            return(CoursesCollection.Values);
        }
        public IEnumerable <UTCourse> FetchItems()
        {
            IItemFetcher <UTDepartment> depFetcher = new UTArtsciDepartmentFetcher();

            List <UTCourse>     coursesDetail         = new List <UTCourse>();
            List <UTDepartment> deps                  = new List <UTDepartment>(depFetcher.FetchItems());
            UTEngHssCsChecker   checker               = new UTEngHssCsChecker();
            Dictionary <string, UTDepartment> depDict = new Dictionary <string, UTDepartment>();

            // Parallel threads for fetching each department
            Parallel.ForEach <UTDepartment>(depFetcher.FetchItems(), new ParallelOptions()
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            }, delegate(UTDepartment dep)
                                            //foreach (UTDepartment dep in depFetcher.FetchItems())
            {
                IItemFetcher <UTCourse> courseDetailFetcher = new UTArtsciCourseDetailFetcher(dep.DetailUrl);
                coursesDetail.AddRange(courseDetailFetcher.FetchItems());
                if (!depDict.ContainsKey(dep.Abbr))
                {
                    depDict.Add(dep.Abbr, dep);
                }
            });
            //}
            string          artsciUrl = WebUrlConstants.ArtsciTimetableNew;
            List <UTCourse> courses   = new List <UTCourse>();
            object          _sync     = new object();

            Parallel.For((int)'A', (int)'Z' + 1, new ParallelOptions()
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            }, delegate(int code)
                         //for (char c = 'A'; c < 'Z'; c++)
            {
                char codeChar = (char)code;
                IItemFetcher <UTCourse> courseInfoFetcherNew = new UTArtsciCourseInfoFetcherNew2(artsciUrl + codeChar);
                IEnumerable <UTCourse> _courses = courseInfoFetcherNew.FetchItems();
                lock (_sync)
                {
                    courses.AddRange(_courses);
                }
            }
                         );

            // Add hss/cs/department info
            //foreach (UTCourse course in courses)
            Parallel.ForEach <UTCourse>(courses, new ParallelOptions()
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            }, delegate(UTCourse course)
            {
                // Add department info
                if (depDict.ContainsKey(course.Code.Substring(0, 3)))
                {
                    course.Department = depDict[course.Code.Substring(0, 3)].Name;
                }
                course.Faculty = "Artsci";

                // Check cs/hss requirement for engineering students
                if (checker.CheckHss(course.Code + course.SemesterPrefix))
                {
                    course.AddCategory("hss");
                }
                if (checker.CheckArtsciCs(course.Code + course.SemesterPrefix))
                {
                    course.AddCategory("cs");
                }
            });
            //}

            // Merge course info and course detail
            IEnumerable <UTCourse> coursesTotal = courses.GroupJoin(coursesDetail,
                                                                    (x => x.Abbr),
                                                                    (x => x.Abbr),
                                                                    ((x, y) => this.CombineInfoDetail(x, y.FirstOrDefault())),
                                                                    new UTCourseAbbrComparer());

            // Add to unique dictionary
            foreach (UTCourse course in coursesTotal)
            {
                if (!CoursesCollection.ContainsKey(course.Abbr))
                {
                    CoursesCollection.Add(course.Abbr, course);
                }
                else
                {
                    UTCourse existingCourse = CoursesCollection[course.Abbr];
                    foreach (CourseSection section in course.Sections)
                    {
                        bool found = false;
                        foreach (CourseSection section2 in existingCourse.Sections)
                        {
                            if (section.Name == section2.Name)
                            {
                                found = true;
                                break;
                            }
                        }
                        if (!found)
                        {
                            existingCourse.Sections.Add(section);
                        }
                    }
                }
            }

            // Match the prerequisites to postrequisites
            foreach (UTCourse course in CoursesCollection.Values)
            {
                if (!String.IsNullOrEmpty(course.Prerequisites))
                {
                    foreach (Match match in CodeRegex.Matches(course.Prerequisites))
                    {
                        string abbr = match.Groups["code"].Value;
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "H1F");
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "H1S");
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "Y1Y");
                        TryMatchPreq(this.CoursesCollection, course.Abbr, abbr, "H1Y");
                    }
                }
            }
            return(CoursesCollection.Values);
        }