#include #include #include #include #include #include #include namespace fs = std::filesystem; struct quatalog_data_t { Json::Value terms_offered; Json::Value prerequisites; Json::Value list_of_terms; Json::Value catalog; Json::Value searchable_catalog; }; enum struct TAG { BEGIN, END, INLINE, COMPLEX_BEGIN }; enum struct TERM { SPRING, SUMMER, SUMMER2, SUMMER3, FALL, WINTER }; enum struct OFFERED { YES, NO, DIFF_CODE, UNSCHEDULED }; const std::unordered_map offered_to_string { { OFFERED::YES,"offered" }, { OFFERED::NO,"not-offered" }, { OFFERED::DIFF_CODE,"offered-diff-code" }, { OFFERED::UNSCHEDULED,"unscheduled" } }; const std::unordered_map term_to_string { { TERM::SPRING,"spring" }, { TERM::SUMMER,"summer" }, { TERM::SUMMER2,"summer2" }, { TERM::SUMMER3,"summer3" }, { TERM::FALL,"fall" }, { TERM::WINTER,"winter" } }; const std::unordered_map term_to_number { { TERM::SPRING,"01" }, { TERM::SUMMER,"05" }, { TERM::SUMMER2,"0502" }, { TERM::SUMMER3,"0503" }, { TERM::FALL,"09" }, { TERM::WINTER,"12" } }; std::unordered_set get_all_courses(const quatalog_data_t&); std::string fix_course_ids(std::string); bool create_dir_if_not_exist(const fs::path&); const Json::Value& get_data(const Json::Value&,std::string); void generate_course_page(const std::string&,const quatalog_data_t&,std::ostream&); void get_prerequisites(const quatalog_data_t&,std::string); void generate_opt_container(std::ostream&); std::string generate_credit_string(const Json::Value& credits); std::string get_course_title(const std::string&,const quatalog_data_t&); void generate_years_table(const Json::Value&,const Json::Value&,const quatalog_data_t&,std::ostream&); void generate_year_row(const int,const Json::Value&,const Json::Value&,const quatalog_data_t&,std::ostream&); bool is_term_scheduled(const std::string&,const quatalog_data_t&); enum OFFERED is_course_offered(const int,const enum TERM,const Json::Value&,const Json::Value&,const quatalog_data_t&); void generate_table_cell(const int,const enum TERM,const Json::Value&,const enum OFFERED,std::ostream&); void generate_attributes(const Json::Value&,std::ostream&); void generate_list(const Json::Value&,const std::string&,const std::string&,const quatalog_data_t&,std::ostream&); void generate_prereq_display(const Json::Value&,const quatalog_data_t&,std::ostream&); void generate_course_pill(std::string,const quatalog_data_t&,std::ostream&); void generate_prereq(const Json::Value&,const quatalog_data_t&,std::ostream&); void generate_or_prereq(const Json::Value&,const quatalog_data_t&,std::ostream&); void generate_and_prereq(const Json::Value&,const quatalog_data_t&,std::ostream&); std::ostream& indent(std::ostream&,const int); std::ostream& tag(std::ostream&,enum TAG,const std::string& = ""); int main(const int argc, const char** argv) { if(argc != 6) { std::cerr << "Bad number of arguments (" << argc << ")" << std::endl; std::cerr << "Usage: " << argv[0] << " " << " " << " " << " " << " " << std::endl; return EXIT_FAILURE; } const auto& terms_offered_filename = std::string(argv[1]); const auto& prerequisites_filename = std::string(argv[2]); const auto& list_of_terms_filename = std::string(argv[3]); const auto& catalog_filename = std::string(argv[4]); const auto& out_dir_path = fs::path(argv[5]); if(!create_dir_if_not_exist(out_dir_path)) { std::cerr << "What" << std::endl; return EXIT_FAILURE; } std::fstream terms_offered_file{terms_offered_filename,std::ios::in}; std::fstream prerequisites_file{prerequisites_filename,std::ios::in}; std::fstream list_of_terms_file{list_of_terms_filename,std::ios::in}; std::fstream catalog_file{catalog_filename,std::ios::in}; quatalog_data_t quatalog_data; terms_offered_file >> quatalog_data.terms_offered; prerequisites_file >> quatalog_data.prerequisites; list_of_terms_file >> quatalog_data.list_of_terms; catalog_file >> quatalog_data.catalog; auto courses = get_all_courses(quatalog_data); for(const auto& course : courses) { const auto& html_path = out_dir_path / (course + ".html"); auto file = std::ofstream(html_path); generate_course_page(course,quatalog_data,file); } } std::unordered_set get_all_courses(const quatalog_data_t& qlog) { std::unordered_set output; for(const std::string& course : qlog.catalog.getMemberNames()) { if(course.length() != 9) continue; output.insert(fix_course_ids(course)); } for(const std::string& course : qlog.terms_offered.getMemberNames()) { output.insert(fix_course_ids(course)); } return output; } std::string fix_course_ids(std::string course) { course[4] = '-'; if(course.substr(0,3) == "STS") { course[3] = 'O'; } return course; } bool create_dir_if_not_exist(const fs::path& path) { if(fs::exists(path)) { if(!fs::is_directory(path)) { std::cerr << "out_directory argument " << path << "is not a directory" << std::endl; return false; } return true; } return fs::create_directory(path); } Json::Value get_data(const Json::Value& data, std::string course_id) { course_id[4] = '-'; if(course_id.substr(0,3) != "STS") { return data[course_id]; } const auto& stso = data[course_id]; course_id[3] = 'S'; const auto& stss = data[course_id]; course_id[3] = 'H'; const auto& stsh = data[course_id]; Json::Value out; for(const auto& key : stso.getMemberNames()) { out[key] = stso[key]; } for(const auto& key : stss.getMemberNames()) { out[key] = stss[key]; } for(const auto& key : stsh.getMemberNames()) { out[key] = stsh[key]; } return out; } void generate_course_page(const std::string& course_id, const quatalog_data_t& quatalog_data, std::ostream& os) { std::cerr << "Generating course page for " << course_id << "..." << std::endl; std::string course_name = get_course_title(course_id,quatalog_data); std::string description; const auto& catalog_entry = quatalog_data.catalog[course_id]; const auto& prereqs_entry = get_data(quatalog_data.prerequisites,course_id); const auto& terms_offered = get_data(quatalog_data.terms_offered,course_id); const auto& latest_term = terms_offered["latest_term"].asString(); const auto& credits = terms_offered[latest_term]["credits"]; const auto& credit_string = generate_credit_string(credits); if(catalog_entry) { description = catalog_entry["description"].asString(); } else { description = "This course is not in the most recent catalog. " "It may have been discontinued, had its course " "code changed, or just not be in the catalog for " "some other reason."; } const auto& mid_digits = course_id.substr(6,2); if(mid_digits == "96" || mid_digits == "97") { course_name = "Topics in " + course_id.substr(0,4); description = "Course codes between X960 and X979 are for topics courses. " "They are often recycled and used for new/experimental courses."; } quatalog_data.searchable_catalog[] const std::regex escape_string(R"(")"); const std::string& description_meta = std::regex_replace(description,escape_string,"""); tag(os,TAG::INLINE) << "" << '\n'; tag(os,TAG::BEGIN,"html"); tag(os,TAG::BEGIN,"head"); tag(os,TAG::BEGIN,"title"); tag(os,TAG::INLINE) << course_id << " - " << course_name << '\n'; tag(os,TAG::END,"title"); tag(os,TAG::INLINE) << R"()" << '\n'; tag(os,TAG::INLINE) << R"()" << '\n'; tag(os,TAG::INLINE) << R"()" << '\n'; tag(os,TAG::INLINE) << R"()" << '\n'; tag(os,TAG::INLINE) << R"(