diff --git a/src/GenerateHtml.cpp b/src/GenerateHtml.cpp index 232a08e..bccc862 100644 --- a/src/GenerateHtml.cpp +++ b/src/GenerateHtml.cpp @@ -1,6 +1,9 @@ +#include #include #include #include +#include +#include #include #include"common.h" @@ -11,11 +14,41 @@ struct quatalog_data_t { Json::Value catalog; }; enum struct TAG { BEGIN, END, INLINE }; +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" } +}; 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 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 enum TERM,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&); @@ -60,12 +93,10 @@ int main(const int argc, prerequisites_file >> quatalog_data.prerequisites; list_of_terms_file >> quatalog_data.list_of_terms; catalog_file >> quatalog_data.catalog; - for(const auto& course : quatalog_data.catalog.getMemberNames()) { std::cerr << course << std::endl; generate_course_page(course,quatalog_data,std::cout); } - //generate_course_page("CSCI-4260",quatalog_data,std::cout); } bool create_dir_if_not_exist(const fs::path& path) { @@ -85,6 +116,7 @@ bool create_dir_if_not_exist(const fs::path& path) { const 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]; } @@ -127,19 +159,30 @@ void generate_course_page(const std::string& course_id, "They are often recycled and used for new/experimental courses."; } + const std::regex escape_string(R"(")"); + const std::string& description_meta = std::regex_replace(description,escape_string,"""); + 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::END,"head"); - tag(os,TAG::BEGIN,"body"); + tag(os,TAG::BEGIN,R"(body class="search_plugin_added")"); + tag(os,TAG::BEGIN,R"(div id="qlog-header")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::INLINE) << R"R()R" << '\n'; + tag(os,TAG::END,"div"); tag(os,TAG::BEGIN,R"(div id="cd-flex")"); tag(os,TAG::BEGIN,R"(div id="course-info-container")"); tag(os,TAG::BEGIN,R"(h1 id="name")"); tag(os,TAG::INLINE) << course_name << '\n'; tag(os,TAG::END,"h1"); - tag(os,TAG::INLINE) << R"(

)" << course_id << "

" << '\n'; + tag(os,TAG::BEGIN,R"(h2 id="code")"); + tag(os,TAG::INLINE) << course_id << '\n'; + tag(os,TAG::END,"h2"); tag(os,TAG::BEGIN,"p"); tag(os,TAG::INLINE) << description << '\n'; tag(os,TAG::END,"p"); @@ -153,11 +196,175 @@ void generate_course_page(const std::string& course_id, generate_list(prereqs_entry["corequisites"],"Corequisites:","coreq",quatalog_data,os); generate_prereq_display(prereqs_entry["prerequisites"],quatalog_data,os); tag(os,TAG::END,"div"); + tag(os,TAG::BEGIN,R"(div id="past-container")"); + tag(os,TAG::BEGIN,R"(h2 id="past-title")"); + tag(os,TAG::INLINE) << "Past Term Data" << '\n'; + tag(os,TAG::END,"h2"); + generate_opt_container(os); + generate_years_table(terms_offered,prereqs_entry["cross_listings"],quatalog_data,os); + tag(os,TAG::END,"div"); tag(os,TAG::END,"div"); tag(os,TAG::END,"body"); tag(os,TAG::END,"html"); } +void generate_years_table(const Json::Value& terms_offered, + const Json::Value& cross_listings, + const quatalog_data_t& qlog, + std::ostream& os) { + tag(os,TAG::BEGIN,"table"); + tag(os,TAG::BEGIN,"thead"); + + tag(os,TAG::BEGIN,"tr"); + tag(os,TAG::INLINE) << "" << '\n'; + tag(os,TAG::INLINE) << R"(Spring)" << '\n'; + tag(os,TAG::INLINE) << R"(Summer)" << '\n'; + tag(os,TAG::INLINE) << R"(Fall)" << '\n'; + //tag(os,TAG::INLINE) << R"(Enrichment)" << '\n'; + tag(os,TAG::END,"tr"); + tag(os,TAG::BEGIN,"tr"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::INLINE) << R"((Session 1))" << '\n'; + tag(os,TAG::INLINE) << R"((Session 2))" << '\n'; + //tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"tr"); + + tag(os,TAG::END,"thead"); + tag(os,TAG::BEGIN,"tbody"); + + const int current_year = std::stoi(qlog.list_of_terms["current_term"].asString().substr(0,4)); + const int oldest_year = std::stoi(qlog.list_of_terms["oldest_term"].asString().substr(0,4)); + for(int year = current_year;year >= oldest_year;year--) { + generate_year_row(year,terms_offered,cross_listings,qlog,os); + } + + tag(os,TAG::END,"tbody"); + tag(os,TAG::END,"table"); +} + +void generate_year_row(const int year, + const Json::Value& terms_offered, + const Json::Value& cross_listings, + const quatalog_data_t& qlog, + std::ostream& os) { + tag(os,TAG::BEGIN,"tr"); + tag(os,TAG::INLINE) << R"()" << year << "" << '\n'; + + generate_table_cell(TERM::SPRING,is_course_offered(year,TERM::SPRING,terms_offered,cross_listings,qlog),os); + + const enum OFFERED summer1 = is_course_offered(year,TERM::SUMMER,terms_offered,cross_listings,qlog); + if(summer1 != OFFERED::NO) { + generate_table_cell(TERM::SUMMER,summer1,os); + } else { + const enum OFFERED summer2 = is_course_offered(year,TERM::SUMMER2,terms_offered,cross_listings,qlog); + const enum OFFERED summer3 = is_course_offered(year,TERM::SUMMER3,terms_offered,cross_listings,qlog); + if((summer2 == OFFERED::NO || summer2 == OFFERED::UNSCHEDULED) + && (summer3 == OFFERED::NO || summer3 == OFFERED::UNSCHEDULED)) { + generate_table_cell(TERM::SUMMER,summer1,os); + } else { + generate_table_cell(TERM::SUMMER2,summer2,os); + generate_table_cell(TERM::SUMMER3,summer3,os); + } + } + + generate_table_cell(TERM::FALL,is_course_offered(year,TERM::FALL,terms_offered,cross_listings,qlog),os); + //generate_table_cell(TERM::WINTER,is_course_offered(year,TERM::WINTER,terms_offered,cross_listings,qlog),os); + + tag(os,TAG::END,"tr"); +} + +void generate_table_cell(const enum TERM term, + const enum OFFERED is_offered, + std::ostream& os) { + tag(os,TAG::INLINE) << R"()" << '\n'; +} + +bool is_term_scheduled(const std::string& term_str, + const quatalog_data_t& qlog) { + static std::unordered_set terms; + if(terms.empty()) { + for(const auto& term : qlog.list_of_terms["all_terms"]) { + terms.insert(term.asString()); + } + } + return terms.count(term_str); +} + +enum OFFERED is_course_offered(const int year, + const enum TERM term, + const Json::Value& terms_offered, + const Json::Value& cross_listings, + const quatalog_data_t& qlog) { + const std::string& term_str = std::to_string(year) + term_to_number.at(term); + if(!is_term_scheduled(term_str,qlog)) { + return OFFERED::UNSCHEDULED; + } else if(terms_offered.isMember(term_str)) { + return OFFERED::YES; + } else { + for(const auto& cl : cross_listings) { + if(get_data(terms_offered,cl.asString())) { + return OFFERED::DIFF_CODE; + } + } + return OFFERED::NO; + } +} + +void generate_opt_container(std::ostream& os) { + tag(os,TAG::BEGIN,R"(div id="opt-container")"); + tag(os,TAG::BEGIN,R"(div id="key-panel")"); + tag(os,TAG::BEGIN,R"(div id="yes-code" class="key-code")"); + tag(os,TAG::BEGIN,R"(span class="code-icon" id="yes-code-icon")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"span"); + tag(os,TAG::INLINE) << "Offered" << '\n'; + tag(os,TAG::END,"div"); + tag(os,TAG::BEGIN,R"(div id="no-code" class="key-code")"); + tag(os,TAG::BEGIN,R"(span class="code-icon" id="no-code-icon")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"span"); + tag(os,TAG::INLINE) << "Not Offered" << '\n'; + tag(os,TAG::END,"div"); + tag(os,TAG::BEGIN,R"(div id="diff-code" class="key-code")"); + tag(os,TAG::BEGIN,R"(span class="code-icon" id="diff-code-icon")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"span"); + tag(os,TAG::INLINE) << "Offered as Cross-Listing Only" << '\n'; + tag(os,TAG::END,"div"); + tag(os,TAG::BEGIN,R"(div id="nil-code" class="key-code")"); + tag(os,TAG::BEGIN,R"(span class="code-icon" id="nil-code-icon")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"span"); + tag(os,TAG::INLINE) << "No Term Data" << '\n'; + tag(os,TAG::END,"div"); + tag(os,TAG::END,"div"); + tag(os,TAG::BEGIN,R"(div id="control-panel")"); + tag(os,TAG::BEGIN,R"(label for="simple-view-input" id="simple-view-label" class="view-option-label")"); + tag(os,TAG::BEGIN,R"(span class="view-icon" id="simple-view-icon")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"span"); + tag(os,TAG::INLINE) << "Simple View" << '\n'; + tag(os,TAG::END,"label"); + tag(os,TAG::BEGIN,R"(label for="detail-view-input" id="detail-view-label" class="view-option-label")"); + tag(os,TAG::BEGIN,R"(span class="view-icon" id="detail-view-icon")"); + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::INLINE) << R"()" << '\n'; + tag(os,TAG::END,"span"); + tag(os,TAG::INLINE) << "Detailed View" << '\n'; + tag(os,TAG::END,"label"); + tag(os,TAG::END,"div"); + tag(os,TAG::END,"div"); +} + std::string get_course_title(const std::string& course_id, const quatalog_data_t& quatalog_data) { const auto& catalog_entry = quatalog_data.catalog[course_id]; @@ -215,7 +422,6 @@ void generate_list(const Json::Value& list, } void generate_prereq_display(const Json::Value& prereqs,const quatalog_data_t& qlog,std::ostream& os) { - if(prereqs.empty()) return; tag(os,TAG::BEGIN,R"(div id="prereq-container" class="rel-info-container")"); tag(os,TAG::BEGIN,R"(div id="prereq-title" class="rel-info-title")"); tag(os,TAG::INLINE) << "Prereqs:" << '\n'; @@ -229,9 +435,12 @@ void generate_prereq_display(const Json::Value& prereqs,const quatalog_data_t& q void generate_prereq(const Json::Value& prereq, const quatalog_data_t& qlog, std::ostream& os) { - if(prereq["type"] == "course") { + if(prereq.empty()) { + tag(os,TAG::BEGIN,R"(span class="none-rect")"); + tag(os,TAG::INLINE) << "none" << '\n'; + tag(os,TAG::END,"span"); + } else if(prereq["type"] == "course") { std::string course = prereq["course"].asString(); - course[4] = '-'; generate_course_pill(course,qlog,os); os << '\n'; } else if(prereq["type"] == "or") {