#include #include "dblib.h" #include "../mg/anamag.h" #include "../mg/umart.h" /////////////////////////////////////////////////////////// // TQuantita' /////////////////////////////////////////////////////////// TDecoder* TQuantita::_umart1 = NULL; TDecoder* TQuantita::_umart2 = NULL; real TQuantita::get_factor(const TCodice_um& um) const { real fc = 1.0; if (_articolo.blank()) { NFCHECK("Unita' di misura generica non supportata"); } else { if (_umart2 == NULL) _umart2 = new TDecoder(LF_UMART, UMART_FC, 2); TString80 code; code << _articolo << '|' << (um.empty() ? _um : um); const TString& val = _umart2->decode(code); if (val.not_empty()) fc = real(val); } return fc; } void TQuantita::set_articolo(const TCodice_articolo& art, const TCodice_um& um) { _articolo = art; if (um.blank()) { if (_umart1 == NULL) _umart1 = new TDecoder(LF_UMART, UMART_UM, 1); TString80 code; code << _articolo << "|1"; const TString& new_um = _umart1->decode(code); if (!new_um.blank()) _um = new_um; _conv = 1.0; } else { _um = um; _conv = get_factor(_um); } CHECK(!_um.blank(), "Unita' di misura nulla"); CHECK(_conv > ZERO, "Invalid conversion factor"); } void TQuantita::copy(const TQuantita& q) { _articolo = q._articolo; _um = q._um; _conv = q._conv; _val = q._val; } void TQuantita::convert(real& val, const TCodice_um& from_um, const TCodice_um& to_um) const { CHECK(!from_um.blank() && !to_um.blank(), "Unita' di misura nulla"); if (from_um != to_um) { if (!_val.is_zero()) { const real mul = get_factor(from_um); const real div = get_factor(to_um); val *= mul; val /= div; } } } void TQuantita::convert_to_base() { CHECK(_conv > ZERO, "Invalid conversion factor"); _val *= _conv; TCodice_um dummy; set_articolo(_articolo, dummy); } int TQuantita::compare(const TSortable& s) const { const TQuantita& q = (const TQuantita&)s; real qta = q._val; if (_um != q._um) convert(qta, q._um, _um); qta -= _val; return -qta.sign(); } const TQuantita& TQuantita::operator +=(const TQuantita& q) { real qta = q._val; if (_um != q._um) convert(qta, q._um, _um); _val += qta; return *this; } const TQuantita& TQuantita::operator -=(const TQuantita& q) { real qta = q._val; if (_um != q._um) convert(qta, q._um, _um); _val -= qta; return *this; } const TQuantita& TQuantita::operator =(const real& q) { CHECK(!_um.blank(), "Unita' di misura nulla"); _val = q; return *this; } const TQuantita& TQuantita::operator *=(const real& q) { CHECK(!_um.blank(), "Unita' di misura nulla"); _val *= q; return *this; } const TQuantita& TQuantita::operator /=(const real& q) { CHECK(!_um.blank(), "Unita' di misura nulla"); _val /= q; return *this; } TQuantita::TQuantita() : _conv(1.0) { } TQuantita::TQuantita(const TCodice_articolo& art) { TCodice_um dummy; set(art, dummy, ZERO); } TQuantita::TQuantita(const TCodice_articolo& art, const TCodice_um& um, const real& val) { set(art, um, val); } TQuantita::TQuantita(const TQuantita& q) { copy(q); } TQuantita::~TQuantita() { } /////////////////////////////////////////////////////////// // TDistinta_expr /////////////////////////////////////////////////////////// bool TDistinta_expr::print_error(const char* msg) const { return error_box(msg); } TDistinta_expr::TDistinta_expr() : TExpression(_numexpr, FALSE) { } /////////////////////////////////////////////////////////// // TDistinta_tree /////////////////////////////////////////////////////////// const TRectype* TDistinta_tree::_curr = NULL; TToken_string TDistinta_tree::_tmp(80, ','); bool TDistinta_tree::isola_codice(TString& code) const { int comma = code.find(','); if (comma > 0) code.cut(comma); return code.not_empty(); } bool TDistinta_tree::curr_code(TCodice_articolo& code) const { _path.get(-2, _tmp); isola_codice(_tmp); code = _tmp; return code.not_empty(); } bool TDistinta_tree::curr_giac(TString& code) const { _path.get(-2, _tmp); _tmp.get(1, code); return code.not_empty(); } int TDistinta_tree::curr_comp(TString& code) const { _path.get(-2, _tmp); _tmp.get(2, code); return atoi(code); } long TDistinta_tree::curr_sort() const { _path.get(-2, _tmp); return _tmp.get_long(3); } const char* TDistinta_tree::curr_um(TCodice_um& code) const { _path.get(-2, _tmp); _tmp.get(4, code); return code; } real TDistinta_tree::curr_qta(bool last_only) const { real qta = 1.0; const int last = _path.items()-1; if (last > 0) { for (int i = last; i > 0; i--) { _path.get(i, _tmp); real val; _tmp.get(5, val); qta *= val; if (last_only || qta.is_zero()) break; } } return qta; } bool TDistinta_tree::goto_node(const TString &id) { if (id != _path) { _stack.destroy(); TToken_string str = id; _path = str.get(0); push_vars(); for (const char* t = str.get(); t; t = str.get()) { _path.add(t); push_vars(); } } return TRUE; } struct TFind_node_data { TCodice_articolo _id; long _count; }; HIDDEN bool find_node_callback(TTree& tree, void* jolly, word flags) { if (flags == SCAN_PRE_ORDER) { TFind_node_data& data = *(TFind_node_data*)jolly; data._count++; TDistinta_tree& dt = (TDistinta_tree&)tree; TCodice_articolo id; dt.curr_code(id); if (data._id == id) return TRUE; } return FALSE; } long TDistinta_tree::find_node(const TCodice_articolo& str, word flags) { if (goto_root()) { TFind_node_data fnd; fnd._id = str; fnd._count = 0; if (scan_breadth_first(find_node_callback, &fnd, flags)) return fnd._count; } return 0L; } void TDistinta_tree::node2id(const TObject* node, TString& id) const { id = *(TToken_string*)node; } TObject* TDistinta_tree::curr_node() const { return (TObject*)&_path; } bool TDistinta_tree::get_description(TString& desc) const { _path.get(-2, desc); isola_codice(desc); return TRUE; } TImage* TDistinta_tree::image(bool selected) const { TImage* img; if (is_cyclic()) img = get_res_image(BMP_STOP); else { if (is_leaf()) img = get_res_image(BMP_FILE); else img = TBidirectional_tree::image(selected); } return img; } void TDistinta_tree::restart() { _dist.destroy(); _rdist.destroy(); _vars.destroy(); _mag.destroy(); _lav.destroy(); shrink_all(); goto_root(); } bool TDistinta_tree::set_root(const TCodice_articolo& str) { const bool ok = find(str, 1) != NULL; if (ok) { _root = str; restart(); } return ok; } bool TDistinta_tree::has_root() const { return _root.not_empty(); } bool TDistinta_tree::goto_root() { const bool ok = has_root(); if (ok) { _path = _root; _stack.destroy(); push_vars(); } return ok; } bool TDistinta_tree::is_cyclic(const TToken_string& path) const { bool cyclic = FALSE; const int last = path.items()-1; if (last > 0) { path.get(-2, _tmp); TCodice_articolo mycod; _tmp.get(0, mycod); for (int i = last-1; i >= 0; i--) { path.get(i, _tmp); isola_codice(_tmp); if (_tmp == mycod) { cyclic = TRUE; break; } } } return cyclic; } static int _sort_key; static int compare_rdist(const TObject** o1, const TObject** o2) { const TRectype* r1 = (const TRectype*)(*o1); const TRectype* r2 = (const TRectype*)(*o2); TString16 field; field << "SORT" << _sort_key; long k1 = r1->get_long(field); long k2 = r2->get_long(field); if (k1 == 0 && k2 == 0) { k1 = r1->get_long("NRIG"); k2 = r2->get_long("NRIG"); } else { if (k1 == 0) k1 = 100000000L; if (k2 == 0) k2 = 100000000L; } return k1 == k2 ? 0 : (k1 > k2 ? +1 : -1); } const TRectype* TDistinta_tree::find(const TCodice_articolo& father, int child) const { TString80 key = father; key << '|' << child; const TRectype& rec = ((TDistinta_tree*)this)->_rdist.get(key); return rec.empty() ? NULL : &rec; } int TDistinta_tree::build_children_list(const TCodice_articolo& father, TPointer_array& children) const { for (int nrig = 1; ; nrig++) { const TRectype* rec = find(father, nrig); if (rec == NULL) break; children.add((TRectype*)rec); } const int total = children.items(); if (total > 1) { _sort_key = _sort; children.sort(compare_rdist); } return total; } bool TDistinta_tree::has_son() const { if (_max_depth > 0) { const int depth = _path.items()-1; if (depth >= _max_depth) return FALSE; } if (is_cyclic()) return FALSE; TCodice_articolo key; curr_code(key); _curr = find(key, 1); // Se c'e' almeno un figlio ed e' necessario ordinare if (_curr != NULL && _sort > 0) { TPointer_array children; const int total = build_children_list(key, children); if (total > 1) _curr = (TRectype*)children.objptr(0); } return _curr != NULL; } void TDistinta_tree::add_child() { const char tipo = _curr->get_char("TIPO"); const TString& comp = _curr->get("CODCOMP"); if (tipo == 'V') _path.add(get_string(comp)); else _path.add(comp); // Codice articolo _path << ',' << _curr->get("LIVELLO");// Livello giacenza long num = _curr->get_long("NRIG"); _path << ',' << num; // Numero componente if (_sort > 0) { TString16 field; field << "SORT" << _sort; num = _curr->get_long(field); } _path << ',' << num; // Numero ordinamento _path << ',' << _curr->get("UM"); // Unita' di misura const TString& expr = _curr->get("EXPR"); const real qta = evaluate_numexpr(expr); _path << ',' << qta; // Quantita' push_vars(); } void TDistinta_tree::kill_child() { // Distrugge l'ultimo stack delle variabili pop_vars(); // Toglie l'ultimo elemento dal path const int pipe = _path.rfind('|'); _path.cut(pipe); } bool TDistinta_tree::goto_firstson() { const bool ok = has_son(); if (ok) add_child(); return ok; } bool TDistinta_tree::has_rbrother() const { const int last = _path.items()-1; if (last < 1) return FALSE; TString80 key; _path.get(last-1, key); isola_codice(key); const TCodice_articolo father(key); curr_comp(key); if (_sort > 0) { TPointer_array children; const int last = build_children_list(father, children)-1; if (last > 0) { for (int c = last; c >= 0; c--) { const TRectype& rec = (const TRectype&)children[c]; if (rec.get("NRIG") == key) break; } if (c >= 0 && c < last) _curr = &(TRectype&)children[c+1]; else _curr = NULL; } else _curr = NULL; } else { const int brother = atoi(key) + 1; _curr = find(father, brother); } return _curr != NULL; } bool TDistinta_tree::goto_rbrother() { const bool ok = has_rbrother(); if (ok) { kill_child(); add_child(); } return ok; } bool TDistinta_tree::has_lbrother() const { const int last = _path.items()-1; if (last < 1) return FALSE; TString80 key; _path.get(last-1, key); isola_codice(key); const TCodice_articolo father(key); curr_comp(key); if (_sort > 0) { TPointer_array children; const int last = build_children_list(father, children)-1; if (last > 0) { for (int c = last; c > 0; c--) { const TRectype& rec = (const TRectype&)children[c]; if (rec.get("NRIG") == key) break; } if (c > 0) _curr = &(TRectype&)children[c-1]; else _curr = NULL; } else _curr = NULL; } else { const int brother = atoi(key) - 1; if (brother > 0) _curr = find(father, brother); else _curr = NULL; } return _curr != NULL; } bool TDistinta_tree::goto_lbrother() { const bool ok = has_lbrother(); if (ok) { kill_child(); add_child(); } return ok; } bool TDistinta_tree::has_father() const { const int items = _path.items(); return items > 1; } bool TDistinta_tree::goto_father() { const bool ok = has_father(); if (ok) kill_child(); return ok; } bool TDistinta_tree::is_root() const { const int items = _path.items(); return items <= 1; } bool TDistinta_tree::is_leaf() const { TCodice_articolo key; curr_code(key); const TRectype* first_son = find(key, 1); return first_son == NULL; } bool TDistinta_tree::is_mag(const char* c) const { TCodice_articolo code = c; if (code.blank()) curr_code(code); const TString& desc = ((TDistinta_tree*)this)->_mag.decode(code); return desc.not_empty(); } bool TDistinta_tree::is_lav(const char* c) const { TCodice_articolo code = c; if (code.blank()) curr_code(code); const TString& desc = ((TDistinta_tree*)this)->_lav.decode(code); return desc.not_empty(); } char TDistinta_tree::get_type(const char* c) const { char type = 'V'; if (is_mag(c)) type = 'A'; else { if (is_lav(c)) type = 'L'; } return type; } void TDistinta_tree::set_sort_key(int k) { CHECK(k >= 0 && k <= 5, "Chiave distinta errata"); _sort = k; } TTypeexp TDistinta_tree::get_var_type(const char* var) { const TString& vt = _vars.decode(var); return vt.blank() ? _strexpr : _numexpr; } void TDistinta_tree::pop_vars() { _stack.pop(); } void TDistinta_tree::clear_globals() { _globals.destroy(); } void TDistinta_tree::set_global(const char* name, const char* val) { TString* str = new TString(val); _globals.add(name, str, TRUE); } void TDistinta_tree::set_global(const char* name, const real& val) { _globals.add(name, val, TRUE); } const TString& TDistinta_tree::get_string(const char* var) { for (int s = 0; s < _stack.count(); s++) { TAssoc_array& a = (TAssoc_array&)_stack.peek(s); TObject* val = a.objptr(var); if (val) { if (val->class_id() == CLASS_STRING) return (TString&)*val; } } TObject* val = _globals.objptr(var); if (val && val->class_id() == CLASS_STRING) return (TString&)*val; return EMPTY_STRING; } const real& TDistinta_tree::get_real(const char* var) { for (int s = 0; s < _stack.count(); s++) { TAssoc_array& a = (TAssoc_array&)_stack.peek(s); TObject* val = a.objptr(var); if (val) { if (val->class_id() != CLASS_STRING) return (real&)*val; } } TObject* val = _globals.objptr(var); if (val && val->class_id() != CLASS_STRING) return (real&)*val; return ZERO; } void TDistinta_tree::evaluate(TDistinta_expr& e) { for (int v = e.numvar()-1; v >= 0; v--) { const char* name = e.varname(v); const TTypeexp vartype = get_var_type(name); if (vartype == _numexpr) e.setvar(v, get_real(name)); else e.setvar(v, get_string(name)); } } real TDistinta_tree::evaluate_numexpr(const char* str) { TDistinta_expr e; e.set(str, _numexpr); evaluate(e); return e.as_real(); } void TDistinta_tree::evaluate_strexpr(const char* str, TString& res) { TDistinta_expr e; e.set(str, _strexpr); evaluate(e); res = e.as_string(); } void TDistinta_tree::push_vars() { TAssoc_array* vars = new TAssoc_array; _stack.push(vars); TCodice_articolo var; curr_code(var); const TString& memo_field = _dist.decode(var); if (!memo_field.blank()) { TString80 expr; TDistinta_expr e; TToken_string memo(memo_field, '\n'); for (const char* str = memo.get(0); str; str = memo.get()) { char* equal = strchr(str, '='); if (equal) { *equal = '\0'; var = str; expr = equal + 1; const TTypeexp exprtype = get_var_type(var); e.set(expr, exprtype); evaluate(e); if (exprtype == _numexpr) vars->add(var, e.as_real()); else vars->add(var, e.as_string()); } } } } struct TExplosion_params { TArray* _array; TString16 _filter; int _raggruppa; int _max_depth; int _sort_key; bool _materiali_base; bool _last_qta; }; static bool explode_callback(TTree& node, void* jolly, word when) { if (when == SCAN_PRE_ORDER) { TDistinta_tree& tree = (TDistinta_tree&)node; if (tree.is_root()) return FALSE; // Don't explode roots const TExplosion_params& ep = *(const TExplosion_params*)jolly; if (ep._materiali_base && !tree.is_leaf()) return FALSE; // Please, leaves only TRiga_esplosione er(tree, ep); const char type = er.tipo(); if (ep._filter.not_empty()) { if (ep._filter.find(type) < 0) return FALSE; } if (ep._sort_key > 0) { if (er.ordinamento() <= 0) return FALSE; // Non fa parte dell'ordinamento } ep._array->add(er); } return FALSE; } int TDistinta_tree::raggruppa(TArray& boom, int mode) const { for (int i = 0; i < boom.items(); i++) { TRiga_esplosione& qta1 = (TRiga_esplosione&)boom[i]; if (mode == 2) qta1.convert_to_base(); for (int j = boom.items()-1; j > i; j--) { TRiga_esplosione& qta2 = (TRiga_esplosione&)boom[j]; if (qta1.articolo() != qta2.articolo()) continue; if (mode == 3 && qta1.um() != qta2.um()) continue; qta1 += qta2; boom.destroy(j, TRUE); } } return boom.items(); } int TDistinta_tree::explode(TArray& boom, bool mb, int gr, int md, const char* filter, int sk, bool lq) { const int old_sk = get_sort_key(); const int old_md = get_max_depth(); if (mb) md = 0; set_sort_key(sk); set_max_depth(md); TExplosion_params ep; ep._array = &boom; ep._materiali_base = mb; ep._raggruppa = gr; ep._max_depth = md; ep._filter = filter; ep._sort_key = sk; ep._last_qta = lq; scan_depth_first(explode_callback, &ep); set_sort_key(old_sk); set_max_depth(old_md); if (gr) raggruppa(boom, gr); return boom.items(); } TDistinta_tree::TDistinta_tree() : _rdist(LF_RDIST), _sort(0), _max_depth(0), _dist(LF_DIST, "PARAMETRI"), _vars("VAR", "B0"), _mag(LF_ANAMAG, "DESCR"), _lav("LAV") { } TDistinta_tree::~TDistinta_tree() { } /////////////////////////////////////////////////////////// // TRiga_esplosione /////////////////////////////////////////////////////////// void TRiga_esplosione::init(const TDistinta_tree& tree, const TExplosion_params& ep) { TCodice_articolo art; tree.curr_code(art); TCodice_um um; tree.curr_um(um); real val = tree.curr_qta(ep._last_qta); set(art, um, val); tree.curr_giac(_giac); _tipo = tree.get_type(art); _sort = tree.curr_sort(); _livello = tree.curr_depth(); } TRiga_esplosione::TRiga_esplosione(const TDistinta_tree& tree, const TExplosion_params& ep) { init(tree, ep); } TRiga_esplosione::TRiga_esplosione(const TRiga_esplosione& re) : TQuantita(re) { _giac = re._giac; _tipo = re._tipo; _livello = re._livello; _sort = re._sort; }