#include "common.h" #include "cache.h" #include "debug.h" #include #include #include void htmlencode(std::string& data) { std::string tmp; tmp.reserve(data.size() + 20); for (size_t i = 0; i != data.size(); i++) { switch (data[i]) { case '&': tmp += "&"; break; case '\"': tmp += """; break; case '\'': tmp += "'"; break; case '<': tmp += "<"; break; case '>': tmp += ">"; break; default: tmp += data[i]; break; } } data.swap(tmp); } constexpr static std::string string_mangle(const std::string& str) { std::string tmp; tmp.reserve(str.size()); for (size_t i = 0; i != str.size(); i++) { if (str[i] == ' ') continue; if (std::isupper(str[i])) tmp.push_back(std::tolower(str[i])); else tmp.push_back(str[i]); } return tmp; } void show_histogram(const pCaches& cc, std::string Cache::*ptr, const std::string& caption, bool html, bool sort_by_val) { if (cc.empty()) return; std::map histogram; for (auto el : cc) histogram[el->*ptr]++; show_histogram(histogram, caption, html, sort_by_val); } void show_histogram(const Caches& cc, std::string Cache::*ptr, const std::string& caption, bool html, bool sort_by_val) { if (cc.empty()) return; std::map histogram; for (const auto& el : cc) histogram[el.*ptr]++; show_histogram(histogram, caption, html, sort_by_val); } // void show_histogram(const pPowertrails& tt, const std::string& caption, bool html, bool sort_by_val) { // if (tt.empty()) return; // // std::map histogram; // // for (auto el : tt) { // std::string link = "number) + "\">" + el.second->name + ""; // histogram[link] = 100 * el.second->found / el.second->caches.size(); // } // // show_histogram(histogram, caption, html, sort_by_val); // } void show_histogram(const std::map& data, const std::string& caption, bool html, bool sort_by_val) { if (data.empty()) return; int HIST_MAX = 20; std::vector> pairs; if (!sort_by_val) HIST_MAX = 1000; std::copy(data.begin(), data.end(), std::back_inserter(pairs)); if (sort_by_val) sort(pairs.begin(), pairs.end(), [&](const std::pair& a, const std::pair& b) { return a.second > b.second; }); else sort(pairs.begin(), pairs.end(), [&](const std::pair& a, const std::pair& b) { return a.first < b.first; }); if (html) { int max; if (sort_by_val) max = pairs[0].second; else max = std::max_element(pairs.begin(), pairs.end(), [&](const std::pair& a, const std::pair& b) { return a.second < b.second; })->second; int i = 0; std::cout << "

" << caption << "

\n"; std::cout << "
\n"; for (auto own : pairs) { if (!own.first.starts_with("" << own.first << ": " << own.second << "
\n"; else if (i == HIST_MAX) { std::cout << "\n"; std::cout << "
\nSee more\n

\n"; std::cout << own.first << " (" << own.second << ")
"; } if (i > HIST_MAX) std::cout << own.first << " (" << own.second << ")
"; i++; } if (i <= HIST_MAX) std::cout << "\n"; else std::cout << "

\n"; } else { std::cout << caption << '\n'; for (auto own : pairs) std::cout << own.first << ": " << own.second << '\n'; } } void show_nested_histogram(const pCaches& fcc, std::string Cache::*ptr, std::string Cache::*ptr2, const std::string& caption, bool html, bool sort_by_val) { if (fcc.empty()) return; std::map histogram; std::vector> pairs; for (auto el : fcc) histogram[el->*ptr]++; std::copy(histogram.begin(), histogram.end(), std::back_inserter(pairs)); if (sort_by_val) sort(pairs.begin(), pairs.end(), [&](const std::pair& a, const std::pair& b) { return a.second > b.second; }); else sort(pairs.begin(), pairs.end(), [&](const std::pair& a, const std::pair& b) { return a.first < b.first; }); if (html) { int HIST_MAX = 20; int max; if (sort_by_val) max = pairs[0].second; else max = std::max_element(pairs.begin(), pairs.end(), [&](const std::pair& a, const std::pair& b) { return a.second < b.second; })->second; int i = 0; std::cout << "

" << caption << "

\n"; std::cout << "
\n"; for (auto own : pairs) { htmlencode(own.first); if (own.first.empty()) own.first = "[unknown]"; if (i < HIST_MAX) { std::map subhistogram; for (auto el : fcc) if (el->*ptr == own.first && !(el->*ptr2).empty()) //TODO problem with [unknown] subhistogram[el->*ptr2]++; if (!subhistogram.empty()) { std::vector> subpairs; std::cout << "
" << own.first << ": " << own.second << "\n"; std::copy(subhistogram.begin(), subhistogram.end(), std::back_inserter(subpairs)); if (sort_by_val) sort(subpairs.begin(), subpairs.end(), [&](const std::pair& a, const std::pair& b) { return a.second > b.second; }); else sort(subpairs.begin(), subpairs.end(), [&](const std::pair& a, const std::pair& b) { return a.first < b.first; }); std::cout << "
\n"; for (auto own : subpairs) { htmlencode(own.first); if (own.first.empty()) own.first = "[unknown]"; std::cout << "
" << own.first << ": " << own.second << "
\n"; } std::cout << "
\n"; std::cout << "
\n"; } else { std::cout << "
" << own.first << ": " << own.second << "
\n"; } } else if (i == HIST_MAX) { std::cout << "
\n"; std::cout << "
\nSee more\n

\n"; std::cout << own.first << " (" << own.second << ")"; } if (i > HIST_MAX) std::cout << ", " << own.first << " (" << own.second << ")"; i++; } if (i <= HIST_MAX) std::cout << "\n"; else std::cout << "

\n"; } else { //TODO text-only version not implemented, displays only first-level list std::cout << caption << '\n'; for (auto own : pairs) std::cout << own.first << ": " << own.second << '\n'; } } uint find_streak(const Date_Caches& cc, std::time_t& start) { int max_str = 0; int cur_str = 0; int cur = 0; int cur_start = cur; int max_start = cur; for (auto i : cc) { if (cur == i.first / 86400) continue; if (i.first / 86400 - cur == 1) { cur_str++; cur = i.first / 86400; continue; } // streak ended if (max_str < cur_str) { max_str = cur_str; max_start = cur_start; } cur_str = 1; cur = cur_start = i.first / 86400; if (max_str == 0) { max_str = 1; max_start = cur; } } if (max_str < cur_str) { max_str = cur_str; max_start = cur_start; } start = max_start * 86400; // convert back from month count to time_t return max_str; } uint get_num(char c, char* opt) { try { if (std::stoi(opt) > 0) { return std::stoi(opt); } else { std::cout << "Option \"-" << c << "\" requires a valid number as an argument\n"; std::exit(EXIT_FAILURE); } } catch (...) { std::cout << "Option \"-" << c << "\" requires a valid number as an argument\n"; std::exit(EXIT_FAILURE); } } template void average_html(const Caches& cc, float Cache::*ptr, const std::string& caption); template void average_html(const Caches& cc, uint Cache::*ptr, const std::string& caption); template void average_html(const Caches& cc, int Cache::*ptr, const std::string& caption); template void average_html(const Caches& cc, T Cache::*ptr, const std::string& caption) { std::cout << "
\n"; std::cout << "Average " << caption << ": " << average(cc, ptr) << "
\n"; std::cout << "
\n"; } template float average(const Caches& cc, float Cache::*ptr); template float average(const Caches& cc, int Cache::*ptr); template float average(const Caches& cc, uint Cache::*ptr); template float average(const Caches& cc, T Cache::*ptr) { return 1.0 * std::accumulate(cc.begin(), cc.end(), 0., [&](const float& a, const Cache& b) { return std::move(a) + b.*ptr; }) / cc.size(); } template void sum_html(const Caches& cc, float Cache::*ptr, const std::string& caption); template void sum_html(const Caches& cc, int Cache::*ptr, const std::string& caption); template void sum_html(const Caches& cc, uint Cache::*ptr, const std::string& caption); template void sum_html(const Caches& cc, T Cache::*ptr, const std::string& caption) { std::cout << "
\n"; std::cout << "Total " << caption << ": " << sum(cc, ptr) << "
\n"; std::cout << "
\n"; } template float sum(const Caches& cc, float Cache::*ptr); template int sum(const Caches& cc, int Cache::*ptr); template uint sum(const Caches& cc, uint Cache::*ptr); template T sum(const Caches& cc, T Cache::*ptr) { return std::accumulate(cc.begin(), cc.end(), 0, [&](const int& a, const Cache& b) { return std::move(a) + b.*ptr; }); } int count_caches(const Caches& cc, std::string& codes, std::function test) { int count = 0; codes.clear(); for (auto& c : cc) { if (test(c)) { count++; codes += c.code; codes += ' '; } } codes.pop_back(); return count; } void header_html() { std::cout << "\n"; std::cout << "\n"; std::cout << " \n"; std::cout << " \n"; std::cout << " \n"; std::cout << " Geocaching stats\n"; std::cout << "\n"; std::cout << "\n"; } void footer_html() { std::cout << "
\n"; std::cout << "\n\n"; } Position Cache::home; Position::Position(const std::string& loc) { int pos = loc.find("|"); lat = stof(loc.substr(0, pos)); lon = stof(loc.substr(pos + 1)); } float cache_distance(const Cache& a, const Cache& b) { return 2 * Earth_radius * asin(sqrt(pow(sin(degtorad((a.pos.lat - b.pos.lat) / 2)), 2) + cos(degtorad(a.pos.lat)) * cos(degtorad(b.pos.lat)) * pow(sin(degtorad((a.pos.lon - b.pos.lon) / 2)), 2))); }