source: trunk/SL/TREE_READ/LabelTranslator.cxx

Last change on this file was 19910, checked in by westram, 3 weeks ago
File size: 5.5 KB
Line 
1// ========================================================= //
2//                                                           //
3//   File      : LabelTranslator.cxx                         //
4//   Purpose   : Translate tree labels                       //
5//                                                           //
6//   Coded by Ralf Westram (coder@reallysoft.de) in Sep 21   //
7//   http://www.arb-home.de/                                 //
8//                                                           //
9// ========================================================= //
10
11#include "LabelTranslator.h"
12#include <TreeNode.h>
13#include <gb_aci.h>
14#include <arb_unordered_set.h>
15
16using namespace std;
17
18typedef arb_unordered_set<string> StringSet;
19
20class TranslationReport : virtual Noncopyable {
21    StringSet translatedLabels;
22
23public:
24    GB_ERROR notify_translate_label(string label) { // @@@ !also pass input translation
25        // returns error if labels found in tree are not unique
26        StringSet::const_iterator found = translatedLabels.find(label);
27        if (found != translatedLabels.end()) {
28            return GBS_global_string("Encountered duplicated label '%s' in tree.", label.c_str());
29        }
30        translatedLabels.insert(label);
31        return NULp;
32    }
33};
34
35
36GB_ERROR LabelTranslator::translate_unlinked_labels_in_tree(TreeNode *tree, TranslationReport& report) const {
37    GB_ERROR error = NULp;
38    if (tree->is_leaf()) {
39        if (!tree->gb_node) { // only translate unlinked leafs (i.e. not-yet-linked nodes or real zombies)
40            error = report.notify_translate_label(tree->name); // @@@ !need to do duplication check for original label (from tree) and for aci-modified label.
41            if (!error) {
42                ErrorOrLabel translation   = translate(tree->name);
43                if (translation.hasError()) {
44                    error = translation.getError().deliver(); // @@@R instead use ARB_ERROR in translate_unlinked_labels_in_tree?
45                }
46                else {
47                    string translated = translation.getValue();
48                    if (translated != tree->name) {
49                        freedup(tree->name, translated.c_str());
50                    }
51                    // @@@L count translated (into report?)
52                }
53            }
54        }
55    }
56    else {
57        error             = translate_unlinked_labels_in_tree(tree->get_leftson(), report);
58        if (!error) error = translate_unlinked_labels_in_tree(tree->get_rightson(), report);
59    }
60    return error;
61}
62
63inline bool generated_by_multiple_species(const char *species_list) {
64    return strchr(species_list, ',') != NULp;
65}
66
67ErrorOrLabel ACI_LabelTranslator::translate(const char *label) const {
68    StringMap::const_iterator found = identifier2shortname.find(label);
69    if (found != identifier2shortname.end()) {
70        const char *species_id = found->second.c_str();
71        if (generated_by_multiple_species(species_id)) {
72            return ErrorOrLabel(GBS_global_string("label '%s' is ambiguous (generated for multiple species: %s)", label, species_id), "");
73        }
74        return ErrorOrLabel(NULp, species_id);
75    }
76
77    // @@@ !need to make sure 'label' is not a species name (otherwise would accidentally link)
78    // @@@L add option to ACI_LabelTranslator: refuse unmatched translation -> bail out with error here.
79    return ErrorOrLabel(NULp, label); // no translation found -> return original
80}
81
82GB_ERROR ACI_LabelTranslator::generate_species_identifiers(GBDATA *gb_main) const {
83    GB_transaction ta(gb_main);
84    GB_ERROR       error = NULp;
85
86    if (ta.ok()) {
87        GBL_env env(gb_main, NULp);  // @@@ pass treename?
88
89        for (GBDATA *gb_species = GBT_first_species(gb_main);
90             gb_species && !error;
91             gb_species = GBT_next_species(gb_species))
92        {
93            GBL_call_env  callEnv(gb_species, env);
94            char         *identifier = GB_command_interpreter_in_env("", species_aci.c_str(), callEnv);
95            const char   *shortname  = GBT_get_name(gb_species);
96
97            if (!identifier) {
98                error = GB_await_error();
99            }
100            else {
101                if (!identifier[0]) {
102                    error = GBS_global_string("empty identifier generated (for species '%s')", shortname);
103                }
104                else {
105                    StringMap::const_iterator found = identifier2shortname.find(identifier);
106                    if (found != identifier2shortname.end()) {
107                        const string& prev_shortnames = found->second;
108                        identifier2shortname[identifier] = prev_shortnames+','+shortname;
109                    }
110                    else {
111                        identifier2shortname[identifier] = shortname;
112                    }
113                }
114                free(identifier);
115            }
116        }
117    }
118
119    error = ta.close(error);
120
121    return error;
122}
123
124GB_ERROR TREE_translate_labels(GBDATA *gb_main, TreeNode *tree, const LabelTranslator& translator) {
125    // @@@R make this a member of LabelTranslator.
126    // @@@R afterwards: make most of class interfaces private.
127
128    GB_ERROR error = NULp;
129
130    error = translator.generate_species_identifiers(gb_main); // @@@L ensure this is performed only once!
131
132    if (!error) {
133        // translate all unlinked labels in tree:
134        TranslationReport report;
135        error = translator.translate_unlinked_labels_in_tree(tree, report);
136    }
137
138    if (error) {
139        error = GBS_global_string("failed to translate tree labels: %s", error);
140    }
141
142    return error;
143}
144
Note: See TracBrowser for help on using the repository browser.