uni

University stuff
git clone git://git.margiolis.net/uni.git
Log | Files | Refs | README | LICENSE

appsystem.hpp (10237B)


      1 #ifndef APPSYSTEM_HPP
      2 #define APPSYSTEM_HPP
      3 
      4 #include <algorithm>
      5 #include <fstream>
      6 #include <iostream>
      7 #include <sstream>
      8 
      9 #include "errlog.hpp"
     10 #include "game.hpp"
     11 #include "office.hpp"
     12 
     13 class AppSystem
     14 {
     15     private:
     16         std::vector<App *> apps;
     17         std::vector<Manufacturer *> manfs;
     18         ErrLog errlog;
     19 
     20     public:
     21         AppSystem();
     22         ~AppSystem();
     23 
     24         AppSystem& operator+= (App *app);
     25         AppSystem& operator+= (Manufacturer *manf);
     26 
     27         template<typename T> void import_data(const char *fpath);
     28         template<typename T> void export_data(const char *fpath);
     29         template<typename T> void call(
     30                 std::string&& appname,
     31                 const T element,
     32                 void (App::*setter)(T));
     33         template<typename T, class U> void cast_call(
     34                 std::string&& appname,
     35                 const T element,
     36                 void (U::*setter)(T));
     37         void removebad(const Manufacturer *manf);
     38         void removebad(const char *manfsn);
     39         
     40         constexpr const std::vector<App *>& get_apps() const {return apps;}
     41         constexpr const std::vector<Manufacturer *>& get_manfs() const {return manfs;} 
     42         const std::vector<Office *> get_freeapps() const;
     43         const std::vector<Game *> get_goodgames() const;
     44 
     45     private:
     46         template<typename T> bool exists(const std::vector<T *>& vec, const T *element);
     47         template<typename T> void parse(std::ifstream& f);
     48         const std::vector<std::string> parse_office_exts(std::ifstream& f);
     49         const std::vector<Review *>
     50             parse_reviews(const std::string& appname, const char *rpath);
     51         void write_office_exts(const Office *of, std::ofstream& f);
     52         const std::string err_read(const char *fpath);
     53         const std::string err_write(const char *fpath);
     54         template<typename T> void dealloc(std::vector<T *>& vec);
     55 };
     56 
     57 /* 
     58  * Parses .csv fields for each type T
     59  * The function is templated just for the sake
     60  * of not having overloads, although this one is
     61  * not any more practical either.
     62  */ 
     63 template<typename T> void
     64 AppSystem::parse(std::ifstream& f)
     65 {
     66     if constexpr (std::is_same_v<T, Manufacturer>)
     67     {
     68         std::string sn, name, email;
     69         std::getline(f, sn, ',');
     70         std::getline(f, name, ',');
     71         std::getline(f, email);
     72         if (f.eof()) return;
     73         manfs.push_back(new Manufacturer(sn.c_str(), name.c_str(), email)); 
     74     }   
     75     else if constexpr (std::is_same_v<T, Office>)
     76     {
     77         std::string sn, name, os, manf, price, skip1, skip2;
     78         std::getline(f, sn, ',');
     79         std::getline(f, name, ',');
     80         std::getline(f, os, ',');
     81         std::getline(f, manf, ',');
     82         std::getline(f, price, ',');
     83         std::getline(f, skip1, ',');
     84         std::getline(f, skip2, ',');
     85         if (f.eof()) return;
     86         std::vector<std::string> exts = parse_office_exts(f);
     87         
     88         if (!manfs.empty())
     89         {
     90             for (const auto& man : manfs)
     91             {
     92                 if (man->get_name() == manf)
     93                 {
     94                     apps.push_back(new Office(sn.c_str(), name, os,
     95                                 man, std::stoi(price), exts));
     96                     break;
     97                 }
     98             }
     99         }
    100     }
    101     else if constexpr (std::is_same_v<T, Game>)
    102     {
    103         std::string sn, name, os, manf, price, genre, online;
    104         std::string skip;
    105         std::getline(f, sn, ',');
    106         std::getline(f, name, ',');
    107         std::getline(f, os, ',');
    108         std::getline(f, manf, ',');
    109         std::getline(f, price, ',');
    110         std::getline(f, genre, ',');
    111         std::getline(f, online, ',');
    112         std::getline(f, skip);
    113         if (f.eof()) return;
    114         bool onl = online == "Yes";
    115         
    116         if (!manfs.empty())
    117         {
    118             for (const auto& man : manfs)
    119             {
    120                 if (man->get_name() == manf)
    121                 {
    122                     apps.push_back(new Game(sn.c_str(), name, os,
    123                                 man, std::stoi(price), genre, onl));
    124                     break;
    125                 }
    126             }
    127         }
    128     }
    129     else if constexpr (std::is_same_v<T, Review>)
    130     {
    131         std::string appname, stars, username, comment;
    132         std::getline(f, appname, ',');
    133         std::getline(f, stars, ',');
    134         std::getline(f, username, ',');
    135         std::getline(f, comment);
    136         if (f.eof()) return;
    137         for (auto&& app : apps)
    138             if (appname == app->get_name())
    139                 app->addrev(new Review(std::stoi(stars), username, comment)); 
    140     }
    141 }
    142 
    143 /* 
    144  * Imports data from a given path and handles a possible
    145  * std::ifstream::badbit exception
    146  */
    147 template<typename T> void
    148 AppSystem::import_data(const char *fpath)
    149 {
    150     std::ifstream f;
    151     f.exceptions(std::ifstream::badbit);
    152     try
    153     {
    154         std::string strpath(fpath);
    155         f.open(fpath);
    156         if (f.is_open())
    157         {
    158             std::printf("Importing data from \'%s\'\n", fpath);
    159             std::string skip;
    160             std::getline(f, skip);
    161             while (f.good())
    162             {
    163                 if constexpr (std::is_same_v<T, Manufacturer>)
    164                     parse<Manufacturer>(f);
    165                 else if constexpr (std::is_same_v<T, App>)
    166                 {
    167                     std::string type;
    168                     std::getline(f, type, ',');
    169                     if (type == "Game") parse<Game>(f);
    170                     if (type == "Office") parse<Office>(f);
    171                 }
    172                 else if constexpr (std::is_same_v<T, Review>)
    173                     parse<Review>(f);
    174             }
    175         }
    176         f.close();
    177     }
    178     catch (const std::ifstream::failure& e)
    179     {
    180         /*
    181          * We terminate because there's no point in continuing if
    182          * the file is corrupted
    183          */
    184         errlog.write(err_read(fpath) + " (" + e.what() + ")");
    185         throw std::runtime_error(err_read(fpath) + " (" + e.what() + ")");
    186     }
    187 }
    188 
    189 /* 
    190  * Exports data to a given path for each type T.
    191  * This function is also templated just for the sake
    192  * of not having overloads. It also handles exceptions.
    193  */
    194 template<typename T> void
    195 AppSystem::export_data(const char *fpath)
    196 {
    197     std::ofstream f;
    198     f.exceptions(std::ofstream::failbit | std::ofstream::badbit);
    199     try
    200     {
    201         std::string strpath(fpath);
    202         f.open(fpath);
    203         std::printf("Exporting data to \'%s\'\n", fpath);
    204         
    205         if constexpr (std::is_same_v<T, Manufacturer>)
    206         {
    207             f << "SN,Name,Email\n";
    208             for (const auto& manf : manfs)
    209                 f << manf->get_serialnum() << ',' <<
    210                     manf->get_name() << ',' <<
    211                     manf->get_email() << std::endl;
    212         }
    213         else if constexpr (std::is_same_v<T, App>)
    214         {
    215             f << "Type,SN,Name,OS,Manf,Price,Genre,Online,Extensions\n";
    216             for (const auto& app : apps)
    217             {
    218                 Manufacturer manf = app->get_manf();
    219                 Game *o = dynamic_cast<Game *>(app);
    220                 f << (o ? "Game" : "Office") << ',';    
    221                 f << app->get_serialnum() << ',' <<
    222                     app->get_name() << ',' <<
    223                     app->get_os() << ',' <<
    224                     manf.get_name() << ',' <<
    225                     app->get_price() << ',' <<
    226                     (o ? o->get_genre() :"N/A") << ',' <<
    227                     (o ? (o->get_online() ? "Yes" : "No") : "N/A") << ',';
    228                 if (o) f << "N/A" << std::endl;
    229                 else
    230                 {
    231                     Office *of = dynamic_cast<Office *>(app);
    232                     write_office_exts(of, f);
    233                     f << std::endl;
    234                 }
    235             }
    236         }
    237         else if constexpr (std::is_same_v<T, Review>)
    238         {
    239             f << "AppName,Stars,Username,Comment\n";
    240             for (const auto& app : apps)
    241             {
    242                 const std::vector<Review *> revs = app->get_revs();
    243                 if (!revs.empty())
    244                     for (const auto& rev : revs)
    245                         f <<
    246                             app->get_name() << ',' <<
    247                             rev->get_stars() << ',' <<
    248                             rev->get_username() << ',' <<
    249                             rev->get_comment() << std::endl;    
    250             }
    251         }
    252         f.close();
    253     }
    254     catch (const std::ofstream::failure& e)
    255     {
    256         /*
    257          * In this case we don't terminate because the output
    258          * file is not to be used by the program later, so
    259          * we shouldn't lose all progress.
    260          */
    261         errlog.write(err_write(fpath) + " (" + e.what() + ")");
    262     }
    263 }
    264 
    265 /* 
    266  * Searches a vector of any type T and returns true if the
    267  * element is found. I made it just so I don't have to write
    268  * all this every time.
    269  */
    270 template<typename T> bool
    271 AppSystem::exists(const std::vector<T *>& vec, const T *element)
    272 {
    273     return std::find(vec.begin(), vec.end(), element) != vec.end();
    274 }
    275 
    276 /* 
    277  * Searches through the apps array and in case the app is found
    278  * it calls a given App setter through a function pointer.
    279  * "element" must be of the same type as the setter's parameter.
    280  * It's ugly.
    281  */
    282 template<typename T> void
    283 AppSystem::call(std::string&& appname, const T element, void (App::*setter)(T))
    284 {
    285     for (auto&& app : apps)
    286         if (app->get_name() == appname)
    287             (app->*setter)(element);
    288 }
    289 
    290 /* 
    291  * Same as above but this one is used for the derived classes
    292  * "Game" and "Office". I could use this one in all cases but
    293  * dynamic casting everytime would be pointless.
    294  */
    295 template<typename T, class U> void
    296 AppSystem::cast_call(std::string&& appname, const T element, void (U::*setter)(T))
    297 {
    298     for (auto&& app : apps)
    299         if (U *o = dynamic_cast<U *>(app))
    300             if (o->get_name() == appname)
    301                 (o->*setter)(element);
    302 }
    303 
    304 /* 
    305  * Frees every pointer object in every vector.
    306  * This function is called only by the destructor.
    307  */
    308 template<typename T> void
    309 AppSystem::dealloc(std::vector<T *>& vec)
    310 {
    311     if (!vec.empty())
    312     {
    313         for (auto&& v : vec)
    314             if (v != nullptr)
    315                 delete v;
    316         vec.clear();
    317     }
    318 }
    319 
    320 #endif /* APPSYSTEM_HPP */