Guest User

example.cpp

a guest
Aug 15th, 2015
416
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 38.91 KB | None | 0 0
  1. #include <iostream>
  2. #include <utility>
  3. #include <vector>
  4. #include <string>
  5. #include <utility>
  6. #include <sstream>
  7. #include <algorithm>
  8. #include <functional>
  9. #include <fstream>
  10. #include <limits>
  11.  
  12. #include "budget_menu.hpp"
  13. #include "utility/scroll_display.hpp"
  14. #include "utility/user_input.hpp"
  15. #include "common/common.hpp"
  16. #include "data/budget_data.hpp"
  17. #include "utility/scroll_display.hpp"
  18. #include "utility/filesystem.hpp"
  19. #include "utility/stream_operations.hpp"
  20. #include "submenu/move_element.hpp"
  21. #include "submenu/allocation_distribution_menu.hpp"
  22. #include "common/global/global_defines.hpp"
  23. #include "submenu/modify_timeframe.hpp"
  24. #include "utility/time_frame.hpp"
  25.  
  26.  
  27. /* budget_statistics_data: */
  28. namespace
  29. {
  30.     typedef struct budget_statistics_data budget_statistics_data;
  31.    
  32.    
  33.     /**
  34.      * @struct budget_statistics_data
  35.      * @author Jonathan Whitlock
  36.      * @date 06/04/2015
  37.      * @file budget_menu.cpp
  38.      * @brief Just trivializes statistics for a budget.  Use it or don't.  Doesn't matter.
  39.      * It mainly makes it easier to calculate, display, and maintain statistics
  40.      * for the budget.
  41.      */
  42.     typedef struct budget_statistics_data
  43.     {
  44.         explicit budget_statistics_data();
  45.         explicit budget_statistics_data(const data::budget_data&);
  46.         budget_statistics_data(const budget_statistics_data&);
  47.         budget_statistics_data(budget_statistics_data&&) noexcept;
  48.        
  49.         ~budget_statistics_data();
  50.        
  51.         budget_statistics_data& operator=(const budget_statistics_data&);
  52.         budget_statistics_data& operator=(budget_statistics_data&&) noexcept;
  53.         bool operator==(const budget_statistics_data&) const;
  54.         bool operator!=(const budget_statistics_data&) const;
  55.        
  56.         const data::budget_data *budget;
  57.         data::money_t money_allocated, money_unallocated;
  58.     } budget_statistics_data;
  59.    
  60.    
  61.     budget_statistics_data::budget_statistics_data() :
  62.             budget{nullptr},
  63.             money_allocated{0},
  64.             money_unallocated{0}
  65.     {
  66.     }
  67.    
  68.     budget_statistics_data::budget_statistics_data(const data::budget_data& b) :
  69.             budget{&b},
  70.             money_allocated{0},
  71.             money_unallocated{0}
  72.     {
  73.         for(std::vector<data::money_alloc_data>::const_iterator it{b.allocs.begin()}; it != b.allocs.end(); ++it)
  74.         {
  75.             this->money_allocated += it->value;
  76.         }
  77.         this->money_unallocated = (this->budget->total_money - this->money_allocated);
  78.     }
  79.    
  80.     budget_statistics_data::budget_statistics_data(const budget_statistics_data& s) :
  81.             budget{s.budget},
  82.             money_allocated{s.money_allocated},
  83.             money_unallocated{s.money_unallocated}
  84.     {
  85.     }
  86.    
  87.     budget_statistics_data::budget_statistics_data(budget_statistics_data&& s) noexcept :
  88.             budget{std::move(s.budget)},
  89.             money_allocated{std::move(s.money_allocated)},
  90.             money_unallocated{std::move(s.money_unallocated)}
  91.     {
  92.     }
  93.    
  94.     budget_statistics_data::~budget_statistics_data()
  95.     {
  96.         this->budget = nullptr;
  97.     }
  98.    
  99.     budget_statistics_data& budget_statistics_data::operator=(const budget_statistics_data& s)
  100.     {
  101.         if(this != &s)
  102.         {
  103.             this->budget = s.budget;
  104.             this->money_allocated = s.money_allocated;
  105.             this->money_unallocated = s.money_unallocated;
  106.         }
  107.         return *this;
  108.     }
  109.    
  110.     budget_statistics_data& budget_statistics_data::operator=(budget_statistics_data&& s) noexcept
  111.     {
  112.         if(this != &s)
  113.         {
  114.             this->budget = std::move(s.budget);
  115.             this->money_allocated = std::move(s.money_allocated);
  116.             this->money_unallocated = std::move(s.money_unallocated);
  117.         }
  118.         return *this;
  119.     }
  120.    
  121.     bool budget_statistics_data::operator==(const budget_statistics_data& s) const
  122.     {
  123.         return (((*(this->budget)) == (*(s.budget))) &&
  124.                     (this->money_allocated == s.money_allocated) &&
  125.                     (this->money_unallocated == s.money_unallocated));
  126.     }
  127.    
  128.     bool budget_statistics_data::operator!=(const budget_statistics_data& s) const
  129.     {
  130.         return (((*(this->budget)) != (*(s.budget))) ||
  131.                     (this->money_allocated != s.money_allocated) ||
  132.                     (this->money_unallocated != s.money_unallocated));
  133.     }
  134.    
  135.    
  136. }
  137.  
  138. /* Local functions that don't really belong anywhere but here.  There are also lesser
  139.  * functions used directly in menus that are within this namespace as well:*/
  140. namespace
  141. {
  142.     data::budget_data load_basic_info(const std::string&);
  143.     void display_error(const std::string&);
  144.     std::vector<data::budget_data> load_basic_info_all(global::program_data&);
  145.     budget_statistics_data apply_allocation(data::budget_data&, const data::money_alloc_data&);
  146.     bool sort_compare_budgets(const std::string&, const std::string&);
  147.     void convert_to_money(std::string&);
  148.     std::string allocation_display(const data::money_alloc_data&);
  149.     std::string money_display(const data::money_t&);
  150.     bool timeframe_conflict(const data::budget_data&, global::program_data&);
  151.    
  152.    
  153.     /**
  154.      * @brief Loads basic info of finite size.  Used for memory efficiency.
  155.      * @return a budget data.
  156.      */
  157.     inline data::budget_data load_basic_info(const std::string& path)
  158.     {
  159.         using fsys::is_file;
  160.         using fsys::is_symlink;
  161.         using utility::in_mem;
  162.        
  163.         data::budget_data tempbud;
  164.        
  165.         if(is_file(path).value && !is_symlink(path).value)
  166.         {
  167.             std::ifstream in{path.c_str(), std::ios::in};
  168.             if(in.good()) in_mem(in, tempbud.total_money);
  169.             if(in.good()) in_mem(in, tempbud.id);
  170.             if(in.good()) in>> tempbud.timeframe;
  171.             if(in.is_open()) in.close();
  172.         }
  173.         return tempbud;
  174.     }
  175.    
  176.     inline void display_error(const std::string& mess)
  177.     {
  178.         using std::cout;
  179.         using std::endl;
  180.        
  181.         common::cls();
  182.         cout<< endl;
  183.         common::center("Error occured: ");
  184.         for(unsigned int x(0); x < 5; ++x) cout<< endl;
  185.         cout<< mess<< endl;
  186.         common::wait();
  187.         common::cls();
  188.     }
  189.    
  190.     /**
  191.      * @brief Returns a list of budgets.  This function only loads the bare info
  192.      * necessary to identify the budgets.  This does not load additional information,
  193.      * like allocations.
  194.      */
  195.     inline std::vector<data::budget_data> load_basic_info_all(global::program_data& pdata)
  196.     {
  197.         pdata.budget_files = std::move(global::budget_paths(pdata.budget_folder));
  198.         if(pdata.budget_files.empty()) return std::vector<data::budget_data>();
  199.        
  200.         std::vector<data::budget_data> tempv;
  201.        
  202.         for(std::vector<std::string>::const_iterator it{pdata.budget_files.begin()}; it != pdata.budget_files.end(); ++it)
  203.         {
  204.             tempv.push_back(std::move(load_basic_info(*it)));
  205.         }
  206.         return tempv;
  207.     }
  208.    
  209.     /**
  210.      * @brief Takes a string representing a (long double), and
  211.      * formats it so that it represents a data::money_t.  This was
  212.      * created because reading (long double) from a std::stringstream
  213.      * resulted in inaccuracies that modified the input of the user
  214.      * to an unacceptable degree.
  215.      * @param s The string to format.
  216.      */
  217.     inline void convert_to_money(std::string& s)
  218.     {
  219.         std::size_t pos{s.find('.')};
  220.         if(pos != std::string::npos)
  221.         {
  222.             if((s.size() - (pos + 1)) > 2)
  223.             {
  224.                 s.insert((s.begin() + (pos + 3)), '.');
  225.                 s.erase((s.begin() + pos));
  226.             }
  227.             else if((s.size() - (pos + 1)) == 2)
  228.             {
  229.                 s.erase((s.begin() + pos));
  230.             }
  231.             else
  232.             {
  233.                 s.erase((s.begin() + pos));
  234.                 s += "0";
  235.             }
  236.         }
  237.         else
  238.         {
  239.             s += "00";
  240.         }
  241.     }
  242.    
  243.     /**
  244.      * @brief Applies an allocation to a budget for the purpose of calculating it's
  245.      * statistics.  The budget is not changed, and all modification is temporary.
  246.      * @param budget The budget to use.
  247.      * @param allocation The allocation data.
  248.      * @return budget_statistics_data on a budget that has the allocation applied.
  249.      */
  250.     inline budget_statistics_data apply_allocation(data::budget_data& budget, const data::money_alloc_data& allocation)
  251.     {
  252.         budget_statistics_data stats;
  253.         data::money_alloc_data original_alloc;
  254.         bool found{false};
  255.        
  256.         for(std::vector<data::money_alloc_data>::iterator it{budget.allocs.begin()}; ((it != budget.allocs.end()) && !found); ++it)
  257.         {
  258.             if((allocation.id == it->id) && !found)
  259.             {
  260.                 found = true;
  261.                 original_alloc = std::move(*it);
  262.                 (*it) = allocation;
  263.                
  264.                 stats = std::move(budget_statistics_data{budget});
  265.                 (*it) = std::move(original_alloc);
  266.             }
  267.         }
  268.         if(!found)
  269.         {
  270.             budget.allocs.push_back(allocation);
  271.             stats = std::move(budget_statistics_data{budget});
  272.             budget.allocs.pop_back();
  273.         }
  274.         return stats;
  275.     }
  276.    
  277.     /**
  278.      * @brief Used to sort budgets for budget_list_menu.
  279.      * @return true if
  280.      */
  281.     inline bool sort_compare_budgets(const std::string& b1, const std::string& b2)
  282.     {
  283.         return (load_basic_info(b1).timeframe.beg >= load_basic_info(b2).timeframe.beg);
  284.     }
  285.    
  286.     /**
  287.      * @brief creates a string representation of a money_alloc_data.
  288.      */
  289.     inline std::string allocation_display(const data::money_alloc_data& a)
  290.     {
  291.         using common::fit_str;
  292.        
  293.         constexpr unsigned int name_size{20};
  294.        
  295.         std::string temps{(fit_str(a.name, name_size) + std::string((name_size - fit_str(a.name, name_size).size()), ' ') +
  296.                 std::string(4, ' ') + money_display(a.value)) + std::string((10 - money_display(a.value).size()), ' ') +
  297.                 "Balance: "};
  298.         if(a.meta_data != nullptr)
  299.         {
  300.             temps += money_display(a.meta_data->balance);
  301.         }
  302.         else
  303.         {
  304.             temps += "[Error dereferencing data::money_alloc_data::meta_data::balance]";
  305.         }
  306.         return temps;
  307.     }
  308.    
  309.     /**
  310.      * @brief returns a string in the form "$0.00"
  311.      */
  312.     inline std::string money_display(const data::money_t& money)
  313.     {
  314.         std::string temps{"$"};
  315.         temps += std::to_string(((long double)money / 100));
  316.         if(temps.find('.') != std::string::npos)
  317.         {
  318.             if((temps.size() - temps.find('.')) > 2) temps.resize((temps.find('.') + 3));
  319.         }
  320.         return temps;
  321.     }
  322.    
  323.     inline bool timeframe_conflict(const data::budget_data& b, global::program_data& pdata)
  324.     {
  325.         data::budget_data tempbud;
  326.        
  327.         pdata.budget_files = std::move(global::budget_paths(pdata.budget_folder));
  328.         for(std::vector<std::string>::iterator it{pdata.budget_files.begin()}; it != pdata.budget_files.end();)
  329.         {
  330.             if(!fsys::is_file(*it)) //just a redundancy
  331.             {
  332.                 it = pdata.budget_files.erase(it);
  333.                 continue;
  334.             }
  335.             tempbud = std::move(load_basic_info(*it));
  336.             if(tempbud.id != b.id)
  337.             {
  338.                 if(tempbud.timeframe.overlaps(b.timeframe)) return true;
  339.             }
  340.             ++it;
  341.         }
  342.         return false;
  343.     }
  344.    
  345.    
  346. }
  347.  
  348. //Primary functions that are directly used in the menus:
  349. namespace
  350. {
  351.     bool user_get_money_value(data::money_t&);
  352.     std::string budget_statistic_display(const data::budget_data&);
  353.     bool call_create_budget(global::program_data&);
  354.     void money_alloc_list_display(const std::vector<data::money_alloc_data>&, std::vector<std::string>&);
  355.     bool call_mod_budget(global::program_data&, const std::string&);
  356.     bool usr_delete_file(const std::string&);
  357.     void create_display(const std::vector<std::string>&, std::vector<std::string>&);
  358.     bool spec_budget_timeframe(global::program_data&, data::budget_data&);
  359.    
  360.    
  361.     /**
  362.      * @brief Gets a monetary value from the user.
  363.      * @param m money to modify
  364.      * @return true if the user entered a new value.
  365.      */
  366.     inline bool user_get_money_value(data::money_t& m)
  367.     {
  368.         //todo add ability to recognize and parse simple equations
  369.         std::string temps{std::move(std::to_string(((long double)m / (long double)100)))};
  370.         bool modified{false}, is_valid{false};
  371.        
  372.         do
  373.         {
  374.             modified = common::get_user_str(temps);
  375.             is_valid = common::str_is_num(temps);
  376.         }while(modified && !is_valid);
  377.         if(modified && is_valid)
  378.         {
  379.             convert_to_money(temps);
  380.             std::stringstream ss;
  381.             ss<< temps;
  382.             ss>> m;
  383.         }
  384.         return (modified && is_valid);
  385.     }
  386.    
  387.     /**
  388.      * @brief Creates a std::string that contains a display for budget statistics.
  389.      * @param budget Budget to display stats for.
  390.      * @return a string.
  391.      */
  392.     inline std::string budget_statistic_display(const data::budget_data& budget)
  393.     {
  394.         std::string temps{"Budget for date: " + common::date_disp(budget.timeframe.beg) + "\n\n"};
  395.         budget_statistics_data stats{budget};
  396.        
  397.         temps += ("Total money in the budget: " + money_display(budget.total_money) + "\n");
  398.         temps += ("    Total money allocated: " + money_display(stats.money_allocated) + "\n\n");
  399.         temps += ("               Money left: " + money_display(stats.money_unallocated));
  400.         return temps;
  401.     }
  402.    
  403.     /**
  404.      * @brief Deletes a file, but displays any errors to the user.  This is used
  405.      * for menu operations.
  406.      * @param path the path to delete (will not delete folders with sub-paths)
  407.      * @return true if the path does't exist.
  408.      */
  409.     inline bool usr_delete_file(const std::string& path)
  410.     {
  411.         using std::cout;
  412.         using std::endl;
  413.        
  414.         if(fsys::is_file(path).value)
  415.         {
  416.             fsys::result_data_boolean tempres(fsys::fdelete(path));
  417.             if(!tempres.value) display_error(tempres.error);
  418.             return tempres.value;
  419.         }
  420.         return !fsys::is_file(path).value;
  421.     }
  422.    
  423.     /**
  424.      * @brief Used to created a display vector for a window_data_class.  Specifically,
  425.      * it's used to create a display of a list of budgets the user has created.
  426.      */
  427.     inline void create_display(const std::vector<std::string>& paths, std::vector<std::string>& display)
  428.     {
  429.         display.erase(display.begin(), display.end());
  430.        
  431.         data::budget_data tempbud;
  432.        
  433.         for(unsigned int x(0); x < paths.size(); ++x)
  434.         {
  435.             if(fsys::is_file(paths[x]).value)
  436.             {
  437.                 tempbud = std::move(load_basic_info(paths[x]));
  438.                 display.push_back(std::move((common::date_disp(tempbud.timeframe.beg) + "   (" +
  439.                         money_display(tempbud.total_money) + ")")));
  440.             }
  441.             else
  442.             {
  443.                 display.push_back("ERROR: File doesn't exist!");
  444.             }
  445.         }
  446.     }
  447.    
  448.     /**
  449.      * @brief Takes a list of money allocations and creates a string representation of each allocation,
  450.      * placing them in a list of strings.  This is used for created a window_data_class<data::money_alloc_data>.
  451.      */
  452.     inline void money_alloc_list_display(const std::vector<data::money_alloc_data>& allocations, std::vector<std::string>& disp)
  453.     {
  454.         disp.erase(disp.begin(), disp.end());
  455.        
  456.         for(unsigned int x{0}; x < allocations.size(); ++x) disp.push_back(std::move(allocation_display(allocations[x])));
  457.     }
  458.    
  459.     /**
  460.      * @brief Calls modify_budget, but also handles the loading
  461.      * and saving of the budget, as well as displaying any errors that occur.
  462.      * This essentially seperates the loading/saving code from the menus.  Menus
  463.     budget_statistic_display * should not save or load any data.
  464.      * @param path the path chosen.
  465.      * @return true if the budget was modified.
  466.      */
  467.     inline bool call_mod_budget(global::program_data& pdat, const std::string& path)
  468.     {
  469.         bool success(true);
  470.         data::budget_data tempbud;
  471.        
  472.         if(common::load_from_file(path, tempbud))
  473.         {
  474.             std::pair<bool, bool> tempres{menu::modify_budget(pdat, tempbud)};
  475.             if(tempres.first && !tempres.second)
  476.             {
  477.                 if(!common::save_to_file(path, tempbud))
  478.                 {
  479.                     success = false;
  480.                     display_error("Could not save budget!");
  481.                 }
  482.             }
  483.             else if(!tempres.first) success = false;
  484.         }
  485.         else
  486.         {
  487.             success = false;
  488.             display_error("Could not load file \"" + path + "\"!");
  489.         }
  490.         return success;
  491.     }
  492.    
  493.     /**
  494.      * @brief Allows the user to choose a timeframe for a budget.
  495.      * @return true if the user entered a valid timeframe that doesn't conflict with
  496.      * any existing budget's.
  497.      */
  498.     inline bool spec_budget_timeframe(global::program_data& pdata, data::budget_data& bud)
  499.     {
  500.         std::pair<bool, bool> res{false, false};
  501.         bool valid{false};
  502.         tdata::timeframe_class frame{bud.timeframe};
  503.         data::budget_data temp_budget;
  504.        
  505.         do
  506.         {
  507.             res = std::move(menu::modify_timeframe(frame));
  508.             pdata.budget_files = std::move(global::budget_paths(pdata.budget_folder));
  509.             valid = (res.first && !res.second);
  510.             if(valid) //to keep the "overlaps" error from showing if user cancels
  511.             {
  512.                 for(std::vector<std::string>::const_iterator it{pdata.budget_files.begin()}; ((it != pdata.budget_files.end()) && valid); ++it)
  513.                 {
  514.                     temp_budget = std::move(load_basic_info(*it));
  515.                     if(bud.id != temp_budget.id)
  516.                     {
  517.                         valid = !temp_budget.timeframe.overlaps(frame);
  518.                     }
  519.                 }
  520.                 if(!valid)
  521.                 {
  522.                     using std::cout;
  523.                     using std::endl;
  524.                    
  525.                     common::cls();
  526.                     for(unsigned int x{0}; x < v_center::value; ++x) cout<< endl;
  527.                     common::center("Another budget's timeframe overlaps with the one you chose.  You \
  528.    must choose another!");
  529.                     common::wait();
  530.                     common::cls();
  531.                 }
  532.             }
  533.         }while(!valid && !res.second);
  534.         if(valid && res.first && !res.second) bud.timeframe = std::move(frame);
  535.         return (valid && res.first && !res.second);
  536.     }
  537.    
  538.     /**
  539.      * @brief This function handles creation of a new budget, as well as saving it
  540.      * if the user modified it.
  541.      * @return true if a new budget was created.
  542.      */
  543.     inline bool call_create_budget(global::program_data& pdata)
  544.     {
  545.         data::budget_data tempb;
  546.         std::pair<bool, bool> temp_result;
  547.         bool budget_created{false};
  548.        
  549.         tempb.id = std::move(data::new_budget_id(load_basic_info_all(pdata)));
  550.         tempb.timeframe.beg = tdata::current_time();
  551.         if(!spec_budget_timeframe(pdata, tempb)) return budget_created;
  552.         temp_result = std::move(menu::modify_budget(pdata, tempb));
  553.         if(temp_result.first && !temp_result.second) //modified, but not canceled
  554.         {
  555.             if(!common::save_to_file(data::budget_path(pdata, tempb), tempb))
  556.             {
  557.                 display_error("Unable to save the budget!");
  558.             }
  559.             else
  560.             {
  561.                 budget_created = true;
  562.             }
  563.         }
  564.         return budget_created;
  565.     }
  566.    
  567.     /**
  568.      * @brief Allows the user to modify the length of time a budget remains active.
  569.      * @return True if the length was modified.
  570.      */
  571.     inline bool modify_budget_length(global::program_data& pdata, data::budget_data& b)
  572.     {
  573.         using std::cout;
  574.         using std::endl;
  575.        
  576.         tdata::time_interval_type temp_interval{b.timeframe.cinterval()};
  577.         std::pair<bool, bool> tempres{std::move(menu::modify_interval(temp_interval))};
  578.        
  579.         if(tempres.first && !tempres.second)
  580.         {
  581.             data::budget_data temp_bud{b};
  582.             temp_bud.timeframe = std::move(tdata::timeframe_class{temp_bud.timeframe.beg, temp_interval});
  583.            
  584.             while(tempres.first && !tempres.second &&
  585.                     timeframe_conflict(temp_bud, pdata))
  586.             {
  587.                 common::cls();
  588.                 for(unsigned int x{0}; x < v_center::value; ++x) cout<< endl;
  589.                 common::center("The chosen length of time overlaps with another timeframe!");
  590.                 common::wait();
  591.                 common::cls();
  592.                 temp_interval = b.timeframe.cinterval();
  593.                 tempres = std::move(menu::modify_interval(temp_interval));
  594.                 temp_bud.timeframe = std::move(tdata::timeframe_class{temp_bud.timeframe.beg, temp_interval});
  595.             }
  596.             if(tempres.first && !tempres.second)
  597.             {
  598.                 b.timeframe = std::move(tdata::timeframe_class{b.timeframe.beg, temp_interval});
  599.                 return true;
  600.             }
  601.         }
  602.         return false;
  603.     }
  604.    
  605.    
  606. }
  607.  
  608. namespace menu
  609. {
  610.     /**
  611.      * @brief Allows the user to modify any of the budgets found at load.  This
  612.      * menu also allows the user to create new budgets.
  613.      * @param pdat program data
  614.      * @return true if no errors occured.
  615.      */
  616.     bool budget_list_menu(global::program_data& pdat)
  617.     {
  618.         using scrollDisplay::window_data_class;
  619.         using scrollDisplay::display_window;
  620.         using std::cout;
  621.         using std::endl;
  622.        
  623.         window_data_class<std::string> scroll_window(pdat.budget_files, create_display);
  624.         bool finished(false);
  625.         keyboard::key_code_data key;
  626.        
  627.         pdat.budget_files = std::move(global::budget_paths(pdat.budget_folder));
  628.         std::sort(pdat.budget_files.begin(), pdat.budget_files.end(), sort_compare_budgets);
  629.         do
  630.         {
  631.             common::cls();
  632.             cout<< endl;
  633.             common::center("Budgets: ");
  634.             cout<< endl;
  635.             display_window(scroll_window);
  636.             cout<< endl;
  637.             cout<< "\'a\' -  Add new budget"<< endl;
  638.             cout<< "\'q\' -  Quit";
  639.             cout.flush();
  640.            
  641.             key = std::move(user_input::gkey_funct());
  642.             {
  643.                 using namespace keyboard::code;
  644.                 using keyboard::keys;
  645.                
  646.                 if(keyboard::is_listed_control(key))
  647.                 {
  648.                     if(key == keys[up::value]) scroll_window.win().mv_up();
  649.                     else if(key == keys[down::value]) scroll_window.win().mv_down();
  650.                     else if(key == keys[home::value]) scroll_window.win().jmp(0);
  651.                     else if(key == keys[end::value]) scroll_window.win().jmp((scroll_window.gdata()->size() - 1));
  652.                     else if(key == keys[del::value])
  653.                     {
  654.                         if(!pdat.budget_files.empty())
  655.                         {
  656.                             if(common::prompt_user("Are you sure you want to delete the \
  657. budget for " + common::date_disp(load_basic_info(scroll_window.cselected()).timeframe.beg) + "?  This \
  658. is permanent!"))
  659.                             {
  660.                                 if(usr_delete_file(scroll_window.cselected()))
  661.                                 {
  662.                                     scroll_window.remove_selected();
  663.                                 }
  664.                             }
  665.                         }
  666.                     }
  667.                 }
  668.                 else
  669.                 {
  670.                     if(!key.control_d.empty())
  671.                     {
  672.                         switch(tolower((char)key.control_d.front()))
  673.                         {
  674.                             case '\n':
  675.                             {
  676.                                 if(!pdat.budget_files.empty())
  677.                                 {
  678.                                     call_mod_budget(pdat, scroll_window.cselected());
  679.                                     pdat.budget_files = std::move(global::budget_paths(pdat.budget_folder));
  680.                                     std::sort(pdat.budget_files.begin(), pdat.budget_files.end(), sort_compare_budgets);
  681.                                 }
  682.                             }
  683.                             break;
  684.                            
  685.                             case 'a':
  686.                             {
  687.                                 call_create_budget(pdat);
  688.                                 pdat.budget_files = std::move(global::budget_paths(pdat.budget_folder));
  689.                                 std::sort(pdat.budget_files.begin(), pdat.budget_files.end(), sort_compare_budgets);
  690.                             }
  691.                             break;
  692.                            
  693.                             case 'q':
  694.                             {
  695.                                 finished = true;
  696.                             }
  697.                             break;
  698.                            
  699.                             default:
  700.                             {
  701.                             }
  702.                             break;
  703.                         }
  704.                     }
  705.                 }
  706.             }
  707.         }while(!finished);
  708.         common::cls();
  709.         return true; //there has yet to be a case where this function fails.
  710.     }
  711.    
  712.     /**
  713.      * @brief Allows the user to modify a budget.  If the user cancels, the budget
  714.      * remains unchanged.
  715.      * @param b The budget to modify.
  716.      * @return an std::pair<bool, bool>.
  717.      * result.first = whether the budget was modified,
  718.      * result.second = whether the user canceled the operation.
  719.      */
  720.     std::pair<bool, bool> modify_budget(global::program_data& pdat __attribute__((unused)), data::budget_data& b)
  721.     {
  722.         //todo add a budget report that shows all allocations, balances, and subtotals that can be easily shared and looks nice.
  723.         using scrollDisplay::window_data_class;
  724.         using keyboard::key_code_data;
  725.         using std::cout;
  726.         using std::endl;
  727.        
  728.         std::pair<bool, bool> result{false, false};
  729.         data::budget_data original_budget{b};
  730.         bool finished{false};
  731.         window_data_class<data::money_alloc_data> scroll_display{b.allocs, money_alloc_list_display};
  732.         key_code_data key;
  733.        
  734.         scroll_display.win().window_size() = 6;
  735.         user_input::cl();
  736.         do
  737.         {
  738.             common::cls();
  739.             cout<< "Today is "<< common::date_disp(tdata::time_class{tdata::current_time()})<< endl;
  740.             cout<< endl;
  741.             common::center("Budget starting " + common::date_disp(b.timeframe.beg));
  742.             cout<< endl;
  743.             cout<< "Budget ends "<< common::date_disp(b.timeframe.cinterval().add_to(b.timeframe.beg))<< endl;
  744.            
  745.             data::generate_meta_data(b);
  746.             scrollDisplay::display_window(scroll_display);
  747.             data::delete_meta_data(b);
  748.            
  749.             cout<< endl;
  750.             cout<< "Total money in this budget: "<< money_display(b.total_money)<< endl;
  751.             cout<< endl;
  752.             cout<< " m -------> Modify total money to the budget"<< endl;
  753.             cout<< " a -------> Add new allocation"<< endl;
  754.             cout<< " d -------> Distribute money"<< endl;
  755.             cout<< " [SPCE] --> Move Selected"<< endl;
  756.             cout<< " s -------> Statistics"<< endl;
  757.             cout<< " L -------> Length of time the budgets is active"<< endl;
  758.             cout<< endl;
  759.             cout<< " [BCKSPC] -  Done"<< endl;
  760.             cout<< " c -  -----  Cancel";
  761.             cout.flush();
  762.            
  763.             key = std::move(user_input::gkey_funct());
  764.            
  765.             if(keyboard::is_listed_control(key))
  766.             {
  767.                 using namespace keyboard::code;
  768.                 using keyboard::keys;
  769.                
  770.                 if(key == keys[up::value]) scroll_display.win().mv_up();
  771.                 else if(key == keys[down::value]) scroll_display.win().mv_down();
  772.                 else if(key == keys[pgup::value]) scroll_display.win().pg_up();
  773.                 else if(key == keys[pgdown::value]) scroll_display.win().pg_down();
  774.                 else if(key == keys[home::value]) while(scroll_display.win().pg_up());
  775.                 else if(key == keys[end::value]) while(scroll_display.win().pg_down());
  776.                 else if(key == keys[backspace::value]) finished = true;
  777.                 else if(key == keys[del::value])
  778.                 {
  779.                     if(!b.allocs.empty())
  780.                     {
  781.                         if(common::prompt_user("Do you really want to delete \"" + scroll_display.selected().name + "\"?"))
  782.                         {
  783.                             scroll_display.remove_selected();
  784.                             result.first = true;
  785.                         }
  786.                     }
  787.                 }
  788.             }
  789.             else
  790.             {
  791.                 if(key.control_d.size() == 1)
  792.                 {
  793.                     switch(std::tolower((char)key.control_d[0]))
  794.                     {
  795.                         case '\n':
  796.                         {
  797.                             if(!b.allocs.empty())
  798.                             {
  799.                                 data::money_alloc_data temp_allocation{scroll_display.selected()};
  800.                                 std::pair<bool, bool> temp_result{modify_allocation(b, temp_allocation)};
  801.                                 if(temp_result.first && !temp_result.second)
  802.                                 {
  803.                                     scroll_display.selected() = std::move(temp_allocation);
  804.                                     result.first = true;
  805.                                 }
  806.                             }
  807.                         }
  808.                         break;
  809.                        
  810.                         case 'a':
  811.                         {
  812.                             data::money_alloc_data new_allocation{"", (data::money_t)0};
  813.                             new_allocation.id = data::new_alloc_id(b.allocs);
  814.                             std::pair<bool, bool> temp_result{modify_allocation(b, new_allocation)};
  815.                             if(temp_result.first && !temp_result.second)
  816.                             {
  817.                                 b.allocs.push_back(std::move(new_allocation));
  818.                                 result.first = true;
  819.                             }
  820.                         }
  821.                         break;
  822.                        
  823.                         case 'l':
  824.                         {
  825.                             if(modify_budget_length(pdat, b)) result.first = true;
  826.                         }
  827.                         break;
  828.                        
  829.                         case 's':
  830.                         {
  831.                             common::cls();
  832.                             cout<< budget_statistic_display(b)<< endl<< endl;
  833.                             common::wait();
  834.                             common::cls();
  835.                         }
  836.                         break;
  837.                        
  838.                         case 'c':
  839.                         {
  840.                             result.second = true;
  841.                             finished = true;
  842.                         }
  843.                         break;
  844.                        
  845.                         case 'm':
  846.                         {
  847.                             common::cls();
  848.                             for(unsigned int x{0}; x < v_center::value; ++x) cout<< endl;
  849.                             cout<< "Current money budgeted: "<< money_display(b.total_money)<< endl;
  850.                             cout<< "Money left in budget: "<< money_display(budget_statistics_data{b}.money_unallocated)<< endl;
  851.                             cout<< endl<< endl;
  852.                             cout<< "Money that would zero budget: "<< money_display(budget_statistics_data{b}.money_allocated)<< endl;
  853.                             cout<< endl;
  854.                             cout<< "Enter the total money you have for this budget: $";
  855.                             cout.flush();
  856.                             if(user_get_money_value(b.total_money))
  857.                             {
  858.                                 result.first = true;
  859.                             }
  860.                         }
  861.                         break;
  862.                        
  863.                         case 'd':
  864.                         {
  865.                             if(submenu::distribution_selection(b)) result.first = true;
  866.                             data::delete_meta_data(b);
  867.                         }
  868.                         break;
  869.                        
  870.                         case ' ':
  871.                         {
  872.                             data::generate_meta_data(b);
  873.                             //note this is how I'm implementing priority: based on order of the elements.
  874.                             if(b.allocs.size() > 1)
  875.                             {
  876.                                 std::function<void()> update_disp{[&b]()->void{data::generate_meta_data(b);}};
  877.                                 if(submenu::move_vector_element(scroll_display, b.allocs, &update_disp))
  878.                                 {
  879.                                     result.first = true;
  880.                                 }
  881.                             }
  882.                             data::delete_meta_data(b);
  883.                         }
  884.                         break;
  885.                        
  886.                         default:
  887.                         {
  888.                         }
  889.                         break;
  890.                     }
  891.                 }
  892.             }
  893.         }while(!finished);
  894.         if(result.second && result.first) b = std::move(original_budget);
  895.         return result;
  896.     }
  897.    
  898.     /**
  899.      * @brief Allows the user to modify a budget allocation.
  900.      * @param allocation The allocation to modify.
  901.      * @param budget The budget referenced.  This is mainly used for
  902.      * making calculations about how much money is left in the budget.  The budget
  903.      * is not modified.
  904.      * @return a std::pair<bool, bool>:
  905.      * first = whether the allocation was modified
  906.      * second = whether the user canceled modification of the allocation.
  907.      */
  908.     std::pair<bool, bool> modify_allocation(data::budget_data& budget, data::money_alloc_data& allocation)
  909.     {
  910.         using std::cout;
  911.         using std::endl;
  912.        
  913.         std::pair<bool, bool> result{false, false};
  914.         bool finished{false};
  915.         keyboard::key_code_data key;
  916.        
  917.         do
  918.         {
  919.             common::cls();
  920.             cout<< "Money that can be allocated: "<< money_display(apply_allocation(budget, allocation).money_unallocated)<< endl;
  921.             cout<< endl;
  922.             common::center("Modify Budget Allocation");
  923.             for(unsigned int x{0}; x < 3; ++x) cout<< endl;
  924.             cout<< " 1 -  Name: \""<< allocation.name<< "\""<< endl;
  925.             cout<< " 2 -  Value: "<< money_display(allocation.value)<< endl;
  926.             cout<< endl;
  927.             cout<< " z -  Zero out"<< endl;
  928.             cout<< " c -  Cancel"<< endl;
  929.             cout<< " [BCKSPC] -  Done";
  930.             cout.flush();
  931.            
  932.             key = std::move(user_input::gkey_funct());
  933.            
  934.             if(keyboard::is_listed_control(key))
  935.             {
  936.                 using namespace keyboard::code;
  937.                 using keyboard::keys;
  938.                
  939.                 if(key == keys[backspace::value]) finished = true;
  940.             }
  941.             else
  942.             {
  943.                 if(key.control_d.size() == 1)
  944.                 {
  945.                     switch(std::tolower((char)key.control_d[0]))
  946.                     {
  947.                         case '1':
  948.                         {
  949.                             std::string temps{((allocation.name == data::money_alloc_data{}.name) ? "" : allocation.name)};
  950.                             common::cls();
  951.                             cout<< "[ESC]: cancel"<< endl;
  952.                             for(unsigned int x{0}; x < 11; ++x) cout<< endl;
  953.                             cout<< "Enter a name: ";
  954.                             cout.flush();
  955.                             if(common::get_user_str(temps))
  956.                             {
  957.                                 allocation.name = std::move(temps);
  958.                                 result.first = true;
  959.                             }
  960.                             temps.erase();
  961.                             common::cls();
  962.                         }
  963.                         break;
  964.                        
  965.                         case '2':
  966.                         {
  967.                             common::cls();
  968.                             cout<< endl;
  969.                             cout<< " [ESC]: Cancel"<< endl;
  970.                             for(unsigned int x{0}; x < 7; ++x) cout<< endl;
  971.                             cout<< "Currently set to: "<< money_display(allocation.value)<< endl;
  972.                             cout<< endl;
  973.                             cout<< "Enter the new value: ";
  974.                             cout.flush();
  975.                             {
  976.                                 data::money_t temp_money{allocation.value};
  977.                                 if(user_get_money_value(temp_money))
  978.                                 {
  979.                                     allocation.value = temp_money;
  980.                                     result.first = true;
  981.                                 }
  982.                             }
  983.                             common::cls();
  984.                         }
  985.                         break;
  986.                        
  987.                         case 'z':
  988.                         {
  989.                             allocation.value += apply_allocation(budget, allocation).money_unallocated;
  990.                             result.first = true;
  991.                         }
  992.                         break;
  993.                        
  994.                         case 'c':
  995.                         {
  996.                             result.second = true;
  997.                             finished = true;
  998.                         }
  999.                         break;
  1000.                        
  1001.                         default:
  1002.                         {
  1003.                         }
  1004.                         break;
  1005.                     }
  1006.                 }
  1007.             }
  1008.         }while(!finished);
  1009.         return result;
  1010.     }
  1011.    
  1012.    
  1013. }
Advertisement
Add Comment
Please, Sign In to add comment