source: tags/ms_r16q2/NTREE/NT_concatenate.cxx

Last change on this file was 14786, checked in by westram, 6 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.4 KB
Line 
1// =======================================================================================
2/*                                                                                       */
3//    File       : NT_concatenate.cxx
4//    Purpose    : 1.Concatenatenation of sequences or alignments
5//                 2.Merging the fields of similar species and creating a new species
6//    Author     : Yadhu Kumar
7//    web site   : http://www.arb-home.de/
8/*                                                                                       */
9//        Copyright Department of Microbiology (Technical University Munich)
10/*                                                                                       */
11// =======================================================================================
12
13#include "NT_local.h"
14
15#include <items.h>
16#include <item_sel_list.h>
17#include <awt_sel_boxes.hxx>
18#include <AW_rename.hxx>
19#include <aw_question.hxx>
20#include <aw_awar.hxx>
21#include <aw_msg.hxx>
22#include <aw_root.hxx>
23#include <arb_progress.h>
24#include <arb_strbuf.h>
25#include <arb_strarray.h>
26#include <awt_modules.hxx>
27#include <arb_global_defs.h>
28
29using namespace std;
30
31#define AWAR_CON_SEQUENCE_TYPE       "tmp/concat/sequence_type"
32#define AWAR_CON_NEW_ALIGNMENT_NAME  "tmp/concat/new_alignment_name"
33#define AWAR_CON_ALIGNMENT_SEPARATOR "tmp/concat/alignment_separator"
34#define AWAR_CON_SELECTED_ALI        "tmp/concat/database_alignments"
35#define AWAR_CON_MERGE_FIELD         "tmp/concat/merge_field"
36#define AWAR_CON_STORE_SIM_SP_NO     "tmp/concat/store_sim_sp_no"
37
38#define AWAR_CON_ALLOW_OVERWRITE_ALI   "tmp/concat/overwrite"
39#define AWAR_CON_INSGAPS_FOR_MISS_ALIS "tmp/concat/insgaps"
40
41#define MOVE_DOWN  0
42#define MOVE_UP    1
43
44struct SpeciesConcatenateList {
45    GBDATA *species;
46    char   *species_name;
47
48    SpeciesConcatenateList *next;
49};
50
51// --------------------------creating and initializing AWARS----------------------------------------
52void NT_createConcatenationAwars(AW_root *aw_root, AW_default aw_def, GBDATA *gb_main) {
53    GB_transaction ta(gb_main);
54
55    char *ali_default = GBT_get_default_alignment(gb_main);
56    char *ali_type    = NULL;
57
58    if (ali_default) {
59        ali_type = GBT_get_alignment_type_string(gb_main, ali_default);
60        if (!ali_type) {
61            // Note: this message will appear during startup (i.e. stick to general statement here!)
62            aw_message(GBS_global_string("Failed to detect type of default alignment (%s)\n"
63                                         "(Reason: %s)", ali_default, GB_await_error()));
64        }
65    }
66    if (!ali_type) ali_type = strdup("rna");
67
68    aw_root->awar_string(AWAR_CON_SEQUENCE_TYPE,       ali_type,         aw_def);
69    aw_root->awar_string(AWAR_CON_NEW_ALIGNMENT_NAME,  "ali_concat",     aw_def)->set_srt("ali_*=*:*=ali_*"); // auto-prefix with "ali_"
70    aw_root->awar_string(AWAR_CON_ALIGNMENT_SEPARATOR, "XXX",            aw_def);
71    aw_root->awar_string(AWAR_CON_SELECTED_ALI,        "",               aw_def);
72    aw_root->awar_string(AWAR_CON_MERGE_FIELD,         "full_name",      aw_def);
73    aw_root->awar_string(AWAR_CON_STORE_SIM_SP_NO,     "merged_species", aw_def);
74
75    aw_root->awar_int(AWAR_CON_ALLOW_OVERWRITE_ALI,   0, aw_def);
76    aw_root->awar_int(AWAR_CON_INSGAPS_FOR_MISS_ALIS, 1, aw_def);
77
78    free(ali_type);
79    free(ali_default);
80}
81
82// ------------------------Selecting alignments from the database for concatenation----------------------
83
84inline char *get_alitype_eval(AW_root *aw_root) {
85    return GBS_global_string_copy("%s=", aw_root->awar(AWAR_CON_SEQUENCE_TYPE)->read_char_pntr()); 
86}
87
88static void alitype_changed_cb(AW_root *aw_root, AW_DB_selection *db_sel) {
89    char *ali_type = get_alitype_eval(aw_root);
90    awt_reconfigure_ALI_selection_list(db_sel, ali_type);
91    free(ali_type);
92}
93
94static AW_DB_selection* createSelectionList(GBDATA *gb_main, AW_window *aws, const char *awarName) {
95
96#ifdef DEBUG
97    static bool ran=false;
98    nt_assert(!ran);
99    ran=true;                 // prevents calling this function for the second time
100#endif
101
102    AW_root         *aw_root  = aws->get_root();
103    char            *ali_type = get_alitype_eval(aw_root);
104    AW_DB_selection *db_sel   = awt_create_ALI_selection_list(gb_main, aws, awarName, ali_type);
105
106    free(ali_type);
107    return db_sel;
108}
109
110// ----------  Create SAI to display alignments that were concatenated --------------
111
112static GB_ERROR create_concatInfo_SAI(GBDATA *gb_main, const char *new_ali_name, const char *ali_separator, const StrArray& ali_names) {
113    GB_ERROR  error       = NULL;
114    GBDATA   *gb_extended = GBT_find_or_create_SAI(gb_main, "ConcatInfo");
115
116    if (!gb_extended) error = GB_await_error();
117    else {
118        GBDATA *gb_data = GBT_add_data(gb_extended, new_ali_name, "data", GB_STRING);
119
120        if (!gb_data) {
121            error = GB_await_error();
122        }
123        else {
124            int new_ali_length = GBT_get_alignment_len(gb_main, new_ali_name);
125            int sep_len        = strlen(ali_separator);
126
127            char *info = (char*)malloc(new_ali_length+1);
128            memset(info, '=', new_ali_length);
129
130            int offset       = 0;
131            int last_ali_idx = ali_names.size()-1;
132
133            for (int a = 0; a <= last_ali_idx; ++a) {
134                const char *ali         = ali_names[a];
135                int         ali_len     = GBT_get_alignment_len(gb_main, ali);
136                int         ali_str_len = strlen(ali);
137
138                char *my_info = info+offset;
139
140                int half_ali_len = ali_len/2;
141                for (int i = 0; i<5; ++i) {
142                    if (i<half_ali_len) {
143                        my_info[i]           = '<';
144                        my_info[ali_len-i-1] = '>';
145                    }
146                }
147
148                if (ali_str_len<ali_len) {
149                    int namepos = half_ali_len - ali_str_len/2;
150                    memcpy(my_info+namepos, ali, ali_str_len);
151                }
152
153                offset += ali_len;
154                if (a != last_ali_idx) {
155                    memcpy(info+offset, ali_separator, sep_len);
156                    offset += sep_len;
157                }
158            }
159
160            nt_assert(offset == new_ali_length); // wrong alignment length!
161            info[new_ali_length] = 0;
162           
163            if (!error) error = GB_write_string(gb_data, info);
164            free(info);
165        }
166    }
167    return error;
168}
169
170// ---------------------------------------- Concatenation function ----------------------------------
171static void concatenateAlignments(AW_window *aws, AW_selection *selected_alis) {
172    nt_assert(selected_alis);
173
174    GB_push_transaction(GLOBAL.gb_main);
175
176    long      marked_species = GBT_count_marked_species(GLOBAL.gb_main);
177    AW_root  *aw_root        = aws->get_root();
178    char     *new_ali_name   = aw_root->awar(AWAR_CON_NEW_ALIGNMENT_NAME)->read_string();
179    GB_ERROR  error          = GBT_check_alignment_name(new_ali_name);
180
181    StrArray ali_names;
182    selected_alis->get_values(ali_names);
183
184    arb_progress progress("Concatenating alignments", marked_species);
185    size_t       ali_count = ali_names.size();
186
187    if (!error && ali_count<2) {
188        error = "Not enough alignments selected for concatenation (need at least 2)";
189    }
190    if (!error) {
191        int found[ali_count], missing[ali_count], ali_length[ali_count];
192
193        for (size_t a = 0; a<ali_count; a++) {
194            found[a]      = 0;
195            missing[a]    = 0;
196            ali_length[a] = GBT_get_alignment_len(GLOBAL.gb_main, ali_names[a]);
197
198            if (strcmp(ali_names[a], new_ali_name) == 0) {
199                error = "Target alignment may not be one of the source alignments";
200            }
201        }
202
203        if (!error) {
204            char      *ali_separator = aw_root->awar(AWAR_CON_ALIGNMENT_SEPARATOR)->read_string();
205            const int  sep_len       = strlen(ali_separator);
206
207            long new_alignment_len = (ali_count-1)*sep_len;
208            for (size_t a = 0; a<ali_count; ++a) {
209                new_alignment_len += ali_length[a];
210            }
211
212            GBDATA *gb_presets          = GBT_get_presets(GLOBAL.gb_main);
213            GBDATA *gb_alignment_exists = GB_find_string(gb_presets, "alignment_name", new_ali_name, GB_IGNORE_CASE, SEARCH_GRANDCHILD);
214            GBDATA *gb_new_alignment    = 0;
215            char   *seq_type            = aw_root->awar(AWAR_CON_SEQUENCE_TYPE)->read_string();
216
217            if (gb_alignment_exists) {
218                // target alignment exists
219                if (aw_root->awar(AWAR_CON_ALLOW_OVERWRITE_ALI)->read_int()) { // allow overwrite
220                    gb_new_alignment             = GBT_get_alignment(GLOBAL.gb_main, new_ali_name);
221                    if (!gb_new_alignment) error = GB_await_error();
222                }
223                else {
224                    error = GBS_global_string("Target alignment '%s' already exists\n(check overwrite-toggle if you really want to overwrite)", new_ali_name);
225                }
226            }
227            else {
228                // create new target alignment
229                gb_new_alignment             = GBT_create_alignment(GLOBAL.gb_main, new_ali_name, new_alignment_len, 0, 0, seq_type);
230                if (!gb_new_alignment) error = GB_await_error();
231            }
232
233            if (!error) {
234                AW_repeated_question ask_about_missing_alignment;
235                bool                 insertGaps = aw_root->awar(AWAR_CON_INSGAPS_FOR_MISS_ALIS)->read_int();
236
237                for (GBDATA *gb_species = GBT_first_marked_species(GLOBAL.gb_main);
238                     gb_species && !error;
239                     gb_species = GBT_next_marked_species(gb_species))
240                {
241                    GBS_strstruct *str_seq       = GBS_stropen(new_alignment_len+1); // create output stream
242                    int            data_inserted = 0;
243
244                    for (size_t a = 0; a<ali_count; ++a) {
245                        if (a) GBS_strcat(str_seq, ali_separator);
246
247                        GBDATA *gb_seq_data = GBT_find_sequence(gb_species, ali_names[a]);
248                        if (gb_seq_data) { // found data
249                            const char *str_data = GB_read_char_pntr(gb_seq_data);
250                            GBS_strcat(str_seq, str_data);
251                            ++found[a];
252                            ++data_inserted;
253                        }
254                        else { // missing data
255                            if (insertGaps) GBS_chrncat(str_seq, '.', ali_length[a]);
256                            ++missing[a];
257                        }
258                    }
259
260                    if (!data_inserted) {
261                        error = GBS_global_string("None of the source alignments had data for species '%s'", GBT_read_name(gb_species));
262                    }
263                    else {
264                        char   *concatenated_ali_seq_data = GBS_strclose(str_seq);
265                        GBDATA *gb_data                   = GBT_add_data(gb_species, new_ali_name, "data", GB_STRING);
266
267                        GB_write_string(gb_data, concatenated_ali_seq_data);
268                        free(concatenated_ali_seq_data);
269                    }
270                    progress.inc_and_check_user_abort(error);
271                }
272
273                if (!error) {
274                    // ............. print missing alignments...........
275                    aw_message(GBS_global_string("Concatenation of alignments was performed for %ld species.", marked_species));
276                    for (size_t a = 0; a<ali_count; ++a) {
277                        aw_message(GBS_global_string("%s: was found in %d species and missing in %d species.", ali_names[a], found[a], missing[a]));
278                    }
279                }
280
281                if (!error) error = GBT_check_data(GLOBAL.gb_main, new_ali_name); // update alignment info (otherwise create_concatInfo_SAI fails when overwriting an alignment)
282                if (!error) error = create_concatInfo_SAI(GLOBAL.gb_main, new_ali_name, ali_separator, ali_names);
283            }
284
285            free(seq_type);
286            free(ali_separator);
287        }
288    }
289
290    if (!error) {
291        char *nfield = GBS_global_string_copy("%s/data", new_ali_name);
292        error        = GBT_add_new_changekey(GLOBAL.gb_main, nfield, GB_STRING);
293        free(nfield);
294    }
295    else {
296        progress.done();
297    }
298    GB_end_transaction_show_error(GLOBAL.gb_main, error, aw_message);
299    free(new_ali_name);
300}
301
302static void addSpeciesToConcatenateList(SpeciesConcatenateList **sclp, GB_CSTR species_name) {
303
304    GBDATA *gb_species_data = GBT_get_species_data(GLOBAL.gb_main);
305    GBDATA *gb_species      = GBT_find_species_rel_species_data(gb_species_data, species_name);
306
307    if (gb_species) {
308        SpeciesConcatenateList *scl = new SpeciesConcatenateList;
309
310        scl->species      = gb_species;
311        scl->species_name = strdup(species_name);
312        scl->next         = *sclp;
313        *sclp             = scl;
314    }
315}
316
317static void freeSpeciesConcatenateList(SpeciesConcatenateList *scl) {
318    while (scl) {
319        SpeciesConcatenateList *next = scl->next;
320        free(scl->species_name);
321        delete scl;
322        scl = next;
323    }
324}
325
326static GB_ERROR checkAndMergeFields(GBDATA *gb_new_species, GB_ERROR error, SpeciesConcatenateList *scl) {
327
328    char *doneFields = strdup(";name;"); // all fields which are already merged
329    int   doneLen    = strlen(doneFields);
330    SpeciesConcatenateList *sl = scl;
331    int  sl_length = 0; while (scl) { sl_length++; scl=scl->next; } // counting no. of similar species stored in the list
332    int *fieldStat = new int[sl_length]; // 0 = not used yet ; -1 = doesn't have field ; 1..n = field content (same number means same content)
333
334    while (sl && !error) { // with all species do..
335        char *newFields  = GB_get_subfields(sl->species);
336        char *fieldStart = newFields; // points to ; before next field
337
338        while (fieldStart[1] && !error) { // with all subfields of the species do..
339            char *fieldEnd = strchr(fieldStart+1, ';');
340            nt_assert(fieldEnd);
341            char behind = fieldEnd[1]; fieldEnd[1] = 0;
342
343            if (strstr(doneFields, fieldStart)==0) { // field is not merged yet
344                char *fieldName = fieldStart+1;
345                int   fieldLen  = int(fieldEnd-fieldName);
346
347                nt_assert(fieldEnd[0]==';');
348                fieldEnd[0] = 0;
349
350                GBDATA   *gb_field = GB_search(sl->species, fieldName, GB_FIND); // field does to exist (it was found before)
351                GB_TYPES  type     = GB_read_type(gb_field);
352
353                if (type==GB_STRING) { // we only merge string fields
354                    int i; int doneSpecies = 0; int nextStat = 1;
355
356                    for (i=0; i<sl_length; i++) { fieldStat[i] = 0; } // clear field status
357
358                    while (doneSpecies<sl_length) { // since all species in list were handled
359                        SpeciesConcatenateList *sl2 = sl;
360                        i = 0;
361
362                        while (sl2) {
363                            if (fieldStat[i]==0) {
364                                gb_field = GB_search(sl2->species, fieldName, GB_FIND);
365                                if (gb_field) {
366                                    char *content = GB_read_as_string(gb_field);
367                                    SpeciesConcatenateList *sl3 = sl2->next;
368                                    fieldStat[i] = nextStat;
369                                    int j = i+1; doneSpecies++;
370
371                                    while (sl3) {
372                                        if (fieldStat[j]==0) {
373                                            gb_field = GB_search(sl3->species, fieldName, GB_FIND);
374                                            if (gb_field) {
375                                                char *content2 = GB_read_as_string(gb_field);
376                                                if (strcmp(content, content2)==0) { // if contents are the same, they get the same status
377                                                    fieldStat[j] = nextStat;
378                                                    doneSpecies++;
379                                                }
380                                                free(content2);
381                                            }
382                                            else {
383                                                fieldStat[j] = -1;
384                                                doneSpecies++;
385                                            }
386                                        }
387                                        sl3 = sl3->next; j++;
388                                    }
389                                    free(content); nextStat++;
390                                }
391                                else {
392                                    fieldStat[i] = -1; // field does not exist here
393                                    doneSpecies++;
394                                }
395                            }
396                            sl2 = sl2->next; i++;
397                        }
398                        if (!sl2) break;
399                    }
400                    nt_assert(nextStat!=1); // this would mean that none of the species contained the field
401                    {
402                        char *new_content     = 0;
403                        int   new_content_len = 0; // @@@ useless (0 where used; unused otherwise)
404
405                        if (nextStat==2) { // all species contain same field content or do not have the field
406                            SpeciesConcatenateList *sl2 = sl;
407                            while (sl2) {
408                                gb_field = GB_search(sl2->species, fieldName, GB_FIND);
409                                if (gb_field) {
410                                    new_content = GB_read_as_string(gb_field);
411                                    new_content_len = strlen(new_content);
412                                    break;
413                                }
414                                sl2 = sl2->next;
415                            }
416                        }
417                        else { // different field contents
418                            int actualStat;
419                            for (actualStat=1; actualStat<nextStat; actualStat++) {
420                                int names_len = 1; // open bracket
421                                SpeciesConcatenateList *sl2 = sl;
422                                char *content = 0; i = 0;
423
424                                while (sl2) {
425                                    if (fieldStat[i]==actualStat) {
426                                        names_len += strlen(sl2->species_name)+1;
427                                        if (!content) {
428                                            gb_field = GB_search(sl2->species, fieldName, GB_FIND);
429                                            nt_assert(gb_field);
430                                            content = GB_read_as_string(gb_field);
431                                        }
432                                    }
433                                    sl2 = sl2->next; i++;
434                                }
435                                nt_assert(content);
436                                int add_len = names_len+1+strlen(content);
437                                char *whole = (char*)malloc(new_content_len+1+add_len+1);
438                                nt_assert(whole);
439                                char *add = new_content ? whole+sprintf(whole, "%s ", new_content) : whole;
440                                sl2 = sl; i = 0;
441                                int first = 1;
442                                while (sl2) {
443                                    if (fieldStat[i]==actualStat) {
444                                        add += sprintf(add, "%c%s", first ? '{' : ';', sl2->species_name);
445                                        first = 0;
446                                    }
447                                    sl2 = sl2->next; i++;
448                                }
449                                add += sprintf(add, "} %s", content);
450
451                                free(content);
452                                freeset(new_content, whole);
453                                new_content_len = strlen(new_content); // cppcheck-suppress deallocuse
454                            }
455                        }
456
457                        if (new_content) {
458                            error = GBT_write_string(gb_new_species, fieldName, new_content);
459                            free(new_content);
460                        }
461                    }
462                }
463
464                // mark field as done:
465                char *new_doneFields = (char*)malloc(doneLen+fieldLen+1+1);
466                sprintf(new_doneFields, "%s%s;", doneFields, fieldName);
467                doneLen += fieldLen+1;
468                freeset(doneFields, new_doneFields);
469                fieldEnd[0] = ';';
470            }
471            fieldEnd[1] = behind;
472            fieldStart = fieldEnd;
473        }
474        free(newFields);
475        sl = sl->next;
476    }
477    free(doneFields);
478    delete [] fieldStat;
479
480    return error;
481}
482
483static GBDATA *concatenateFieldsCreateNewSpecies(AW_window *, GBDATA *gb_species, SpeciesConcatenateList *scl) {
484    GB_push_transaction(GLOBAL.gb_main);
485
486    GB_ERROR  error           = 0;
487    GBDATA   *gb_species_data = GBT_get_species_data(GLOBAL.gb_main);
488
489    // data needed for name generation
490    char *full_name = 0;
491    char *acc       = 0;
492
493    // --------------------getting the species related data --------------------
494
495    GBDATA *gb_new_species = 0;
496
497    if (!error) {
498        // copy species to create a new species
499        gb_new_species = GB_create_container(gb_species_data, "species");
500        error          = gb_new_species ? GB_copy(gb_new_species, gb_species) : GB_await_error();
501
502        if (!error) { // write dummy-name (real name written below)
503            error = GBT_write_string(gb_new_species, "name", "$currcat$");
504        }
505    }
506
507    if (!error) { // copy full name
508        full_name             = GBT_read_string(gb_species, "full_name");
509        if (!full_name) error = GB_await_error();
510        else error            = GBT_write_string(gb_new_species, "full_name", full_name);
511    }
512
513    if (!error) {
514        ConstStrArray ali_names;
515        GBT_get_alignment_names(ali_names, GLOBAL.gb_main);
516
517        long id = 0;
518        for (SpeciesConcatenateList *speciesList = scl; speciesList; speciesList = speciesList->next) {
519            for (int no_of_alignments = 0; ali_names[no_of_alignments]!=0; no_of_alignments++) {
520                GBDATA *gb_seq_data = GBT_find_sequence(speciesList->species, ali_names[no_of_alignments]);
521                if (gb_seq_data) {
522                    const char *seq_data  = GB_read_char_pntr(gb_seq_data);
523                    GBDATA *gb_data = GBT_add_data(gb_new_species, ali_names[no_of_alignments], "data", GB_STRING);
524                    error           = GB_write_string(gb_data, seq_data);
525                    if (!error) id += GBS_checksum(seq_data, 1, ".-");  // creating checksum of the each aligned sequence to generate new accession number
526                }
527                if (error) error = GB_export_errorf("Can't create alignment '%s'", ali_names[no_of_alignments]);
528            }
529        }
530
531        if (!error) {
532            acc   = GBS_global_string_copy("ARB_%lX", id); // create new accession number
533            error = GBT_write_string(gb_new_species, "acc", acc);
534        }
535    }
536
537    if (!error) error = checkAndMergeFields(gb_new_species, error, scl);
538
539    // now generate new name
540    if (!error) {
541        char *new_species_name = 0;
542
543        const char *add_field = AW_get_nameserver_addid(GLOBAL.gb_main);
544        GBDATA     *gb_addid  = add_field[0] ? GB_entry(gb_new_species, add_field) : 0;
545        char       *addid     = 0;
546        if (gb_addid) addid   = GB_read_as_string(gb_addid);
547
548        error = AWTC_generate_one_name(GLOBAL.gb_main, full_name, acc, addid, new_species_name);
549        if (!error) {   // name was created
550            if (GBT_find_species_rel_species_data(gb_species_data, new_species_name) != 0) {
551                // if the name is not unique -> create unique name
552                UniqueNameDetector und(gb_species_data);
553                freeset(new_species_name, AWTC_makeUniqueShortName(new_species_name, und));
554                if (!new_species_name) error = GB_await_error();
555            }
556        }
557
558        if (!error) error = GBT_write_string(gb_new_species, "name", new_species_name); // insert new 'name'
559
560        free(new_species_name);
561        free(addid);
562    }
563
564    error = GB_end_transaction(GLOBAL.gb_main, error);
565    if (error) {
566        gb_new_species = 0;
567        aw_message(error);
568    }
569
570    free(acc);
571    free(full_name);
572
573    return gb_new_species;
574}
575
576enum MergeSpeciesType {
577    MERGE_SPECIES_SIMPLE,
578    MERGE_SPECIES_AND_CONCAT_ALI,
579};
580
581static void mergeSimilarSpecies(AW_window *aws, MergeSpeciesType mergeType, AW_selection *selected_alis) {
582    nt_assert(correlated(selected_alis, mergeType == MERGE_SPECIES_AND_CONCAT_ALI));
583
584    GB_ERROR     error = NULL;
585    arb_progress wrapper;
586    {
587        AW_root *aw_root          = aws->get_root();
588        char    *merge_field_name = aw_root->awar(AWAR_CON_MERGE_FIELD)->read_string();
589
590        SpeciesConcatenateList *scl            = 0; // to build list of similar species
591        SpeciesConcatenateList *newSpeciesList = 0;  // new SpeciesConcatenateList
592
593        GB_begin_transaction(GLOBAL.gb_main);       // open database for transaction
594
595        const char *report_field_name = prepare_and_get_selected_itemfield(aw_root, AWAR_CON_STORE_SIM_SP_NO, GLOBAL.gb_main, SPECIES_get_selector(), FIF_NAME_SELECTED);
596        if (!report_field_name && GB_have_error()) error = GB_await_error();
597
598        if (!error && strcmp(merge_field_name, NO_FIELD_SELECTED) == 0) {
599            error = "Please select database field for similarity detection";
600        }
601
602        if (!error) {
603            PersistentNameServerConnection stayAlive;
604            arb_progress progress("Merging similar species", GBT_count_marked_species(GLOBAL.gb_main));
605            progress.auto_subtitles("Species");
606
607            for (GBDATA * gb_species = GBT_first_marked_species(GLOBAL.gb_main);
608                 gb_species && !error;
609                 gb_species = GBT_next_marked_species(gb_species))
610            {
611                GBDATA     *gb_species_field = GB_entry(gb_species, merge_field_name);
612                const char *name             = GBT_read_name(gb_species);
613
614                if (!gb_species_field) {
615                    // exit if species doesn't have any data in the selected field
616                    error = GBS_global_string("Species '%s' does not contain data in selected field '%s'", name, merge_field_name);
617                }
618                else {
619                    char *gb_species_field_content = GB_read_as_string(gb_species_field);
620                    int   similar_species          = 0;
621
622                    for (GBDATA * gb_species_next = GBT_next_marked_species(gb_species);
623                         gb_species_next && !error;
624                         gb_species_next = GBT_next_marked_species(gb_species_next))
625                    {
626                        GBDATA     *gb_next_species_field = GB_entry(gb_species_next, merge_field_name);
627                        const char *next_name             = GBT_read_name(gb_species_next);
628
629                        if (!gb_next_species_field) {
630                            // exit if species doesn't have any data in the selected field
631                            error = GBS_global_string("Species '%s' does not contain data in selected field '%s'", next_name, merge_field_name);
632                        }
633                        else {
634                            char *gb_next_species_field_content = GB_read_as_string(gb_next_species_field);
635
636                            if (strcmp(gb_species_field_content, gb_next_species_field_content) == 0) {
637                                addSpeciesToConcatenateList(&scl, next_name);
638                                GB_write_flag(gb_species_next, 0);
639                                ++similar_species;
640                                ++progress;
641                            }
642                            free(gb_next_species_field_content);
643                        }
644                    }
645
646                    if (similar_species > 0 && !error) {
647                        ++similar_species; // correct merge counter
648                        addSpeciesToConcatenateList(&scl, name);
649                        GB_write_flag(gb_species, 0);
650
651                        GBDATA *new_species_created = concatenateFieldsCreateNewSpecies(aws, gb_species, scl);
652
653                        nt_assert(new_species_created);
654                        if (new_species_created) {      // create a list of newly created species
655                            addSpeciesToConcatenateList(&newSpeciesList, GBT_read_name(new_species_created));
656                        }
657
658                        if (report_field_name) {
659                            GBDATA *gb_report     = GBT_searchOrCreate_itemfield_according_to_changekey(new_species_created, report_field_name, SPECIES_get_selector().change_key_path);
660                            if (!gb_report) error = GB_await_error();
661                            else    error         = GB_write_lossless_int(gb_report, similar_species);
662                        }
663                    }
664
665                    freeSpeciesConcatenateList(scl); scl = 0;
666                    free(gb_species_field_content);
667                }
668
669                progress.inc_and_check_user_abort(error);
670            }
671        }
672
673        if (!error) {
674            GBT_mark_all(GLOBAL.gb_main, 0);        // unmark all species in the database
675            int newSpeciesCount = 0;
676
677            for (; newSpeciesList; newSpeciesList = newSpeciesList->next) { // mark only newly created species
678                GB_write_flag(newSpeciesList->species, 1);
679                newSpeciesCount++;
680            }
681            aw_message(GBS_global_string("%i new species were created by taking \"%s\" as a criterion!", newSpeciesCount, merge_field_name));
682            freeSpeciesConcatenateList(newSpeciesList);
683        }
684
685        free(merge_field_name);
686
687        GB_end_transaction_show_error(GLOBAL.gb_main, error, aw_message);
688    }
689
690    if (mergeType == MERGE_SPECIES_AND_CONCAT_ALI && !error) {
691        // @@@ what happens if merge-process above succeeds and concatenateAlignments below fails?
692        // @@@ i think both steps should be put into ONE transaction!
693        concatenateAlignments(aws, selected_alis);
694    }
695}
696
697static AW_window *createMergeSimilarSpeciesWindow(AW_root *aw_root, MergeSpeciesType mergeType, AW_selection *selected_alis) {
698    AW_window_simple *aws = new AW_window_simple;
699
700    {
701        char       *window_id    = GBS_global_string_copy("MERGE_SPECIES_%i", mergeType);
702        const char *window_title = NULL;
703        switch (mergeType) {
704            case MERGE_SPECIES_SIMPLE:         window_title = "Merge species";         break;
705            case MERGE_SPECIES_AND_CONCAT_ALI: window_title = "Merge and concatenate"; break;
706        }
707        aws->init(aw_root, window_id, window_title);
708        free(window_id);
709    }
710    aws->load_xfig("merge_species.fig");
711
712    aws->callback(makeHelpCallback("merge_species.hlp"));
713    aws->at("help");
714    aws->create_button("HELP", "HELP", "H");
715
716    create_itemfield_selection_button(aws, FieldSelDef(AWAR_CON_MERGE_FIELD,     GLOBAL.gb_main, SPECIES_get_selector(), FIELD_FILTER_STRING_READABLE, "field to compare"),           "field_select");
717    create_itemfield_selection_button(aws, FieldSelDef(AWAR_CON_STORE_SIM_SP_NO, GLOBAL.gb_main, SPECIES_get_selector(), FIELD_FILTER_INT_WRITEABLE,   "report-field", SF_ALLOW_NEW), "store_sp_no");
718
719    {
720        const char *buttonText = NULL;
721        switch (mergeType) {
722            case MERGE_SPECIES_SIMPLE:         buttonText = "Merge similar species";                       break;
723            case MERGE_SPECIES_AND_CONCAT_ALI: buttonText = "Merge similar species and concat alignments"; break;
724        }
725
726        aws->at("merge");
727        aws->callback(makeWindowCallback(mergeSimilarSpecies, mergeType, selected_alis));
728        aws->create_autosize_button("MERGE_SIMILAR_SPECIES", buttonText, "M");
729    }
730
731    aws->at("close");
732    aws->callback(AW_POPDOWN);
733    aws->create_button("CLOSE", "CLOSE", "C");
734
735    return aws;
736}
737
738AW_window *NT_createMergeSimilarSpeciesWindow(AW_root *aw_root) {
739    static AW_window *aw = 0;
740    if (!aw) aw = createMergeSimilarSpeciesWindow(aw_root, MERGE_SPECIES_SIMPLE, NULL);
741    return aw;
742}
743
744static AW_window *NT_createMergeSimilarSpeciesAndConcatenateWindow(AW_root *aw_root, AW_selection *selected_alis) {
745    static AW_window *aw = NULL;
746#if defined(ASSERTION_USED)
747    static AW_selection *prev_selected_alis = NULL;
748#endif
749
750    if (!aw) {
751        aw = createMergeSimilarSpeciesWindow(aw_root, MERGE_SPECIES_AND_CONCAT_ALI, selected_alis);
752#if defined(ASSERTION_USED)
753        prev_selected_alis = selected_alis;
754#endif
755    }
756#if defined(ASSERTION_USED)
757    nt_assert(selected_alis == prev_selected_alis); // would need multiple windows in that case
758#endif
759    return aw;
760}
761
762static void useSelectedAlignment(AW_window *aww) {
763    AW_root    *root   = aww->get_root();
764    const char *selali = root->awar(AWAR_CON_SELECTED_ALI)->read_char_pntr();
765    if (selali && strcmp(selali, NO_ALI_SELECTED) != 0) {
766        root->awar(AWAR_CON_NEW_ALIGNMENT_NAME)->write_string(selali);
767    }
768    else {
769        aw_message("Select alignment to use in the left alignment list");
770    }
771}
772
773// ----------------------------Creating concatenation window-----------------------------------------
774AW_window *NT_createConcatenationWindow(AW_root *aw_root) {
775    AW_window_simple *aws = new AW_window_simple;
776
777    aws->init(aw_root, "CONCAT_ALIGNMENTS", "Concatenate Alignments");
778    aws->load_xfig("concatenate.fig");
779
780    aws->auto_space(5, 5);
781    aws->button_length(8);
782
783    aws->callback(makeHelpCallback("concatenate.hlp"));
784    aws->at("help");
785    aws->create_button("HELP", "HELP", "H");
786
787    aws->at("close");
788    aws->callback(AW_POPDOWN);
789    aws->create_button("CLOSE", "CLOSE", "C");
790
791    aws->at("dbAligns");
792    AW_DB_selection *all_alis = createSelectionList(GLOBAL.gb_main, aws, AWAR_CON_SELECTED_ALI);
793    AW_selection    *sel_alis = awt_create_subset_selection_list(aws, all_alis->get_sellist(), "concatAligns", "collect", "sort");
794
795    aws->at("type");
796    aws->create_option_menu(AWAR_CON_SEQUENCE_TYPE, true);
797    aws->insert_option("DNA", "d", "dna");
798    aws->insert_option("RNA", "r", "rna");
799    aws->insert_default_option("PROTEIN", "p", "ami");
800    aws->update_option_menu();
801    aw_root->awar(AWAR_CON_SEQUENCE_TYPE)->add_callback(makeRootCallback(alitype_changed_cb, all_alis));
802
803    aws->at("aliSeparator");
804    aws->create_input_field(AWAR_CON_ALIGNMENT_SEPARATOR, 10);
805
806    aws->at("aliName");
807    aws->create_input_field(AWAR_CON_NEW_ALIGNMENT_NAME, 25);
808    aws->button_length(5);
809    aws->callback(useSelectedAlignment);
810    aws->create_button("USE", "Use");
811
812    aws->at("overwrite");
813    aws->label("Allow to overwrite an existing alignment?");
814    aws->create_toggle(AWAR_CON_ALLOW_OVERWRITE_ALI);
815
816    aws->at("insgaps");
817    aws->label("Insert gaps for missing alignment data?");
818    aws->create_toggle(AWAR_CON_INSGAPS_FOR_MISS_ALIS);
819
820    aws->button_length(22);
821    aws->at("go");
822
823    aws->callback(makeWindowCallback(concatenateAlignments, sel_alis));
824    aws->create_button("CONCATENATE", "CONCATENATE", "A");
825
826    aws->callback(NT_createMergeSimilarSpeciesWindow);
827    aws->create_button("MERGE_SPECIES", "MERGE SIMILAR SPECIES", "M");
828
829    aws->callback(makeCreateWindowCallback(NT_createMergeSimilarSpeciesAndConcatenateWindow, sel_alis));
830    aws->create_button("MERGE_CONCATENATE", "MERGE & CONCATENATE", "S");
831
832    return aws;
833}
834// -------------------------------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.