00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "units.h"
00023
00024 #include "log.h"
00025
00026 #include "utils/strprintf.h"
00027 #include "utils/stringutils.h"
00028 #include "utils/xml.h"
00029
00030 #include <cmath>
00031 #include <climits>
00032 #include <vector>
00033
00034 struct UnitLevel {
00035 std::string symbol;
00036 int count;
00037 int round;
00038 };
00039
00040 struct UnitDescription {
00041 std::vector<struct UnitLevel> levels;
00042 double conversion;
00043 bool mix;
00044 };
00045
00046 enum UnitType {
00047 UNIT_WEIGHT = 0,
00048 UNIT_CURRENCY = 1,
00049 UNIT_END
00050 };
00051
00052 struct UnitDescription units[UNIT_END];
00053
00054 void Units::loadUnits()
00055 {
00056 {
00057 struct UnitDescription ud;
00058
00059 ud.conversion = 1.0;
00060 ud.mix = false;
00061
00062 struct UnitLevel bu;
00063 bu.symbol = "g";
00064 bu.count = 1;
00065 bu.round = 0;
00066
00067 ud.levels.push_back(bu);
00068
00069 struct UnitLevel ul;
00070 ul.symbol = "kg";
00071 ul.count = 1000;
00072 ul.round = 2;
00073
00074 ud.levels.push_back(ul);
00075
00076 units[UNIT_WEIGHT] = ud;
00077 }
00078
00079 {
00080 struct UnitDescription ud;
00081
00082 ud.conversion = 1.0;
00083 ud.mix = false;
00084
00085 struct UnitLevel bu;
00086 bu.symbol = "¤";
00087 bu.count = 1;
00088 bu.round = 0;
00089
00090 ud.levels.push_back(bu);
00091
00092 units[UNIT_CURRENCY] = ud;
00093 }
00094
00095 XML::Document doc("units.xml");
00096 xmlNodePtr root = doc.rootNode();
00097
00098 if (!root || !xmlStrEqual(root->name, BAD_CAST "units"))
00099 {
00100 logger->log("Error loading unit definition file: units.xml");
00101 return;
00102 }
00103
00104 for_each_xml_child_node(node, root)
00105 {
00106 if (xmlStrEqual(node->name, BAD_CAST "unit"))
00107 {
00108 struct UnitDescription ud;
00109 int level = 1;
00110 const std::string type = XML::getProperty(node, "type", "");
00111 ud.conversion = XML::getProperty(node, "conversion", 1.0);
00112 ud.mix = XML::getProperty(node, "mix", "no") == "yes";
00113
00114 struct UnitLevel bu;
00115 bu.symbol = XML::getProperty(node, "base", "¤");
00116 bu.count = 1;
00117 bu.round = XML::getProperty(node, "round", 2);
00118
00119 ud.levels.push_back(bu);
00120
00121 for_each_xml_child_node(uLevel, node)
00122 {
00123 if (xmlStrEqual(uLevel->name, BAD_CAST "level"))
00124 {
00125 struct UnitLevel ul;
00126 ul.symbol = XML::getProperty(uLevel, "symbol",
00127 strprintf("¤%d",level));
00128 ul.count = XML::getProperty(uLevel, "count", -1);
00129 ul.round = XML::getProperty(uLevel, "round", bu.round);
00130
00131 if (ul.count > 0)
00132 {
00133 ud.levels.push_back(ul);
00134 level++;
00135 }
00136 else
00137 {
00138 logger->log("Error bad unit count: %d for %s in %s",
00139 ul.count, ul.symbol.c_str(), bu.symbol.c_str());
00140 }
00141 }
00142 }
00143
00144
00145 struct UnitLevel ll;
00146 ll.symbol = "";
00147 ll.count = INT_MAX;
00148 ll.round = 0;
00149
00150 ud.levels.push_back(ll);
00151
00152 if (type == "weight")
00153 units[UNIT_WEIGHT] = ud;
00154 else if (type == "currency")
00155 units[UNIT_CURRENCY] = ud;
00156 else
00157 logger->log("Error unknown unit type: %s", type.c_str());
00158 }
00159 }
00160 }
00161
00162 std::string formatUnit(int value, int type)
00163 {
00164 struct UnitDescription ud = units[type];
00165 struct UnitLevel ul;
00166
00167
00168 if (value <= 0) {
00169 ul = ud.levels[0];
00170 return strprintf("0%s", ul.symbol.c_str());
00171 } else {
00172 double amount = ud.conversion * value;
00173
00174
00175 if (ud.mix && ud.levels.size() > 0 && ud.levels[1].count < amount)
00176 {
00177 std::string output;
00178 struct UnitLevel pl = ud.levels[0];
00179 ul = ud.levels[1];
00180 int levelAmount = (int) amount;
00181 int nextAmount;
00182
00183 levelAmount /= ul.count;
00184
00185 amount -= levelAmount * ul.count;
00186
00187 if (amount > 0) {
00188 output = strprintf("%.*f%s", pl.round, amount,
00189 pl.symbol.c_str());
00190 }
00191
00192 for (unsigned int i = 2; i < ud.levels.size(); i++)
00193 {
00194 pl = ul;
00195 ul = ud.levels[i];
00196
00197 nextAmount = levelAmount / ul.count;
00198 levelAmount %= ul.count;
00199
00200 if (levelAmount > 0) output = strprintf("%d%s",
00201 levelAmount, pl.symbol.c_str()) + output;
00202
00203 if (!nextAmount) break;
00204 levelAmount = nextAmount;
00205 }
00206
00207 return output;
00208 }
00209 else
00210 {
00211 for (unsigned int i = 0; i < ud.levels.size(); i++)
00212 {
00213 ul = ud.levels[i];
00214 if (amount < ul.count && ul.count > 0) {
00215 ul = ud.levels[i - 1];
00216 break;
00217 }
00218 amount /= ul.count;
00219 }
00220
00221 return strprintf("%.*f%s", ul.round, amount, ul.symbol.c_str());
00222 }
00223 }
00224 }
00225
00226 std::string Units::formatCurrency(int value)
00227 {
00228 return formatUnit(value, UNIT_CURRENCY);
00229 }
00230
00231 std::string Units::formatWeight(int value)
00232 {
00233 return formatUnit(value, UNIT_WEIGHT);
00234 }