source: tags/ms_r16q2/PROBE_DESIGN/probe_design.cxx

Last change on this file was 14772, checked in by westram, 8 years ago
  • tweaked 'Check server'
    • use '-h' with df and ls (=human-readable size-info)
    • also show content/freespace for ~/.arb_pts
    • quote used directories (fixes problems with spaces etc.)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 110.3 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : probe_design.cxx                                  //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "SaiProbeVisualization.hxx"
12#include "probe_match_parser.hxx"
13
14#include <PT_com.h>
15#include <PT_server.h> // needed for DOMAIN_MIN_LENGTH
16#include <client.h>
17#include <servercntrl.h>
18#include <probe_gui.hxx>
19#include <probe_local.hxx>
20
21#include <GEN.hxx>
22#include <TreeCallbacks.hxx>
23
24#include <iupac.h>
25#include <awt_config_manager.hxx>
26#include <awt_sel_boxes.hxx>
27#include <awt_misc.hxx>
28
29#include <aw_awars.hxx>
30#include <aw_preset.hxx>
31#include <aw_select.hxx>
32#include <aw_msg.hxx>
33#include <aw_root.hxx>
34#include <aw_question.hxx>
35#include <aw_edit.hxx>
36#include <rootAsWin.h>
37
38#include <adGene.h>
39
40#include <arb_progress.h>
41#include <arb_strbuf.h>
42#include <arb_strarray.h>
43#include <arb_file.h>
44#include <arb_misc.h>
45
46#include "probe_collection.hxx"
47
48// general awars
49
50#define AWAR_PROBE_CREATE_GENE_SERVER "tmp/probe_admin/gene_server" // whether to create a gene pt server
51
52// probe match awars
53
54// #define AWAR_PD_MATCH_ITEM     AWAR_SPECIES_NAME
55#define AWAR_PD_SELECTED_MATCH "tmp/probe_design/match"
56#define AWAR_PD_MATCH_RESOLVE  "tmp/probe_design/match_resolve" // for IUPAC resolution
57
58#define AWAR_PD_MATCH_SORTBY     "probe_match/sort_by" // weighted mismatches
59#define AWAR_PD_MATCH_COMPLEMENT "probe_match/complement" // check reverse complement too
60#define AWAR_PD_MATCH_MARKHITS   "probe_match/mark_hits" // mark hitten species in database
61#define AWAR_PD_MATCH_WRITE2TMP  "probe_match/write_2_tmp" // write result to field tmp
62#define AWAR_PD_MATCH_AUTOMATCH  "probe_match/auto_match" // auto match probes when target string changes
63
64#define AWAR_PD_MATCH_NHITS    "tmp/probe_match/nhits" // display the 'number of hits'
65
66// probe design awars
67
68#define AWAR_PD_DESIGN_CLIPRESULT "probe_design/CLIPRESULT" // 'length of output' (how many probes will get designed)
69#define AWAR_PD_DESIGN_MISHIT     "probe_design/MISHIT"     // 'non group hits'
70#define AWAR_PD_DESIGN_MAXBOND    "probe_design/MAXBOND"    // max hairpinbonds ?
71#define AWAR_PD_DESIGN_MINTARGETS "probe_design/MINTARGETS" // 'min. group hits (%)'
72
73#define AWAR_PD_DESIGN_MIN_LENGTH "probe_design/PROBELENGTH"      // min. length of probe
74#define AWAR_PD_DESIGN_MAX_LENGTH "probe_design/PROBEMAXLENGTH"   // max. length of probe (or empty)
75
76#define AWAR_PD_DESIGN_MIN_TEMP     "probe_design/MINTEMP"     // temperature (min)
77#define AWAR_PD_DESIGN_MAX_TEMP     "probe_design/MAXTEMP"     // temperature (max)
78#define AWAR_PD_DESIGN_MIN_GC       "probe_design/MINGC"       // GC content (min)
79#define AWAR_PD_DESIGN_MAX_GC       "probe_design/MAXGC"       // GC content (max)
80#define AWAR_PD_DESIGN_MIN_ECOLIPOS "probe_design/MINECOLI"    // ecolipos (min)
81#define AWAR_PD_DESIGN_MAX_ECOLIPOS "probe_design/MAXECOLI"    // ecolipos (max)
82
83#define AWAR_PD_DESIGN_GENE "probe_design/gene" // generate probes for genes ?
84
85// probe design/match (expert window)
86#define AWAR_PD_COMMON_EXP_BONDS_FORMAT "probe_design/bonds/pos%i"  // format to generate bond awar names
87#define AWAR_PD_COMMON_EXP_SPLIT        "probe_design/SPLIT"
88
89#define AWAR_PD_DESIGN_EXP_DTEDGE "probe_design/DTEDGE"
90#define AWAR_PD_DESIGN_EXP_DT     "probe_design/DT"
91
92#define AWAR_PD_MATCH_NMATCHES   "probe_match/nmatches"
93#define AWAR_PD_MATCH_LIM_NMATCH "probe_match/lim_nmatch"
94#define AWAR_PD_MATCH_MAX_RES    "probe_match/maxres"
95
96// --------------------------------
97// probe collection awars
98
99// probe collection window
100#define AWAR_PC_TARGET_STRING      "probe_collection/target_string"
101#define AWAR_PC_TARGET_NAME        "probe_collection/target_name"
102#define AWAR_PC_MATCH_WEIGHTS      "probe_collection/match_weights/pos"
103#define AWAR_PC_MATCH_WIDTH        "probe_collection/match_weights/width"
104#define AWAR_PC_MATCH_BIAS         "probe_collection/match_weights/bias"
105#define AWAR_PC_AUTO_MATCH         "probe_collection/auto"
106#define AWAR_PC_CURRENT_COLLECTION "probe_collection/current"
107
108#define AWAR_PC_SELECTED_PROBE     "tmp/probe_collection/probe"
109#define AWAR_PC_MATCH_NHITS        "tmp/probe_collection/nhits"
110
111// probe collection matching control parameters
112#define AWAR_PC_MISMATCH_THRESHOLD "probe_collection/mismatch_threshold"
113
114#define REPLACE_TARGET_CONTROL_CHARS ":#=_:\\:=_"
115
116// ----------------------------------------
117
118static saiProbeData *g_spd = 0;
119
120static struct {
121    aisc_com          *link;
122    T_PT_LOCS          locs;
123    T_PT_MAIN          com;
124    AW_window_simple  *win;
125    AW_selection_list *resultList; // @@@ replace by TypedSelectionList?
126} PD;
127
128struct ProbeMatchEventParam : virtual Noncopyable {
129    GBDATA            *gb_main;
130    AW_selection_list *selection_id;                // may be NULL
131    int               *counter;                     // may be NULL (if != NULL -> afterwards contains number of hits)
132
133    // results set by probe_match_event:
134    std::string hits_summary; // shown in probe match window
135    bool        refresh_sai_display;
136
137    void init_results() {
138        refresh_sai_display = false;
139    }
140
141    ProbeMatchEventParam(GBDATA *gb_main_, int *counter_)         : gb_main(gb_main_), selection_id(NULL), counter(counter_) { init_results(); }
142    ProbeMatchEventParam(GBDATA *gb_main_, AW_selection_list *id) : gb_main(gb_main_), selection_id(id),   counter(NULL)     { init_results(); }
143};
144
145struct AutoMatchSettings {
146    ProbeMatchEventParam *event_param; // not owned!
147    bool                  disable;
148
149    AutoMatchSettings(ProbeMatchEventParam *event_param_, bool disable_)
150        : event_param(event_param_), disable(disable_)
151    {}
152    AutoMatchSettings()
153        : event_param(NULL) , disable(true)
154    {}
155
156    bool initialized() const { return event_param != NULL; }
157};
158
159static AutoMatchSettings auto_match_cb_settings;
160
161// prototypes:
162static void probe_match_event_using_awars(AW_root *root, ProbeMatchEventParam *event_param);
163
164static void auto_match_cb(AW_root *root) {
165    if (!auto_match_cb_settings.disable) {
166        char *ts = root->awar(AWAR_TARGET_STRING)->read_string();
167        if (strlen(ts) > 0) {
168            probe_match_event_using_awars(root, auto_match_cb_settings.event_param);
169        }
170        free(ts);
171    }
172}
173
174static const char *auto_match_sensitive_awars[] = {
175    AWAR_TARGET_STRING,
176    AWAR_PT_SERVER,
177    AWAR_PD_MATCH_COMPLEMENT,
178    AWAR_MAX_MISMATCHES,
179    AWAR_PD_MATCH_SORTBY,
180    0
181};
182
183static void auto_match_changed(AW_root *root) {
184    static bool callback_active = false;
185    int         autoMatch       = root->awar(AWAR_PD_MATCH_AUTOMATCH)->read_int();
186
187    if (autoMatch) {
188        if (!callback_active) {
189            for (int i = 0; auto_match_sensitive_awars[i]; ++i) {
190                root->awar(auto_match_sensitive_awars[i])->add_callback(auto_match_cb);
191            }
192        }
193    }
194    else {
195        if (callback_active) {
196            for (int i = 0; auto_match_sensitive_awars[i]; ++i) {
197                root->awar(auto_match_sensitive_awars[i])->remove_callback(auto_match_cb);
198            }
199        }
200    }
201    callback_active = bool(autoMatch);
202}
203
204static void enable_auto_match_cb(AW_root *root, ProbeMatchEventParam *event_param) {
205    if (event_param == NULL && auto_match_cb_settings.initialized()) {
206        // "partially" enable (w/o ProbeMatchEventParam) is only done
207        // if not already "fully enabled"
208        return;
209    }
210
211    auto_match_cb_settings = AutoMatchSettings(event_param, false);
212    auto_match_changed(root);
213}
214
215static void popup_match_window_cb(AW_window *aww, GBDATA *gb_main) { // @@@ shall be called by auto_match_cb (if never opened b4)
216    AW_root   *root         = aww->get_root();
217    AW_window *match_window = create_probe_match_window(root, gb_main);
218    match_window->activate();
219    root->awar(AWAR_TARGET_STRING)->touch(); // force re-match
220}
221
222// --------------------------------------------------------------------------------
223
224static void popup_probe_design_result_window(AW_window *aww, GBDATA *gb_main) {
225    if (!PD.win) {
226        AW_root *root = aww->get_root();
227
228        PD.win = new AW_window_simple;
229        PD.win->init(root, "PD_RESULT", "PD RESULT");
230        PD.win->load_xfig("pd_reslt.fig");
231
232        PD.win->button_length(6);
233        PD.win->auto_space(10, 10);
234
235        PD.win->at("help");
236        PD.win->callback(makeHelpCallback("probedesignresult.hlp"));
237        PD.win->create_button("HELP", "HELP", "H");
238
239        PD.win->at("result");
240        PD.resultList = PD.win->create_selection_list(AWAR_TARGET_STRING, 40, 5, false);
241        const StorableSelectionList *storable_result_list = new StorableSelectionList(TypedSelectionList("prb", PD.resultList, "designed probes", "designed")); // @@@ make member of PD ?
242
243        PD.resultList->clear();
244        PD.resultList->insert_default("No probes designed yet", "");
245
246        PD.win->at("buttons");
247
248        PD.win->callback(AW_POPDOWN);
249        PD.win->create_button("CLOSE", "CLOSE", "C");
250
251        PD.win->callback(makeWindowCallback(awt_clear_selection_list_cb, PD.resultList));
252        PD.win->create_button("CLEAR", "CLEAR", "R");
253
254        PD.win->callback(makeCreateWindowCallback(create_load_box_for_selection_lists, storable_result_list));
255        PD.win->create_button("LOAD", "LOAD", "L");
256
257        PD.win->callback(makeCreateWindowCallback(create_save_box_for_selection_lists, storable_result_list));
258        PD.win->create_button("SAVE", "SAVE", "S");
259
260        PD.win->callback(makeWindowCallback(create_print_box_for_selection_lists, &storable_result_list->get_typedsellist()));
261        PD.win->create_button("PRINT", "PRINT", "P");
262
263        PD.win->callback(makeWindowCallback(popup_match_window_cb, gb_main));
264        PD.win->create_button("MATCH", "MATCH", "M");
265
266        PD.win->label("Auto match");
267        PD.win->create_toggle(AWAR_PD_MATCH_AUTOMATCH);
268
269        enable_auto_match_cb(root, NULL);
270    }
271    PD.win->activate();
272}
273
274static int init_local_com_struct() {
275    const char *user = GB_getenvUSER();
276
277    if (aisc_create(PD.link, PT_MAIN, PD.com,
278                    MAIN_LOCS, PT_LOCS, PD.locs,
279                    LOCS_USER, user,
280                    NULL)) {
281        return 1;
282    }
283    return 0;
284}
285
286static const char *PD_probe_pt_look_for_server(int serverNumber, GB_ERROR& error) {
287    // return PT server info string (see GBS_read_arb_tcp for details)
288    // or NULL (in this case 'error' is set)
289
290    // DRY vs  ../TOOLS/arb_probe.cxx@AP_probe_pt_look_for_server
291    // DRY vs  ../MULTI_PROBE/MP_noclass.cxx@MP_probe_pt_look_for_server
292
293    const char *result     = 0;
294    const char *server_tag = GBS_ptserver_tag(serverNumber);
295
296    error = arb_look_and_start_server(AISC_MAGIC_NUMBER, server_tag);
297    if (!error) {
298        result             = GBS_read_arb_tcp(server_tag);
299        if (!result) error = GB_await_error();
300    }
301    pd_assert(contradicted(result, error));
302    return result;
303}
304
305static GB_ERROR species_requires(GBDATA *gb_species, const char *whats_required) {
306    return GBS_global_string("Species '%s' needs %s", GBT_read_name(gb_species), whats_required);
307}
308
309static GB_ERROR gene_requires(GBDATA *gb_gene, const char *whats_required) {
310    GBDATA *gb_species = GB_get_grandfather(gb_gene);
311    pd_assert(gb_species);
312    return GBS_global_string("Gene '%s' of organism '%s' needs %s", GBT_read_name(gb_gene), GBT_read_name(gb_species), whats_required);
313}
314
315static GB_ERROR pd_get_the_names(GBDATA *gb_main, bytestring &bs, bytestring &checksum) {
316    GBS_strstruct *names     = GBS_stropen(1024);
317    GBS_strstruct *checksums = GBS_stropen(1024);
318    GB_ERROR       error     = 0;
319
320    GB_begin_transaction(gb_main);
321
322    char *use = GBT_get_default_alignment(gb_main);
323
324    for (GBDATA *gb_species = GBT_first_marked_species(gb_main); gb_species; gb_species = GBT_next_marked_species(gb_species)) {
325        GBDATA *gb_name = GB_entry(gb_species, "name");
326        if (!gb_name) { error = species_requires(gb_species, "name"); break; }
327
328        GBDATA *gb_data = GBT_find_sequence(gb_species, use);
329        if (!gb_data) { error = species_requires(gb_species, GBS_global_string("data in '%s'", use)); break; }
330
331        GBS_intcat(checksums, GBS_checksum(GB_read_char_pntr(gb_data), 1, ".-"));
332        GBS_strcat(names, GB_read_char_pntr(gb_name));
333        GBS_chrcat(checksums, '#');
334        GBS_chrcat(names, '#');
335    }
336
337    GBS_str_cut_tail(names, 1); // remove trailing '#'
338    GBS_str_cut_tail(checksums, 1); // remove trailing '#'
339
340    free(use);
341
342    bs.data = GBS_strclose(names);
343    bs.size = strlen(bs.data)+1;
344
345    checksum.data = GBS_strclose(checksums);
346    checksum.size = strlen(checksum.data)+1;
347
348    GB_commit_transaction(gb_main);
349
350    return error;
351}
352
353static GB_ERROR pd_get_the_gene_names(GBDATA *gb_main, bytestring &bs, bytestring &checksum) {
354    GBS_strstruct *names     = GBS_stropen(1024);
355    GBS_strstruct *checksums = GBS_stropen(1024);
356    GB_ERROR       error     = 0;
357
358    GB_begin_transaction(gb_main);
359    const char *use = GENOM_ALIGNMENT; // gene pt server is always build on 'ali_genom'
360
361    for (GBDATA *gb_species = GEN_first_organism(gb_main); gb_species && !error; gb_species = GEN_next_organism(gb_species)) {
362        const char *species_name = 0;
363        {
364            GBDATA *gb_data = GBT_find_sequence(gb_species, use);
365            if (!gb_data) { error = species_requires(gb_species, GBS_global_string("data in '%s'", use)); break; }
366
367            GBDATA *gb_name = GB_search(gb_species, "name", GB_FIND);
368            if (!gb_name) { error = species_requires(gb_species, "name"); break; }
369            species_name = GB_read_char_pntr(gb_name);
370        }
371
372        for (GBDATA *gb_gene = GEN_first_marked_gene(gb_species); gb_gene && !error; gb_gene = GEN_next_marked_gene(gb_gene)) {
373            const char *gene_name = 0;
374            {
375                GBDATA *gb_gene_name = GB_entry(gb_gene, "name");
376                if (!gb_gene_name) { error = gene_requires(gb_gene, "name"); break; }
377                gene_name = GB_read_char_pntr(gb_gene_name);
378            }
379
380            {
381                char *gene_seq       = GBT_read_gene_sequence(gb_gene, false, 0);
382                if (!gene_seq) error = GB_await_error();
383                else {
384                    long        CheckSum = GBS_checksum(gene_seq, 1, ".-");
385                    const char *id       = GBS_global_string("%s/%s", species_name, gene_name);
386
387                    GBS_intcat(checksums, CheckSum);
388                    GBS_strcat(names, id);
389                    GBS_chrcat(checksums, '#');
390                    GBS_chrcat(names, '#');
391
392                    free(gene_seq);
393                }
394            }
395        }
396    }
397
398    GBS_str_cut_tail(names, 1); // remove trailing '#'
399    GBS_str_cut_tail(checksums, 1); // remove trailing '#'
400
401    if (error) {
402        GBS_strforget(names);
403        GBS_strforget(checksums);
404    }
405    else {
406        bs.size = GBS_memoffset(names)+1;
407        bs.data = GBS_strclose(names);
408
409        checksum.size = GBS_memoffset(checksums)+1;
410        checksum.data = GBS_strclose(checksums);
411    }
412    error = GB_end_transaction(gb_main, error);
413    return error;
414}
415
416inline const char *bond_awar_name(int i) {
417    return GBS_global_string(AWAR_PD_COMMON_EXP_BONDS_FORMAT, i);
418}
419
420struct ProbeCommonSettings {
421    float split;
422    float bonds[16];
423
424    explicit ProbeCommonSettings(AW_root *root)
425        : split(root->awar(AWAR_PD_COMMON_EXP_SPLIT)->read_float())
426    {
427        for (int i=0; i<16; i++) {
428            bonds[i] = root->awar(bond_awar_name(i))->read_float();
429        }
430    }
431};
432
433static int probe_common_send_data(const ProbeCommonSettings& commonSettings) {
434    // send data common to probe-design AND -match
435    if (aisc_put(PD.link, PT_LOCS, PD.locs,
436                 LOCS_SPLIT, (double)commonSettings.split,
437                 NULL))
438        return 1;
439
440    for (int i=0; i<16; i++) {
441        if (aisc_put(PD.link, PT_LOCS, PD.locs,
442                     PT_INDEX,     (long)i,
443                     LOCS_BONDVAL, (double)commonSettings.bonds[i],
444                     NULL))
445            return 1;
446    }
447    return 0;
448}
449static int probe_design_send_data(AW_root *root, const T_PT_PDC& pdc) {
450    if (aisc_put(PD.link, PT_PDC, pdc,
451                 PDC_DTEDGE,     (double)root->awar(AWAR_PD_DESIGN_EXP_DTEDGE)->read_float()*100.0,
452                 PDC_DT,         (double)root->awar(AWAR_PD_DESIGN_EXP_DT)->read_float()*100.0,
453                 PDC_CLIPRESULT, (long)root->awar(AWAR_PD_DESIGN_CLIPRESULT)->read_int(),
454                 NULL))
455        return 1;
456
457    return probe_common_send_data(ProbeCommonSettings(root));
458}
459
460struct ProbeMatchSettings : public ProbeCommonSettings {
461    int serverNumber;
462    int nmatches;
463    int nlimit;
464    int maxhits;
465    int complement;
466    int sortBy;
467    int maxMismatches;
468    int markHits;
469    int write2tmp;
470
471    std::string targetString;
472
473    explicit ProbeMatchSettings(AW_root *root)
474        : ProbeCommonSettings(root),
475          serverNumber(root->awar(AWAR_PT_SERVER)->read_int()),
476          nmatches(root->awar(AWAR_PD_MATCH_NMATCHES)->read_int()),
477          nlimit(root->awar(AWAR_PD_MATCH_LIM_NMATCH)->read_int()),
478          maxhits(root->awar(AWAR_PD_MATCH_MAX_RES)->read_int()),
479          complement(root->awar(AWAR_PD_MATCH_COMPLEMENT)->read_int()),
480          sortBy(root->awar(AWAR_PD_MATCH_SORTBY)->read_int()),
481          maxMismatches(root->awar(AWAR_MAX_MISMATCHES)->read_int()),
482          markHits(root->awar(AWAR_PD_MATCH_MARKHITS)->read_int()),
483          write2tmp(root->awar(AWAR_PD_MATCH_WRITE2TMP)->read_int()),
484          targetString(root->awar(AWAR_TARGET_STRING)->read_char_pntr())
485    {}
486};
487
488static int probe_match_send_data(const ProbeMatchSettings& matchSettings) {
489    if (aisc_put(PD.link, PT_LOCS, PD.locs,
490                 LOCS_MATCH_N_ACCEPT, (long)matchSettings.nmatches,
491                 LOCS_MATCH_N_LIMIT,  (long)matchSettings.nlimit,
492                 LOCS_MATCH_MAX_HITS, (long)matchSettings.maxhits,
493                 NULL))
494        return 1;
495
496    return probe_common_send_data(matchSettings);
497}
498
499static int ecolipos2int(const char *awar_val) {
500    int i = atoi(awar_val);
501    return i>0 ? i : -1;
502}
503
504static char *readableUnknownNames(const ConstStrArray& unames) {
505    GBS_strstruct readable(100);
506
507    int ulast = unames.size()-1;
508    int umax  = ulast <= 10 ? ulast : 10;
509    for (int u = 0; u <= umax; ++u) {
510        if (u) readable.cat(u == ulast ? " and " : ", ");
511        readable.cat(unames[u]);
512    }
513
514    if (umax<ulast) readable.nprintf(30, " (and %i other)", ulast-umax);
515
516    return readable.release();
517}
518
519static void probe_design_event(AW_window *aww, GBDATA *gb_main) {
520    AW_root     *root  = aww->get_root();
521    T_PT_PDC     pdc;
522    T_PT_TPROBE  tprobe;
523    bytestring   bs;
524    bytestring   check;
525    GB_ERROR     error = 0;
526
527    arb_progress progress("Probe design");
528    progress.subtitle("Connecting PT-server");
529
530    {
531        const char *servername = PD_probe_pt_look_for_server(root->awar(AWAR_PT_SERVER)->read_int(), error);
532        if (servername) {
533            PD.link = aisc_open(servername, PD.com, AISC_MAGIC_NUMBER, &error);
534            if (!PD.link) error = "can't contact PT server";
535            PD.locs.clear();
536        }
537    }
538
539    if (!error && init_local_com_struct()) {
540        error = "Cannot contact to probe server: Connection Refused";
541    }
542
543    bool design_gene_probes = root->awar(AWAR_PD_DESIGN_GENE)->read_int();
544    if (design_gene_probes) {
545        GB_transaction ta(gb_main);
546        if (!GEN_is_genome_db(gb_main, -1)) design_gene_probes = false;
547    }
548
549    if (!error) {
550        if (design_gene_probes) { // design probes for genes
551            error = pd_get_the_gene_names(gb_main, bs, check);
552        }
553        else {
554            error = pd_get_the_names(gb_main, bs, check);
555        }
556    }
557
558    if (error) {
559        aw_message(error);
560        return;
561    }
562
563    progress.subtitle("probe design running");
564
565    if (aisc_create(PD.link, PT_LOCS, PD.locs,
566                    LOCS_PROBE_DESIGN_CONFIG, PT_PDC, pdc,
567                    PDC_MIN_PROBELEN, (long)root->awar(AWAR_PD_DESIGN_MIN_LENGTH)->read_int(),
568                    PDC_MAX_PROBELEN, (long)root->awar(AWAR_PD_DESIGN_MAX_LENGTH)->read_int(),
569                    PDC_MINTEMP,      (double)root->awar(AWAR_PD_DESIGN_MIN_TEMP)->read_float(),
570                    PDC_MAXTEMP,      (double)root->awar(AWAR_PD_DESIGN_MAX_TEMP)->read_float(),
571                    PDC_MINGC,        (double)root->awar(AWAR_PD_DESIGN_MIN_GC)->read_float()/100.0,
572                    PDC_MAXGC,        (double)root->awar(AWAR_PD_DESIGN_MAX_GC)->read_float()/100.0,
573                    PDC_MAXBOND,      (double)root->awar(AWAR_PD_DESIGN_MAXBOND)->read_int(),
574                    PDC_MIN_ECOLIPOS, (long)ecolipos2int(root->awar(AWAR_PD_DESIGN_MIN_ECOLIPOS)->read_char_pntr()),
575                    PDC_MAX_ECOLIPOS, (long)ecolipos2int(root->awar(AWAR_PD_DESIGN_MAX_ECOLIPOS)->read_char_pntr()),
576                    PDC_MISHIT,       (long)root->awar(AWAR_PD_DESIGN_MISHIT)->read_int(),
577                    PDC_MINTARGETS,   (double)root->awar(AWAR_PD_DESIGN_MINTARGETS)->read_float()/100.0,
578                    NULL))
579    {
580        aw_message("Connection to PT_SERVER lost (1)");
581        return;
582    }
583
584    if (probe_design_send_data(root, pdc)) {
585        aw_message("Connection to PT_SERVER lost (1)");
586        return;
587    }
588
589    aisc_put(PD.link, PT_PDC, pdc,
590             PDC_NAMES, &bs,
591             PDC_CHECKSUMS, &check,
592             NULL);
593
594
595    // Get the unknown names
596    bytestring unknown_names;
597    if (aisc_get(PD.link, PT_PDC, pdc,
598                 PDC_UNKNOWN_NAMES, &unknown_names,
599                 NULL))
600    {
601        aw_message("Connection to PT_SERVER lost (1)");
602        return;
603    }
604
605    bool abort = false;
606
607    if (unknown_names.size>1) {
608        ConstStrArray unames_array;
609        GBT_split_string(unames_array, unknown_names.data, "#", true);
610
611        char *readable_unames = readableUnknownNames(unames_array);
612
613        if (design_gene_probes) { // updating sequences of missing genes is not possible with gene PT server
614            aw_message(GBS_global_string("Your PT server is not up to date or wrongly chosen!\n"
615                                         "It knows nothing about the following genes:\n"
616                                         "\n"
617                                         "  %s\n"
618                                         "\n"
619                                         "You have to rebuild the PT server.",
620                                         readable_unames));
621            abort = true;
622        }
623        else if (aw_question("ptserver_add_unknown",
624                             GBS_global_string("Your PT server is not up to date or wrongly chosen!\n"
625                                               "It knows nothing about the following species:\n"
626                                               "\n"
627                                               "  %s\n"
628                                               "\n"
629                                               "You may now temporarily add these sequences for probe design.\n",
630                                               readable_unames),
631                             "Add and continue,Abort"))
632        {
633            abort = true;
634        }
635        else {
636            GB_transaction ta(gb_main);
637
638            char *ali_name = GBT_get_default_alignment(gb_main);
639
640            for (size_t u = 0; !abort && u<unames_array.size(); ++u) {
641                const char *uname      = unames_array[u];
642                GBDATA     *gb_species = GBT_find_species(gb_main, uname);
643                if (!gb_species) {
644                    aw_message(GBS_global_string("Species '%s' not found", uname));
645                    abort = true;
646                }
647                else {
648                    GBDATA *data = GBT_find_sequence(gb_species, ali_name);
649                    if (!data) {
650                        aw_message(GB_export_errorf("Species '%s' has no sequence belonging to alignment '%s'", uname, ali_name));
651                        abort = true;
652                    }
653                    else {
654                        T_PT_SEQUENCE pts;
655
656                        bytestring bs_seq;
657                        bs_seq.data = (char*)GB_read_char_pntr(data);
658                        bs_seq.size = GB_read_string_count(data)+1;
659
660                        aisc_create(PD.link, PT_PDC, pdc,
661                                    PDC_SEQUENCE, PT_SEQUENCE, pts,
662                                    SEQUENCE_SEQUENCE, &bs_seq,
663                                    NULL);
664                    }
665                }
666            }
667            free(ali_name);
668        }
669        free(readable_unames);
670        free(unknown_names.data);
671    }
672
673    if (!abort) {
674        aisc_put(PD.link, PT_PDC, pdc,
675                 PDC_GO, (long)0,
676                 NULL);
677
678        progress.subtitle("Reading results from server");
679        {
680            char *locs_error = 0;
681            if (aisc_get(PD.link, PT_LOCS, PD.locs,
682                         LOCS_ERROR, &locs_error,
683                         NULL))
684            {
685                aw_message("Connection to PT_SERVER lost (1)");
686                abort = true;
687            }
688            else if (*locs_error) {
689                aw_message(locs_error);
690                abort = true;
691            }
692            else {
693                free(locs_error);
694            }
695        }
696    }
697
698    if (!abort) {
699        aisc_get(PD.link, PT_PDC, pdc,
700                 PDC_TPROBE, tprobe.as_result_param(),
701                 NULL);
702
703        popup_probe_design_result_window(aww, gb_main);
704        PD.resultList->clear();
705
706        {
707            char *match_info = 0;
708            aisc_get(PD.link, PT_PDC, pdc,
709                     PDC_INFO_HEADER, &match_info,
710                     NULL);
711
712            char *s = strtok(match_info, "\n");
713            while (s) {
714                PD.resultList->insert(s, "");
715                s = strtok(0, "\n");
716            }
717            free(match_info);
718        }
719
720        while (tprobe.exists()) {
721            T_PT_TPROBE  tprobe_next;
722            char        *match_info = 0;
723
724            if (aisc_get(PD.link, PT_TPROBE, tprobe,
725                         TPROBE_NEXT, tprobe_next.as_result_param(),
726                         TPROBE_INFO, &match_info,
727                         NULL)) break;
728
729            tprobe.assign(tprobe_next);
730
731            char *probe, *space;
732            probe = strpbrk(match_info, "acgtuACGTU");
733            if (probe) space = strchr(probe, ' ');
734            if (probe && space) {
735                *space = 0; probe = strdup(probe); *space=' ';
736            }
737            else {
738                probe = strdup("");
739            }
740            PD.resultList->insert(match_info, probe);
741            free(probe);
742            free(match_info);
743        }
744        PD.resultList->insert_default("", "");
745        PD.resultList->update();
746    }
747
748    aisc_close(PD.link, PD.com); PD.link = 0;
749    return;
750}
751
752static bool allow_probe_match_event = true;
753
754static __ATTR__USERESULT GB_ERROR probe_match_event(const ProbeMatchSettings& matchSettings, ProbeMatchEventParam *event_param) {
755    GB_ERROR error = NULL;
756    if (allow_probe_match_event) {
757#if defined(ASSERTION_USED)
758        // runtime check against awar usage when NOT called from probe match window!
759        typedef SmartPtr< LocallyModify<bool> > Maybe;
760
761        Maybe dontReadAwars;
762        Maybe dontWriteAwars;
763
764        if (!event_param || !event_param->selection_id) {
765            dontReadAwars = new LocallyModify<bool>(AW_awar::deny_read, true);
766            dontWriteAwars = new LocallyModify<bool>(AW_awar::deny_write, true);
767        }
768#endif
769
770        AW_selection_list *selection_id = event_param ? event_param->selection_id : NULL;
771        int               *counter      = event_param ? event_param->counter : NULL;
772        GBDATA            *gb_main      = event_param ? event_param->gb_main : NULL;
773        int                show_status  = 0;
774        int                extras       = 1;        // mark species and write to temp fields
775
776        if (!gb_main) { error = "Please open probe match window once to enable auto-match"; }
777
778        SmartPtr<arb_progress> progress;
779
780        if (!error) {
781            const char *servername = PD_probe_pt_look_for_server(matchSettings.serverNumber, error);
782
783            if (!error) {
784                if (selection_id) {
785                    selection_id->clear();
786                    pd_assert(!counter);
787                    show_status = 1;
788                }
789                else if (counter) {
790                    extras = 0;
791                }
792
793                if (show_status) {
794                    progress = new arb_progress("Probe match");
795                    progress->subtitle("Connecting PT-server");
796                }
797
798                PD.link = aisc_open(servername, PD.com, AISC_MAGIC_NUMBER, &error);
799                if (!error && !PD.link) error = "Cannot contact PT-server";
800                PD.locs.clear();
801            }
802        }
803
804        if (!error && init_local_com_struct())              error = "Cannot contact PT-server (2)";
805        if (!error && probe_match_send_data(matchSettings)) error = "Connection to PT_SERVER lost (2)";
806
807        const char *probe = matchSettings.targetString.c_str();
808        if (!error) {
809            if (show_status) progress->subtitle("Probe match running");
810
811            if (aisc_nput(PD.link, PT_LOCS, PD.locs,
812                          LOCS_MATCH_REVERSED,       (long)matchSettings.complement, // @@@ use of complement/reverse looks suspect -> check (all uses of LOCS_MATCH_REVERSED and LOCS_MATCH_COMPLEMENT)
813                          LOCS_MATCH_COMPLEMENT,     (long)0,
814                          LOCS_MATCH_SORT_BY,        (long)matchSettings.sortBy,
815                          LOCS_MATCH_MAX_MISMATCHES, (long)matchSettings.maxMismatches,
816                          LOCS_SEARCHMATCH,          probe,
817                          NULL))
818            {
819                error = "Connection to PT_SERVER lost (2)";
820            }
821            else {
822                delete(g_spd);              // delete previous probe data
823                g_spd = new saiProbeData;
824                transferProbeData(g_spd);
825
826                g_spd->setProbeTarget(probe);
827            }
828        }
829
830        bytestring bs;
831        bs.data = 0;
832
833        long matches_truncated = 0;
834        if (!error) {
835            if (show_status) progress->subtitle("Reading results");
836
837            T_PT_MATCHLIST  match_list;
838            long            match_list_cnt    = 0;
839            char           *locs_error        = 0;
840
841            if (aisc_get(PD.link, PT_LOCS, PD.locs,
842                         LOCS_MATCH_LIST,        match_list.as_result_param(),
843                         LOCS_MATCH_LIST_CNT,    &match_list_cnt,
844                         LOCS_MATCH_STRING,      &bs,
845                         LOCS_MATCHES_TRUNCATED, &matches_truncated,
846                         LOCS_ERROR,             &locs_error,
847                         NULL))
848            {
849                error = "Connection to PT_SERVER lost (3)";
850            }
851            else {
852                if (locs_error) {
853                    if (*locs_error) error = GBS_static_string(locs_error);
854                    free(locs_error);
855                }
856                else {
857                    error = "Missing status from server (connection aborted?)";
858                }
859            }
860
861            event_param->hits_summary = GBS_global_string(matches_truncated ? "[more than %li]" : "%li", match_list_cnt);
862            if (matches_truncated) {
863                aw_message("Too many matches, displaying a random digest.\n" // @@@ should better be handled by caller
864                           "Increase the limit in the expert window.");
865            }
866        }
867
868        long mcount                = 0;
869        long unknown_species_count = 0;
870        long unknown_gene_count    = 0;
871
872        if (!error) {
873            char        toksep[2]  = { 1, 0 };
874            char       *strtok_ptr = 0; // stores strtok position
875            const char *hinfo      = strtok_r(bs.data, toksep, &strtok_ptr);
876
877            bool              gene_flag = false;
878            ProbeMatchParser *parser    = 0;
879            char             *result    = (char*)malloc(1024);
880
881
882            if (hinfo) {
883                g_spd->setHeadline(hinfo);
884                parser = new ProbeMatchParser(probe, hinfo);
885                error  = parser->get_error();
886                if (!error) gene_flag = parser->is_gene_result();
887            }
888
889            if (selection_id) {
890                int width         = 0;
891                if (parser && !error) width = parser->get_probe_region_offset()+2+10; // 2 cause headline is shorter and 10 for match prefix region
892
893                const char *searched = GBS_global_string("%-*s%s", width, "Searched for ", probe);
894                selection_id->insert(searched, probe);
895                if (hinfo) selection_id->insert(hinfo, "");
896            }
897
898
899            // clear all marks and delete all 'tmp' entries
900
901            int mark        = extras && matchSettings.markHits;
902            int write_2_tmp = extras && matchSettings.write2tmp;
903
904            GB_push_transaction(gb_main);
905
906            GBDATA *gb_species_data = GBT_get_species_data(gb_main);
907            if (mark && !error) {
908                if (show_status) progress->subtitle(gene_flag ? "Unmarking all species and genes" : "Unmarking all species");
909                for (GBDATA *gb_species = GBT_first_marked_species_rel_species_data(gb_species_data);
910                     gb_species;
911                     gb_species = GBT_next_marked_species(gb_species))
912                {
913                    GB_write_flag(gb_species, 0);
914                }
915
916                if (gene_flag) {
917                    // unmark genes of ALL species
918                    for (GBDATA *gb_species = GBT_first_species_rel_species_data(gb_species_data);
919                         gb_species;
920                         gb_species = GBT_next_species(gb_species))
921                    {
922                        GBDATA *genData = GEN_find_gene_data(gb_species);
923                        if (genData) {
924                            for (GBDATA *gb_gene = GEN_first_marked_gene(gb_species);
925                                 gb_gene;
926                                 gb_gene = GEN_next_marked_gene(gb_gene))
927                            {
928                                GB_write_flag(gb_gene, 0);
929                            }
930                        }
931                    }
932                }
933            }
934            if (write_2_tmp && !error) {
935                if (show_status) progress->subtitle("Deleting old 'tmp' fields");
936                for (GBDATA *gb_species = GBT_first_species_rel_species_data(gb_species_data);
937                     gb_species;
938                     gb_species = GBT_next_species(gb_species))
939                {
940                    GBDATA *gb_tmp = GB_entry(gb_species, "tmp");
941                    if (gb_tmp) GB_delete(gb_tmp);
942                    if (gene_flag) {
943                        for (GBDATA *gb_gene = GEN_first_gene(gb_species);
944                             gb_gene;
945                             gb_gene = GEN_next_gene(gb_species))
946                        {
947                            gb_tmp = GB_entry(gb_gene, "tmp");
948                            if (gb_tmp) GB_delete(gb_tmp);
949                        }
950                    }
951                }
952            }
953
954            // read results from pt-server :
955
956            if (!error) {
957                if (show_status) progress->subtitle("Parsing results");
958
959                g_spd->probeSpecies.clear();
960                g_spd->probeSeq.clear();
961
962                if (gene_flag) {
963                    if (!GEN_is_genome_db(gb_main, -1)) {
964                        error = "Wrong PT-Server chosen (selected one is built for genes)";
965                    }
966                }
967            }
968
969            const char *match_name = 0;
970            while (hinfo && !error && (match_name = strtok_r(0, toksep, &strtok_ptr))) {
971                const char *match_info = strtok_r(0, toksep, &strtok_ptr);
972                if (!match_info) break;
973
974                pd_assert(parser);
975                ParsedProbeMatch  ppm(match_info, *parser);
976                char             *gene_str = 0;
977
978                if (gene_flag) {
979                    gene_str = ppm.get_column_content("genename", true);
980                }
981
982                if (!error) {
983                    char flags[]       = "xx";
984                    GBDATA *gb_species = GBT_find_species_rel_species_data(gb_species_data, match_name);
985
986                    if (gb_species) {
987                        GBDATA *gb_gene = 0;
988                        if (gene_flag && strncmp(gene_str, "intergene_", 10) != 0) { // real gene
989                            gb_gene = GEN_find_gene(gb_species, gene_str);
990                            if (!gb_gene) {
991                                aw_message(GBS_global_string("Gene '%s' not found in organism '%s'", gene_str, match_name));
992                            }
993                        }
994
995                        if (mark) {
996                            GB_write_flag(gb_species, 1);
997                            flags[0] = '*';
998                            if (gb_gene) {
999                                GB_write_flag(gb_gene, 1);
1000                                flags[1] = '*';
1001                            }
1002                            else {
1003                                flags[1] = '?'; // no gene
1004                            }
1005                        }
1006                        else {
1007                            flags[0] = " *"[GB_read_flag(gb_species)];
1008                            flags[1] = " *?"[gb_gene ? GB_read_flag(gb_gene) : 2];
1009                        }
1010
1011                        if (write_2_tmp) {
1012                            // write or append to field 'tmp'
1013
1014                            GBDATA   *gb_tmp = 0;
1015                            GB_ERROR  error2 = 0;
1016                            bool      append = true;
1017                            {
1018                                GBDATA *gb_parent = gene_flag ? gb_gene : gb_species;
1019                                gb_tmp            = GB_search(gb_parent, "tmp", GB_FIND);
1020                                if (!gb_tmp) {
1021                                    append              = false;
1022                                    gb_tmp              = GB_search(gb_parent, "tmp", GB_STRING);
1023                                    if (!gb_tmp) error2 = GB_await_error();
1024                                }
1025                            }
1026
1027                            if (!error2) {
1028                                pd_assert(gb_tmp);
1029                                if (append) {
1030                                    char *prevContent = GB_read_string(gb_tmp);
1031                                    if (!prevContent) {
1032                                        error2 = GB_await_error();
1033                                    }
1034                                    else {
1035                                        char *concatenatedContent = (char *)malloc(strlen(prevContent)+1+strlen(match_info)+1);
1036                                        sprintf(concatenatedContent, "%s\n%s", prevContent, match_info);
1037                                        error2 = GB_write_string(gb_tmp, concatenatedContent);
1038                                        free(concatenatedContent);
1039                                        free(prevContent);
1040                                    }
1041                                }
1042                                else {
1043                                    error2 = GB_write_string(gb_tmp, match_info);
1044                                }
1045                            }
1046
1047                            if (error2) aw_message(error2);
1048                        }
1049                    }
1050                    else {
1051                        flags[0] = flags[1] = '?'; // species does not exist
1052                        unknown_species_count++;
1053                    }
1054
1055
1056                    if (gene_flag) {
1057                        sprintf(result, "%s %s", flags, match_info+1); // both flags (skip 1 space from match info to keep alignment)
1058                        char *gene_match_name = new char[strlen(match_name) + strlen(gene_str)+2];
1059                        sprintf(gene_match_name, "%s/%s", match_name, gene_str);
1060                        if (selection_id) selection_id->insert(result, gene_match_name);   // @@@ wert fuer awar eintragen
1061                    }
1062                    else {
1063                        sprintf(result, "%c %s", flags[0], match_info); // only first flag ( = species related)
1064                        if (selection_id) selection_id->insert(result, match_name);   // @@@ wert fuer awar eintragen
1065
1066                        // storing probe data into linked lists
1067                        g_spd->probeSeq.push_back(std::string(match_info));
1068                        g_spd->probeSpecies.push_back(std::string(match_name));
1069                    }
1070                    mcount++;
1071                }
1072
1073                free(gene_str);
1074            }
1075
1076            if (error) error = GBS_static_string(error); // make static copy (error may be freed by delete parser)
1077            delete parser;
1078            free(result);
1079
1080            GB_pop_transaction(gb_main);
1081        }
1082
1083        if (error) {
1084            if (event_param) event_param->hits_summary = "[none]"; // clear hits
1085        }
1086        else {
1087            if (unknown_species_count>0) {
1088                error = GBS_global_string("%li matches hit unknown species -- PT-server is out-of-date or build upon a different database", unknown_species_count);
1089            }
1090            if (unknown_gene_count>0 && !error) {
1091                error = GBS_global_string("%li matches hit unknown genes -- PT-server is out-of-date or build upon a different database", unknown_gene_count);
1092            }
1093
1094            if (selection_id) {     // if !selection_id then probe match window is not opened
1095                pd_assert(g_spd);
1096                event_param->refresh_sai_display = true; // want refresh of SAI/Probe window
1097            }
1098        }
1099
1100        if (counter) *counter = mcount;
1101
1102        aisc_close(PD.link, PD.com);
1103        PD.link = 0;
1104
1105        if (selection_id) {
1106            const char *last_line                 = 0;
1107            if (error) last_line                  = GBS_global_string("****** Error: %s *******", error);
1108            else if (matches_truncated) last_line = "****** List is truncated *******";
1109            else        last_line                 = "****** End of List *******";
1110
1111            selection_id->insert_default(last_line, "");
1112            selection_id->update();
1113        }
1114
1115        free(bs.data);
1116    }
1117    return error;
1118}
1119
1120static void probe_match_event_using_awars(AW_root *root, ProbeMatchEventParam *event_param) {
1121    if (allow_probe_match_event) {
1122        GB_ERROR error = probe_match_event(ProbeMatchSettings(root), event_param);
1123        aw_message_if(error);
1124
1125        LocallyModify<bool> flag(allow_probe_match_event, false);
1126
1127        if (event_param) {
1128            if (event_param->refresh_sai_display) {
1129                root->awar(AWAR_SPV_DB_FIELD_NAME)->touch(); // force refresh of SAI/Probe window
1130            }
1131            if (event_param->selection_id) {
1132                root->awar(AWAR_PD_MATCH_NHITS)->write_string(event_param->hits_summary.c_str()); // update hits in probe match window
1133            }
1134        }
1135        root->awar(AWAR_TREE_REFRESH)->touch(); // refresh tree
1136    }
1137}
1138
1139static void probe_match_all_event(AW_window *aww, AW_selection_list *iselection_id, GBDATA *gb_main) {
1140    AW_selection_list_iterator selentry(iselection_id);
1141    arb_progress               progress("Matching all resolved strings", iselection_id->size());
1142    ProbeMatchSettings         matchSettings(aww->get_root());
1143    const bool                 got_result = selentry;
1144
1145    while (selentry) {
1146        const char *entry          = selentry.get_value(); // @@@ rename -> probe
1147        matchSettings.targetString = entry;
1148
1149        int                  counter = -1;
1150        ProbeMatchEventParam match_event(gb_main, &counter);
1151        GB_ERROR             error   = probe_match_event(matchSettings, &match_event);
1152
1153        // write # of hits to list entries:
1154        {
1155#define DISP_FORMAT "%7i %s"
1156            const char *displayed;
1157            if (error) {
1158                displayed = GBS_global_string(DISP_FORMAT " (Error: %s)", 0, entry, error);
1159            }
1160            else {
1161                displayed = GBS_global_string(DISP_FORMAT, counter, entry);
1162            }
1163            selentry.set_displayed(displayed);
1164#undef DISP_FORMAT
1165        }
1166
1167        ++selentry;
1168        progress.inc();
1169    }
1170
1171    if (got_result) {
1172        iselection_id->sort(true, true);
1173        iselection_id->update();
1174    }
1175}
1176
1177static void resolved_probe_chosen(AW_root *root) {
1178    char *string = root->awar(AWAR_PD_MATCH_RESOLVE)->read_string();
1179    root->awar(AWAR_TARGET_STRING)->write_string(string);
1180}
1181
1182static void selected_match_changed_cb(AW_root *root) {
1183    // this gets called when ever the selected probe match changes
1184    char *temp;
1185    char *selected_match = root->awar(AWAR_PD_SELECTED_MATCH)->read_string();
1186
1187    if (strchr(selected_match, '/')) { // "organism/gene"
1188        temp = strtok(selected_match, "/");
1189        root->awar(AWAR_SPECIES_NAME)->write_string(temp);
1190        temp = strtok(NULL, " /\n");
1191        root->awar(AWAR_GENE_NAME)->write_string(temp);
1192    }
1193    else {
1194        root->awar(AWAR_SPECIES_NAME)->write_string(selected_match);
1195    }
1196
1197    {
1198        LocallyModify<bool> flag(allow_probe_match_event, false); // avoid recursion
1199        root->awar(AWAR_TARGET_STRING)->touch(); // forces editor to jump to probe match in gene
1200    }
1201
1202    free(selected_match);
1203}
1204
1205static void probelength_changed_cb(AW_root *root, bool maxChanged) {
1206    static bool avoid_recursion = false;
1207    if (!avoid_recursion) {
1208        AW_awar *awar_minl = root->awar(AWAR_PD_DESIGN_MIN_LENGTH);
1209        AW_awar *awar_maxl = root->awar(AWAR_PD_DESIGN_MAX_LENGTH);
1210
1211        int minl = awar_minl->read_int();
1212        int maxl = awar_maxl->read_int();
1213
1214        if (minl>maxl) {
1215            if (maxChanged) awar_minl->write_int(maxl);
1216            else            awar_maxl->write_int(minl);
1217        }
1218    }
1219}
1220
1221static void minmax_awar_pair_changed_cb(AW_root *root, bool maxChanged, const char *minAwarName, const char *maxAwarName) {
1222    static bool avoid_recursion = false;
1223    if (!avoid_recursion) {
1224        LocallyModify<bool> flag(avoid_recursion, true);
1225
1226        AW_awar *awar_min = root->awar(minAwarName);
1227        AW_awar *awar_max = root->awar(maxAwarName);
1228
1229        float currMin = awar_min->read_float();
1230        float currMax = awar_max->read_float();
1231
1232        if (currMin>currMax) { // invalid -> correct
1233            if (maxChanged) awar_min->write_float(currMax);
1234            else            awar_max->write_float(currMin);
1235        }
1236    }
1237}
1238static void gc_minmax_changed_cb(AW_root *root, bool maxChanged) {
1239    minmax_awar_pair_changed_cb(root, maxChanged, AWAR_PD_DESIGN_MIN_GC, AWAR_PD_DESIGN_MAX_GC);
1240}
1241static void temp_minmax_changed_cb(AW_root *root, bool maxChanged) {
1242    minmax_awar_pair_changed_cb(root, maxChanged, AWAR_PD_DESIGN_MIN_TEMP, AWAR_PD_DESIGN_MAX_TEMP);
1243}
1244
1245void create_probe_design_variables(AW_root *root, AW_default props, AW_default db) {
1246    PD.win = 0;        // design result window not created
1247
1248    root->awar_string(AWAR_SPECIES_NAME,         "", props);
1249    root->awar_string(AWAR_PD_SELECTED_MATCH,    "", props)->add_callback(selected_match_changed_cb);
1250    root->awar_float (AWAR_PD_DESIGN_EXP_DTEDGE, .5, props);
1251    root->awar_float (AWAR_PD_DESIGN_EXP_DT,     .5, props);
1252
1253    double default_bonds[16] = {
1254        0.0, 0.0, 0.5, 1.1,
1255        0.0, 0.0, 1.5, 0.0,
1256        0.5, 1.5, 0.4, 0.9,
1257        1.1, 0.0, 0.9, 0.0
1258    };
1259
1260    for (int i=0; i<16; i++) {
1261        root->awar_float(bond_awar_name(i), default_bonds[i], props)->set_minmax(0, 3.0);
1262    }
1263    root->awar_float(AWAR_PD_COMMON_EXP_SPLIT,  .5, props);
1264    root->awar_float(AWAR_PD_DESIGN_EXP_DTEDGE, .5, props);
1265    root->awar_float(AWAR_PD_DESIGN_EXP_DT,     .5, props);
1266
1267    root->awar_int  (AWAR_PD_DESIGN_CLIPRESULT, 50,   props)->set_minmax(0, 1000);
1268    root->awar_int  (AWAR_PD_DESIGN_MISHIT,     0,    props)->set_minmax(0, 100000);
1269    root->awar_int  (AWAR_PD_DESIGN_MAXBOND,    4,    props)->set_minmax(0, 20);
1270    root->awar_float(AWAR_PD_DESIGN_MINTARGETS, 50.0, props)->set_minmax(0, 100);
1271
1272    AW_awar *awar_min_len = root->awar_int(AWAR_PD_DESIGN_MIN_LENGTH, 18, props);
1273    awar_min_len->set_minmax(DOMAIN_MIN_LENGTH, 100)->add_callback(makeRootCallback(probelength_changed_cb, false));
1274    root->awar_int(AWAR_PD_DESIGN_MAX_LENGTH, awar_min_len->read_int(), props)->set_minmax(DOMAIN_MIN_LENGTH, 100)->add_callback(makeRootCallback(probelength_changed_cb, true));
1275
1276    root->awar_float(AWAR_PD_DESIGN_MIN_TEMP,     30.0,   props)->set_minmax(0, 1000)->add_callback(makeRootCallback(temp_minmax_changed_cb, false));
1277    root->awar_float(AWAR_PD_DESIGN_MAX_TEMP,     100.0,  props)->set_minmax(0, 1000)->add_callback(makeRootCallback(temp_minmax_changed_cb, true));
1278
1279    root->awar_float(AWAR_PD_DESIGN_MIN_GC, 50.0,  props)->add_callback(makeRootCallback(gc_minmax_changed_cb, false));
1280    root->awar_float(AWAR_PD_DESIGN_MAX_GC, 100.0, props)->add_callback(makeRootCallback(gc_minmax_changed_cb, true));
1281
1282    gc_minmax_changed_cb(root, false);
1283    gc_minmax_changed_cb(root, true);
1284
1285    root->awar_string(AWAR_PD_DESIGN_MIN_ECOLIPOS, "", props);
1286    root->awar_string(AWAR_PD_DESIGN_MAX_ECOLIPOS, "", props);
1287
1288    root->awar_int(AWAR_PT_SERVER,      0, props);
1289    root->awar_int(AWAR_PD_DESIGN_GENE, 0, props);
1290
1291    root->awar_int(AWAR_PD_MATCH_MARKHITS,   1, props);
1292    root->awar_int(AWAR_PD_MATCH_SORTBY,     0, props);
1293    root->awar_int(AWAR_PD_MATCH_WRITE2TMP,  0, props);
1294    root->awar_int(AWAR_PD_MATCH_COMPLEMENT, 0, props);
1295
1296    root->awar_int   (AWAR_MAX_MISMATCHES, 0, db)->set_minmax(0, 200);
1297    root->awar_string(AWAR_TARGET_STRING,  0, db);
1298
1299    root->awar_string(AWAR_PD_MATCH_NHITS,      "[none]", props);
1300    root->awar_int   (AWAR_PD_MATCH_NMATCHES,   1,        props);
1301    root->awar_int   (AWAR_PD_MATCH_LIM_NMATCH, 4,        props);
1302    root->awar_int   (AWAR_PD_MATCH_MAX_RES,    1000000,  props);
1303
1304    root->awar_int(AWAR_PD_MATCH_AUTOMATCH, 0, props)->add_callback(auto_match_changed);
1305
1306    root->awar_string(AWAR_PD_MATCH_RESOLVE, "", props)->add_callback(resolved_probe_chosen);
1307    root->awar_string(AWAR_ITARGET_STRING,   "", db);
1308
1309    root->awar_int(AWAR_PROBE_ADMIN_PT_SERVER,    0, db);
1310    root->awar_int(AWAR_PROBE_CREATE_GENE_SERVER, 0, db);
1311
1312    root->awar_string(AWAR_SPV_SAI_2_PROBE,    "",     db); // name of SAI selected in list
1313    root->awar_string(AWAR_SPV_DB_FIELD_NAME,  "name", db); // name of displayed species field
1314    root->awar_int   (AWAR_SPV_DB_FIELD_WIDTH, 10,     db); // width of displayed species field
1315    root->awar_string(AWAR_SPV_ACI_COMMAND,    "",     db); // User defined or pre-defined ACI command to display
1316
1317    root->awar_int(AWAR_PC_MATCH_NHITS,     0, db);
1318    root->awar_int(AWAR_PC_AUTO_MATCH,      0, props);
1319
1320    root->awar_string(AWAR_PC_TARGET_STRING,  "", db)->set_srt(REPLACE_TARGET_CONTROL_CHARS);
1321    root->awar_string(AWAR_PC_TARGET_NAME,    "", db)->set_srt(REPLACE_TARGET_CONTROL_CHARS);
1322    root->awar_string(AWAR_PC_SELECTED_PROBE, "", db);
1323
1324    root->awar_float(AWAR_PC_MATCH_WIDTH, 1.0, db)->set_minmax(0.01, 100.0);
1325    root->awar_float(AWAR_PC_MATCH_BIAS,  0.0, db)->set_minmax(-1.0, 1.0);
1326
1327    root->awar_float(AWAR_PC_MISMATCH_THRESHOLD, 0.0, db)->set_minmax(0, 100); // Note: limits will be modified by probe_match_with_specificity_event
1328
1329    float default_weights[16] = {0.0};
1330    float default_width = 1.0;
1331    float default_bias  = 0.0;
1332
1333    ArbProbeCollection& g_probe_collection = get_probe_collection();
1334    g_probe_collection.getParameters(default_weights, default_width, default_bias);
1335    g_probe_collection.clear();
1336
1337    char buffer[256] = {0};
1338
1339    for (int i = 0; i < 16 ; i++) {
1340        sprintf(buffer, AWAR_PC_MATCH_WEIGHTS"%i", i);
1341        AW_awar *awar = root->awar_float(buffer, 0.0, db);
1342
1343        awar->set_minmax(0, 10);
1344        default_weights[i] = awar->read_float();
1345    }
1346
1347    g_probe_collection.setParameters(default_weights, default_width, default_bias);
1348
1349    // read probes from DB and add them to collection
1350    {
1351        AW_awar *awar_current = root->awar_string(AWAR_PC_CURRENT_COLLECTION, "", db);
1352        char    *current      = awar_current->read_string();
1353
1354        if (current && current[0]) {
1355            // Note: target sequences/names do not contain '#'/':' (see REPLACE_TARGET_CONTROL_CHARS)
1356            ConstStrArray probes;
1357            GBT_splitNdestroy_string(probes, current, "#", true);
1358
1359            for (size_t i = 0; i<probes.size(); ++i) {
1360                const char *probe = probes[i];
1361                const char *colon = strchr(probe, ':');
1362
1363                if (colon) {
1364                    char       *name = GB_strpartdup(probe, colon-1);
1365                    const char *seq  = colon+1;
1366                    g_probe_collection.add(name, seq);
1367                    free(name);
1368                }
1369                else {
1370                    aw_message(GBS_global_string("Saved probe ignored: has wrong format ('%s', expected 'name:seq')", probe));
1371                }
1372            }
1373        }
1374        free(current);
1375    }
1376    root->awar_string(AWAR_SPV_SELECTED_PROBE, "",     db); // For highlighting the selected PROBE
1377}
1378
1379static AW_window *create_probe_expert_window(AW_root *root, bool for_design) {
1380    AW_window_simple *aws = new AW_window_simple;
1381    if (for_design) {
1382        aws->init(root, "PD_exp", "Probe Design (Expert)");
1383        aws->load_xfig("pd_spec.fig");
1384    }
1385    else {
1386        aws->init(root, "PM_exp", "Probe Match (Expert)");
1387        aws->load_xfig("pm_spec.fig");
1388    }
1389
1390    aws->label_length(30);
1391    aws->button_length(10);
1392
1393    aws->at("close");
1394    aws->callback(AW_POPDOWN);
1395    aws->create_button("CLOSE", "CLOSE", "C");
1396
1397    aws->callback(makeHelpCallback(for_design ? "pd_spec_param.hlp" : "pm_spec_param.hlp")); // uses_hlp_res("pm_spec_param.hlp", "pd_spec_param.hlp"); see ../SOURCE_TOOLS/check_resources.pl@uses_hlp_res
1398    aws->at("help");
1399    aws->create_button("HELP", "HELP", "C");
1400
1401    for (int i=0; i<16; i++) { // bond matrix
1402        char bondAt[3];
1403        sprintf(bondAt, "%i", i);
1404        aws->at(bondAt);
1405
1406        aws->create_input_field(bond_awar_name(i), 4);
1407    }
1408
1409    aws->sens_mask(AWM_EXP);
1410    aws->at("split"); aws->create_input_field(AWAR_PD_COMMON_EXP_SPLIT,  6);
1411
1412    if (for_design) {
1413        aws->at("dt_edge"); aws->create_input_field(AWAR_PD_DESIGN_EXP_DTEDGE, 6);
1414        aws->at("dt");      aws->create_input_field(AWAR_PD_DESIGN_EXP_DT,     6);
1415        aws->sens_mask(AWM_ALL);
1416    }
1417    else {
1418        aws->at("nmatches");   aws->create_input_field(AWAR_PD_MATCH_NMATCHES,   3);
1419        aws->at("lim_nmatch"); aws->create_input_field(AWAR_PD_MATCH_LIM_NMATCH, 3);
1420        aws->sens_mask(AWM_ALL);
1421        aws->at("max_res");    aws->create_input_field(AWAR_PD_MATCH_MAX_RES,    14);
1422    }
1423
1424    return aws;
1425}
1426
1427static AWT_config_mapping_def probe_design_mapping_def[] = {
1428    // main window:
1429    { AWAR_PD_DESIGN_CLIPRESULT,   "clip" },
1430    { AWAR_PD_DESIGN_MISHIT,       "mishit" },
1431    { AWAR_PD_DESIGN_MAXBOND,      "maxbond" },
1432    { AWAR_PD_DESIGN_MINTARGETS,   "mintarget" },
1433    { AWAR_PD_DESIGN_MIN_LENGTH,   "probelen" },
1434    { AWAR_PD_DESIGN_MAX_LENGTH,   "probemaxlen" },
1435    { AWAR_PD_DESIGN_MIN_TEMP,     "mintemp" },
1436    { AWAR_PD_DESIGN_MAX_TEMP,     "maxtemp" },
1437    { AWAR_PD_DESIGN_MIN_GC,       "mingc" },
1438    { AWAR_PD_DESIGN_MAX_GC,       "maxgc" },
1439    { AWAR_PD_DESIGN_MIN_ECOLIPOS, "minecoli" },
1440    { AWAR_PD_DESIGN_MAX_ECOLIPOS, "maxecoli" },
1441    { AWAR_PD_DESIGN_GENE,         "gene" },
1442
1443    // expert window:
1444    { AWAR_PD_DESIGN_EXP_DTEDGE,   "dtedge" },
1445    { AWAR_PD_DESIGN_EXP_DT,       "dt" },
1446
1447    { 0, 0 }
1448};
1449
1450static void setup_probe_config(AWT_config_definition& cdef, const AWT_config_mapping_def *mapping) {
1451    cdef.add(mapping);
1452
1453    // entries common for both expert windows (design + match)
1454    cdef.add(AWAR_PD_COMMON_EXP_SPLIT, "split");
1455    for (int i = 0; i<16; ++i) {
1456        cdef.add(bond_awar_name(i), "bond", i);
1457    }
1458}
1459
1460AW_window *create_probe_design_window(AW_root *root, GBDATA *gb_main) {
1461    bool is_genom_db;
1462    {
1463        GB_transaction ta(gb_main);
1464        is_genom_db = GEN_is_genome_db(gb_main, -1);
1465    }
1466
1467    AW_window_simple *aws = new AW_window_simple;
1468    aws->init(root, "PROBE_DESIGN", "PROBE DESIGN");
1469
1470    aws->load_xfig("pd_main.fig");
1471
1472    aws->at("close");
1473    aws->callback(AW_POPDOWN);
1474    aws->create_button("CLOSE", "CLOSE", "C");
1475
1476    aws->at("help");
1477    aws->callback(makeHelpCallback("probedesign.hlp"));
1478    aws->create_button("HELP", "HELP", "H");
1479
1480    aws->callback(makeWindowCallback(probe_design_event, gb_main));
1481    aws->at("design");
1482    aws->highlight();
1483    aws->create_button("GO", "GO", "G");
1484
1485    aws->callback(makeWindowCallback(popup_probe_design_result_window, gb_main));
1486    aws->at("result");
1487    aws->create_button("RESULT", "RESULT", "S");
1488
1489    aws->callback(makeCreateWindowCallback(create_probe_expert_window, true));
1490    aws->at("expert");
1491    aws->create_button("EXPERT", "EXPERT", "S");
1492
1493    aws->at("pt_server");
1494    aws->label("PT-Server:");
1495    awt_create_PTSERVER_selection_button(aws, AWAR_PT_SERVER);
1496
1497    aws->at("lenout");   aws->create_input_field(AWAR_PD_DESIGN_CLIPRESULT, 6);
1498    aws->at("mishit");   aws->create_input_field(AWAR_PD_DESIGN_MISHIT,     6);
1499    aws->sens_mask(AWM_EXP);
1500    aws->at("maxbonds"); aws->create_input_field(AWAR_PD_DESIGN_MAXBOND,    6);
1501    aws->sens_mask(AWM_ALL);
1502    aws->at("minhits");  aws->create_input_field(AWAR_PD_DESIGN_MINTARGETS, 6);
1503
1504    aws->at("minlen"); aws->create_input_field(AWAR_PD_DESIGN_MIN_LENGTH,   5);
1505    aws->at("maxlen"); aws->create_input_field(AWAR_PD_DESIGN_MAX_LENGTH,   5);
1506    aws->at("mint");   aws->create_input_field(AWAR_PD_DESIGN_MIN_TEMP,     5);
1507    aws->at("maxt");   aws->create_input_field(AWAR_PD_DESIGN_MAX_TEMP,     5);
1508    aws->at("mingc");  aws->create_input_field(AWAR_PD_DESIGN_MIN_GC,       5);
1509    aws->at("maxgc");  aws->create_input_field(AWAR_PD_DESIGN_MAX_GC,       5);
1510    aws->at("minpos"); aws->create_input_field(AWAR_PD_DESIGN_MIN_ECOLIPOS, 5);
1511    aws->at("maxpos"); aws->create_input_field(AWAR_PD_DESIGN_MAX_ECOLIPOS, 5);
1512
1513    if (is_genom_db) {
1514        aws->at("gene");
1515        aws->label("Gene probes?");
1516        aws->create_toggle(AWAR_PD_DESIGN_GENE);
1517    }
1518
1519    aws->at("save");
1520    AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "probe_design", makeConfigSetupCallback(setup_probe_config, probe_design_mapping_def));
1521
1522    return aws;
1523}
1524
1525// -------------------------------------------------------------------
1526
1527inline void my_strupr(char *s) {
1528    pd_assert(s);
1529    for (int i=0; s[i]; i++) {
1530        s[i] = toupper(s[i]);
1531    }
1532}
1533
1534static void resolve_IUPAC_target_string(AW_root *root, AW_selection_list *selection_id, GBDATA *gb_main) {
1535    selection_id->clear();
1536
1537    GB_alignment_type ali_type = GBT_get_alignment_type(gb_main, GBT_get_default_alignment(gb_main));
1538
1539    GB_ERROR err = 0;
1540    if (ali_type != GB_AT_RNA && ali_type!=GB_AT_DNA) {
1541        err = "Wrong alignment type";
1542        GB_clear_error();
1543    }
1544    else {
1545        int   index   = ali_type==GB_AT_RNA ? 1 : 0;
1546        char *istring = root->awar(AWAR_ITARGET_STRING)->read_string();
1547
1548        if (istring && istring[0]) { // contains sth?
1549            my_strupr(istring);
1550
1551            int bases_to_resolve = 0;
1552            char *istr = istring;
1553            int istring_length = strlen(istring);
1554
1555            for (;;) {
1556                char i = *istr++;
1557                if (!i) break;
1558                if (i=='?') continue; // ignore '?'
1559
1560                int idx = i-'A';
1561                if (idx<0 || idx>=26 || iupac::nuc_group[idx][index].members==0) {
1562                    err = GBS_global_string("Illegal character '%c' in IUPAC-String", i);
1563                    break;
1564                }
1565
1566                if (iupac::nuc_group[idx][index].count>1) {
1567                    bases_to_resolve++;
1568                }
1569            }
1570
1571            if (!err) {
1572                int *offsets_to_resolve = new int[bases_to_resolve];
1573                int resolutions = 1;
1574                {
1575                    istr = istring;
1576                    int offset = 0;
1577                    int offset_count = 0;
1578                    for (;;) {
1579                        char i = *istr++;
1580                        if (!i) break;
1581
1582                        if (i!='?') {
1583                            int idx = iupac::to_index(i);
1584                            pd_assert(iupac::nuc_group[idx][index].members);
1585
1586                            if (iupac::nuc_group[idx][index].count>1) {
1587                                offsets_to_resolve[offset_count++] = offset; // store string offsets of non-unique base-codes
1588                                resolutions *= iupac::nuc_group[idx][index].count; // calc # of resolutions
1589                            }
1590                        }
1591                        offset++;
1592                    }
1593                }
1594
1595                {
1596                    int *resolution_idx = new int[bases_to_resolve];
1597                    int *resolution_max_idx = new int[bases_to_resolve];
1598                    {
1599                        int i;
1600                        for (i=0; i<bases_to_resolve; i++) {
1601                            resolution_idx[i] = 0;
1602                            int idx = iupac::to_index(istring[offsets_to_resolve[i]]);
1603                            resolution_max_idx[i] = iupac::nuc_group[idx][index].count-1;
1604                        }
1605                    }
1606
1607                    char *buffer = new char[istring_length+1];
1608                    int not_last = resolutions-1;
1609
1610                    for (;;) {
1611                        // create string according to resolution_idx[]:
1612                        int i;
1613
1614                        memcpy(buffer, istring, istring_length+1);
1615                        for (i=0; i<bases_to_resolve; i++) {
1616                            int off = offsets_to_resolve[i];
1617                            int idx = iupac::to_index(istring[off]);
1618
1619                            pd_assert(iupac::nuc_group[idx][index].members);
1620                            buffer[off] = iupac::nuc_group[idx][index].members[resolution_idx[i]];
1621                        }
1622
1623                        selection_id->insert(buffer, buffer);
1624                        not_last--;
1625
1626                        // permute indices:
1627                        int nidx = bases_to_resolve-1;
1628                        int done = 0;
1629                        while (!done && nidx>=0) {
1630                            if (resolution_idx[nidx]<resolution_max_idx[nidx]) {
1631                                resolution_idx[nidx]++;
1632                                done = 1;
1633                                break;
1634                            }
1635                            nidx--;
1636                        }
1637                        if (!done) break; // we did all permutations!
1638
1639                        nidx++; // do not touch latest incremented index
1640                        while (nidx<bases_to_resolve) resolution_idx[nidx++] = 0; // zero all other indices
1641                    }
1642
1643                    delete [] buffer;
1644                    delete [] resolution_max_idx;
1645                    delete [] resolution_idx;
1646
1647                    pd_assert(!err);
1648                    selection_id->insert_default("", "");
1649                }
1650
1651                delete [] offsets_to_resolve;
1652            }
1653        }
1654        else { // empty input
1655            selection_id->insert_default("", "");
1656        }
1657    }
1658    if (err) selection_id->insert_default(err, "");
1659    selection_id->update();
1660}
1661
1662enum ModMode { TS_MOD_CLEAR, TS_MOD_REV_COMPL, TS_MOD_COMPL };
1663
1664static void modify_target_string(AW_window *aww, GBDATA *gb_main, ModMode mod_mode) {
1665    AW_root  *root          = aww->get_root();
1666    char     *target_string = root->awar(AWAR_TARGET_STRING)->read_string();
1667    GB_ERROR  error         = 0;
1668
1669    if (mod_mode == TS_MOD_CLEAR) target_string[0] = 0;
1670    else {
1671        GB_transaction    ta(gb_main);
1672        GB_alignment_type ali_type = GBT_get_alignment_type(gb_main, GBT_get_default_alignment(gb_main));
1673        if (ali_type == GB_AT_UNKNOWN) {
1674            error = GB_await_error();
1675        }
1676        else if (mod_mode == TS_MOD_REV_COMPL) {
1677            char T_or_U;
1678            error = GBT_determine_T_or_U(ali_type, &T_or_U, "reverse-complement");
1679            if (!error) GBT_reverseComplementNucSequence(target_string, strlen(target_string), T_or_U);
1680        }
1681        else if (mod_mode == TS_MOD_COMPL) {
1682            char T_or_U;
1683            error = GBT_determine_T_or_U(ali_type, &T_or_U, "complement");
1684            if (!error) freeset(target_string, GBT_complementNucSequence(target_string, strlen(target_string), T_or_U));
1685        }
1686    }
1687
1688    if (error) aw_message(error);
1689    else root->awar(AWAR_TARGET_STRING)->write_string(target_string);
1690    free(target_string);
1691}
1692
1693static void clear_itarget(AW_window *aww) {
1694    aww->get_root()->awar(AWAR_ITARGET_STRING)->write_string("");
1695}
1696
1697static AW_window *create_IUPAC_resolve_window(AW_root *root, GBDATA *gb_main) {
1698    AW_window_simple *aws = new AW_window_simple;
1699
1700    aws->init(root, "PROBE_MATCH_RESOLVE_IUPAC", "Resolve IUPAC for Probe Match");
1701    aws->load_xfig("pd_match_iupac.fig");
1702
1703    aws->button_length(11);
1704
1705    aws->at("close");
1706    aws->callback(AW_POPDOWN);
1707    aws->create_button("CLOSE", "CLOSE", "C");
1708
1709    aws->at("help");
1710    aws->callback(makeHelpCallback("pd_match_iupac.hlp"));
1711    aws->create_button("HELP", "HELP", "H");
1712
1713    aws->at("istring");
1714    aws->create_input_field(AWAR_ITARGET_STRING, 32);
1715
1716    aws->at("iresult");
1717    AW_selection_list *iselection_id;
1718    iselection_id = aws->create_selection_list(AWAR_PD_MATCH_RESOLVE, 32, 15, true);
1719    iselection_id->insert_default("---empty---", "");
1720
1721    // add callback for automatic decomposition of AWAR_ITARGET_STRING:
1722    RootCallback  upd_cb       = makeRootCallback(resolve_IUPAC_target_string, iselection_id, gb_main);
1723    AW_awar      *awar_itarget = root->awar(AWAR_ITARGET_STRING);
1724    awar_itarget->add_callback(upd_cb);
1725    root->awar(AWAR_DEFAULT_ALIGNMENT)->add_callback(upd_cb);
1726
1727    aws->at("match_all");
1728    aws->callback(makeWindowCallback(probe_match_all_event, iselection_id, gb_main));
1729    aws->create_button("MATCH_ALL", "Match all", "M");
1730
1731    aws->at("clear");
1732    aws->callback(clear_itarget);
1733    aws->create_button("CLEAR", "Clear", "r");
1734
1735    aws->at("iupac_info");
1736    aws->callback(AWT_create_IUPAC_info_window);
1737    aws->create_button("IUPAC_INFO", "IUPAC info", "I");
1738
1739    awar_itarget->touch(); // force initial refresh for saved value
1740
1741    return aws;
1742}
1743
1744static void popupSaiProbeMatchWindow(AW_window *aw, GBDATA *gb_main) {
1745    static AW_window *aw_saiProbeMatch = 0;
1746
1747    if (!aw_saiProbeMatch) aw_saiProbeMatch = createSaiProbeMatchWindow(aw->get_root(), gb_main);
1748    if (g_spd) transferProbeData(g_spd); // transferring probe data to saiProbeMatch function
1749
1750    aw_saiProbeMatch->activate();
1751}
1752
1753static AWT_config_mapping_def probe_match_mapping_def[] = {
1754    // main window:
1755    { AWAR_TARGET_STRING,       "target" },
1756    { AWAR_PD_MATCH_COMPLEMENT, "complement" },
1757    { AWAR_PD_MATCH_MARKHITS,   "markhits" },
1758    { AWAR_PD_MATCH_WRITE2TMP,  "writetmp" },
1759    { AWAR_PD_MATCH_AUTOMATCH,  "automatch" },
1760
1761    // expert window:
1762    { AWAR_PD_MATCH_NMATCHES,   "nmatches" },
1763    { AWAR_PD_MATCH_LIM_NMATCH, "limitnmatch" },
1764    { AWAR_PD_MATCH_MAX_RES,    "maxresults" },
1765
1766    { 0, 0 }
1767};
1768
1769
1770AW_window *create_probe_match_window(AW_root *root, GBDATA *gb_main) {
1771    static AW_window_simple *aws = 0; // the one and only probe match window
1772    if (!aws) {
1773        aws = new AW_window_simple;
1774
1775        aws->init(root, "PROBE_MATCH", "PROBE MATCH");
1776        aws->load_xfig("pd_match.fig");
1777
1778        aws->auto_space(5, 5);
1779
1780        aws->at("close");
1781        aws->callback(AW_POPDOWN);
1782        aws->create_button("CLOSE", "CLOSE", "C");
1783
1784        aws->callback(makeHelpCallback("probematch.hlp"));
1785        aws->at("help");
1786        aws->create_button("HELP", "HELP", "H");
1787
1788        aws->at("string");
1789        aws->create_input_field(AWAR_TARGET_STRING, 32);
1790
1791        AW_selection_list *selection_id;
1792        aws->at("result");
1793        selection_id = aws->create_selection_list(AWAR_PD_SELECTED_MATCH, 110, 15, true);
1794        selection_id->insert_default("****** No results yet *******", "");  // if list is empty -> crashed if new species was selected in ARB_EDIT4
1795
1796        static SmartPtr<TypedSelectionList> typed_selection = new TypedSelectionList("match", selection_id, "probe match", "probe_match");
1797        aws->at("print");
1798        aws->callback(makeWindowCallback(create_print_box_for_selection_lists, &*typed_selection));
1799        aws->create_button("PRINT", "PRINT", "P");
1800
1801        aws->at("matchSai");
1802        aws->help_text("saiProbe.hlp");
1803        aws->callback(makeWindowCallback(popupSaiProbeMatchWindow, gb_main));
1804        aws->create_button("MATCH_SAI", "Match SAI", "S");
1805
1806        aws->callback(makeCreateWindowCallback(create_probe_expert_window, false));
1807        aws->at("expert");
1808        aws->create_button("EXPERT", "EXPERT", "X");
1809
1810        aws->at("pt_server");
1811        awt_create_PTSERVER_selection_button(aws, AWAR_PT_SERVER);
1812
1813        aws->at("complement");
1814        aws->create_toggle(AWAR_PD_MATCH_COMPLEMENT);
1815
1816        aws->at("mark");
1817        aws->create_toggle(AWAR_PD_MATCH_MARKHITS);
1818
1819        aws->at("weighted");
1820        aws->create_toggle(AWAR_PD_MATCH_SORTBY);
1821
1822        aws->at("mismatches");
1823        aws->create_input_field_with_scaler(AWAR_MAX_MISMATCHES, 5, 200, AW_SCALER_EXP_LOWER);
1824
1825        aws->at("tmp");
1826        aws->create_toggle(AWAR_PD_MATCH_WRITE2TMP);
1827
1828        aws->at("nhits");
1829        aws->create_button(0, AWAR_PD_MATCH_NHITS);
1830
1831        aws->button_length(9);
1832
1833        ProbeMatchEventParam *event_param = new ProbeMatchEventParam(gb_main, selection_id);
1834        aws->callback(RootAsWindowCallback::simple(probe_match_event_using_awars, event_param));
1835        aws->at("match");
1836        aws->create_button("MATCH", "MATCH", "D");
1837
1838        aws->at("auto");
1839        aws->label("Auto");
1840        aws->create_toggle(AWAR_PD_MATCH_AUTOMATCH);
1841        enable_auto_match_cb(root, event_param);
1842
1843        aws->callback(makeWindowCallback(modify_target_string, gb_main, TS_MOD_CLEAR));
1844        aws->at("clear");
1845        aws->create_button("CLEAR", "Clear", "0");
1846
1847        aws->callback(makeWindowCallback(modify_target_string, gb_main, TS_MOD_REV_COMPL));
1848        aws->at("revcompl");
1849        aws->create_button("REVCOMPL", "RevCompl", "R");
1850
1851        aws->callback(makeWindowCallback(modify_target_string, gb_main, TS_MOD_COMPL));
1852        aws->at("compl");
1853        aws->create_button("COMPL", "Compl", "C");
1854
1855        aws->callback(makeCreateWindowCallback(create_IUPAC_resolve_window, gb_main));
1856        aws->at("iupac");
1857        aws->create_button("IUPAC", "IUPAC", "I");
1858
1859        aws->at("config");
1860        AWT_insert_config_manager(aws, AW_ROOT_DEFAULT, "probe_match", makeConfigSetupCallback(setup_probe_config, probe_match_mapping_def));
1861    }
1862    return aws;
1863}
1864
1865static void pd_start_pt_server(AW_window *aww) {
1866    const char *server_tag = GBS_ptserver_tag(aww->get_root()->awar(AWAR_PROBE_ADMIN_PT_SERVER)->read_int());
1867    arb_progress progress("Connecting PT-server");
1868    GB_ERROR error = arb_look_and_start_server(AISC_MAGIC_NUMBER, server_tag);
1869    if (error) aw_message(error);
1870}
1871
1872static void pd_kill_pt_server(AW_window *aww, bool kill_all) {
1873    if (aw_ask_sure("kill_ptserver",
1874                    GBS_global_string("Are you sure to stop %s", kill_all ? "all servers" : "that server")))
1875    {
1876        long min = 0;
1877        long max = 0;
1878
1879        if (kill_all) {
1880            const char * const *pt_servers = GBS_get_arb_tcp_entries("ARB_PT_SERVER*");
1881            while (pt_servers[max]) max++;
1882        }
1883        else {
1884            min = max = aww->get_root()->awar(AWAR_PROBE_ADMIN_PT_SERVER)->read_int(); // selected server
1885        }
1886
1887        arb_progress progress("Stopping PT-servers..", max-min+1);
1888        GB_ERROR     error = NULL;
1889
1890        for (int i = min; i <= max && !error;  i++) {
1891            char *choice = GBS_ptserver_id_to_choice(i, 0);
1892            if (!choice) {
1893                error = GB_await_error();
1894            }
1895            else {
1896                progress.subtitle(GBS_global_string("Trying to stop '%s'", choice));
1897
1898                const char *server_tag = GBS_ptserver_tag(i);
1899                GB_ERROR    kill_error = arb_look_and_kill_server(AISC_MAGIC_NUMBER, server_tag);
1900
1901                if (kill_error) aw_message(GBS_global_string("Could not stop '%s' (Reason: %s)", choice, kill_error));
1902                else aw_message(GBS_global_string("Stopped '%s'", choice));
1903
1904                free(choice);
1905            }
1906            progress.inc_and_check_user_abort(error);
1907        }
1908        progress.done();
1909        aw_message_if(error);
1910    }
1911}
1912
1913static const char *ptserver_directory_info_command(const char *dirname, const char *directory) {
1914    return GBS_global_string("echo 'Contents of directory %s:'; echo; (cd \"%s\"; ls -hl); echo; "
1915                             "echo 'Available disk space in %s:'; echo; df -h \"%s\"; echo; ",
1916                             dirname, directory,
1917                             dirname, directory);
1918
1919}
1920
1921static void pd_query_pt_server(AW_window *aww) {
1922    const char *server_tag = GBS_ptserver_tag(aww->get_root()->awar(AWAR_PROBE_ADMIN_PT_SERVER)->read_int());
1923
1924    GBS_strstruct *strstruct = GBS_stropen(1024);
1925    GBS_strcat(strstruct, ptserver_directory_info_command("ARBHOME/lib/pts", "$ARBHOME/lib/pts"));
1926
1927    const char *ARB_LOCAL_PTS = ARB_getenv_ignore_empty("ARB_LOCAL_PTS");
1928    if (ARB_LOCAL_PTS) GBS_strcat(strstruct, ptserver_directory_info_command("ARB_LOCAL_PTS", "$ARB_LOCAL_PTS")); // only defined if called via 'arb'-script
1929    else               GBS_strcat(strstruct, ptserver_directory_info_command("HOME/.arb_pts", "${HOME}/.arb_pts"));
1930
1931    GBS_strcat(strstruct, "echo 'Running ARB programs:'; echo; ");
1932
1933    GB_ERROR error = NULL;
1934    {
1935        const char *socketid = GBS_read_arb_tcp(server_tag);
1936        if (!socketid) {
1937            error = GB_await_error();
1938        }
1939        else {
1940            char *arb_who = createCallOnSocketHost(socketid, "$ARBHOME/bin/", "arb_who", WAIT_FOR_TERMINATION, NULL);
1941            GBS_strcat(strstruct, arb_who);
1942            free(arb_who);
1943        }
1944    }
1945
1946    char *sys         = GBS_strclose(strstruct);
1947    if (!error) error = GB_xcmd(sys, true, false);
1948    free(sys);
1949
1950    aw_message_if(error);
1951}
1952
1953static void pd_export_pt_server(AW_window *aww, GBDATA *gb_main) {
1954    AW_root  *awr   = aww->get_root();
1955    GB_ERROR  error = 0;
1956
1957    bool create_gene_server = awr->awar(AWAR_PROBE_CREATE_GENE_SERVER)->read_int();
1958    {
1959        GB_transaction ta(gb_main);
1960        if (create_gene_server && !GEN_is_genome_db(gb_main, -1)) create_gene_server = false;
1961
1962        // check alignment first
1963        if (create_gene_server) {
1964            GBDATA *gb_ali     = GBT_get_alignment(gb_main, GENOM_ALIGNMENT);
1965            if (!gb_ali) error = GB_await_error();
1966        }
1967        else { // normal pt server
1968            char              *use     = GBT_get_default_alignment(gb_main);
1969            GB_alignment_type  alitype = GBT_get_alignment_type(gb_main, use);
1970            if (alitype == GB_AT_AA) error = "The PT-server does only support RNA/DNA sequence data";
1971            free(use);
1972        }
1973    }
1974
1975    long        server_num = awr->awar(AWAR_PROBE_ADMIN_PT_SERVER)->read_int();
1976    const char *server_tag  = GBS_ptserver_tag(server_num);
1977
1978    if (!error &&
1979        aw_question("update_ptserver",
1980                    "This function will send your loaded database to the pt_server,\n"
1981                    "which will need a long time (up to several hours) to analyse the data.\n"
1982                    "Until the new server has analyzed all data, no server functions are available.\n\n"
1983                    "Note 1: You must have the write permissions to do that ($ARBHOME/lib/pts/xxx))\n"
1984                    "Note 2: The server will do the job in background,\n"
1985                    "        quitting this program won't affect the server",
1986                    "Cancel,Do it"))
1987    {
1988        arb_progress progress("Updating PT-server");
1989        progress.subtitle("Stopping PT-server");
1990        arb_look_and_kill_server(AISC_MAGIC_NUMBER, server_tag);
1991
1992        const char *ipPort = GBS_read_arb_tcp(server_tag);
1993        const char *file   = NULL;
1994        if (!ipPort) error = GB_await_error();
1995        else {
1996            file = GBS_scan_arb_tcp_param(ipPort, "-d");
1997            GBS_add_ptserver_logentry(GBS_global_string("Started build of '%s'", file));
1998
1999            char *db_name = awr->awar(AWAR_DB_PATH)->read_string();
2000            GBS_add_ptserver_logentry(GBS_global_string("Exporting DB '%s'", db_name));
2001            free(db_name);
2002        }
2003
2004        if (!error) {
2005            progress.subtitle("Exporting the database");
2006            {
2007                const char *mode = GB_supports_mapfile() ? "mbf" : "bf"; // save PT-server database with Fastload file (if supported)
2008                if (create_gene_server) {
2009                    char *temp_server_name = GBS_string_eval(file, "*.arb=*_temp.arb", 0);
2010                    error = GB_save_as(gb_main, temp_server_name, mode);
2011
2012                    if (!error) {
2013                        // convert database (genes -> species)
2014                        progress.subtitle("Preparing DB for gene PT server");
2015                        GBS_add_ptserver_logentry("Preparing DB for gene PT server");
2016                        char *command = GBS_global_string_copy("$ARBHOME/bin/arb_gene_probe %s %s", temp_server_name, file);
2017                        error = GBK_system(command);
2018                        if (error) error = GBS_global_string("Couldn't convert database for gene pt server\n(Reason: %s)", error);
2019                        free(command);
2020                    }
2021                    free(temp_server_name);
2022                }
2023                else { // normal pt_server
2024                    error = GB_save_as(gb_main, file, mode);
2025                }
2026            }
2027        }
2028
2029        if (!error) { // set pt-server database file to same permissions as pts directory
2030            char *dir = const_cast<char*>(strrchr(file, '/'));
2031            if (dir) {
2032                *dir = 0;
2033                long modi = GB_mode_of_file(file);
2034                *dir = '/';
2035                modi &= 0666;
2036                error = GB_set_mode_of_file(file, modi);
2037            }
2038        }
2039
2040        if (!error) {
2041            progress.subtitle("Start PT-server (builds in background)");
2042            error = arb_start_server(server_tag, 1);
2043        }
2044    }
2045    if (error) aw_message(error);
2046}
2047
2048static void pd_view_pt_log(AW_window *) {
2049    AW_edit(GBS_ptserver_logname());
2050}
2051
2052AW_window *create_probe_admin_window(AW_root *root, GBDATA *gb_main) {
2053    bool is_genom_db;
2054    {
2055        GB_transaction ta(gb_main);
2056        is_genom_db = GEN_is_genome_db(gb_main, -1);
2057    }
2058
2059    AW_window_simple *aws = new AW_window_simple;
2060    aws->init(root, "PT_SERVER_ADMIN", "PT_SERVER ADMIN");
2061
2062    aws->load_xfig("pd_admin.fig");
2063
2064
2065    aws->callback(makeHelpCallback("probeadmin.hlp"));
2066    aws->at("help");
2067    aws->create_button("HELP", "HELP", "H");
2068
2069    aws->at("close");
2070    aws->callback(AW_POPDOWN);
2071    aws->create_button("CLOSE", "CLOSE", "C");
2072
2073    aws->button_length(18);
2074
2075    aws->at("pt_server");
2076    awt_create_PTSERVER_selection_list(aws, AWAR_PROBE_ADMIN_PT_SERVER);
2077
2078    aws->at("start");
2079    aws->callback(pd_start_pt_server);
2080    aws->create_button("START_SERVER", "Start server");
2081
2082    aws->at("kill");
2083    aws->callback(makeWindowCallback(pd_kill_pt_server, false));
2084    aws->create_button("KILL_SERVER", "Stop server");
2085
2086    aws->at("query");
2087    aws->callback(pd_query_pt_server);
2088    aws->create_button("CHECK_SERVER", "Check server");
2089
2090    aws->at("kill_all");
2091    aws->callback(makeWindowCallback(pd_kill_pt_server, true));
2092    aws->create_button("KILL_ALL_SERVERS", "Stop all servers");
2093
2094    aws->at("edit");
2095    aws->callback(makeWindowCallback(awt_edit_arbtcpdat_cb, gb_main));
2096    aws->create_button("CREATE_TEMPLATE", "Configure");
2097
2098    aws->at("log");
2099    aws->callback(pd_view_pt_log);
2100    aws->create_button("EDIT_LOG", "View logfile");
2101
2102    aws->at("export");
2103    aws->callback(makeWindowCallback(pd_export_pt_server, gb_main));
2104    aws->create_button("UPDATE_SERVER", "Build server");
2105
2106    if (is_genom_db) {
2107        aws->at("gene_server");
2108        aws->label("Gene server?");
2109        aws->create_toggle(AWAR_PROBE_CREATE_GENE_SERVER);
2110    }
2111
2112    return aws;
2113}
2114
2115// ----------------------------------------------------------------------------
2116
2117static AW_window *create_probe_match_specificity_control_window(AW_root *root) {
2118    static AW_window_simple *aws = NULL;
2119
2120    if (!aws) {
2121        aws = new AW_window_simple;
2122
2123        aws->init(root, "MATCH_DISPLAYCONTROL", "MATCH DISPLAY CONTROL");
2124
2125        aws->auto_space(10, 10);
2126        aws->label_length(35);
2127
2128        const int FIELDSIZE  = 5;
2129        const int SCALERSIZE = 500;
2130
2131        aws->label("Mismatch threshold");
2132        aws->create_input_field_with_scaler(AWAR_PC_MISMATCH_THRESHOLD, FIELDSIZE, SCALERSIZE);
2133
2134        aws->at_newline();
2135
2136        aws->label("Clade marked threshold");
2137        aws->create_input_field_with_scaler(AWAR_DTREE_GROUP_MARKED_THRESHOLD, FIELDSIZE, SCALERSIZE);
2138
2139        aws->at_newline();
2140
2141        aws->label("Clade partially marked threshold");
2142        aws->create_input_field_with_scaler(AWAR_DTREE_GROUP_PARTIALLY_MARKED_THRESHOLD, FIELDSIZE, SCALERSIZE);
2143
2144        aws->at_newline();
2145
2146        aws->callback(TREE_create_marker_settings_window);
2147        aws->create_autosize_button("MARKER_SETTINGS", "Marker display settings", "d");
2148
2149        aws->at_newline();
2150    }
2151
2152    return aws;
2153}
2154
2155// ----------------------------------------------------------------------------
2156
2157struct ArbPM_Context {
2158    AW_selection_list *probes_id;
2159    AWT_canvas        *ntw;
2160
2161    ArbPM_Context()
2162        : probes_id(NULL),
2163          ntw(NULL)
2164    {}
2165};
2166
2167static ArbPM_Context PM_Context;
2168
2169static void       probe_match_update_probe_list(ArbPM_Context *pContext);
2170static AW_window *create_probe_collection_window(AW_root *root, ArbPM_Context *pContext);
2171
2172struct ArbWriteFile_Context {
2173    FILE         *pFile;
2174    arb_progress *pProgress;
2175    int           nLastPercent;
2176
2177    ArbWriteFile_Context()
2178        : pFile(NULL),
2179          pProgress(NULL),
2180          nLastPercent(0)
2181    {}
2182};
2183
2184// ----------------------------------------------------------------------------
2185
2186static bool probe_match_with_specificity_enum_callback(void *pVoidContext, const char *pResult, bool bIsComment, int nItem, int nItems) {
2187    ArbWriteFile_Context *pContext = (ArbWriteFile_Context*)pVoidContext;
2188    int                   nPercent = (int)(100.0 * nItem / nItems);
2189
2190    if (!bIsComment) {
2191        if (pContext->nLastPercent != nPercent) {
2192            pContext->nLastPercent = nPercent;
2193            pContext->pProgress->inc();
2194        }
2195    }
2196
2197    if (pContext->pFile != 0) {
2198        // Update status - put after matching cause matching writes its own status messages
2199        fprintf(pContext->pFile, "%s\n", pResult);
2200    }
2201
2202    return pContext->pProgress->aborted();
2203}
2204
2205// ----------------------------------------------------------------------------
2206
2207static void probe_match_with_specificity_edit_event() {
2208    AW_edit(get_results_manager().resultsFileName(), 0, 0, 0);
2209}
2210
2211// ----------------------------------------------------------------------------
2212
2213class GetMatchesContext { // @@@ merge with ProbeCollDisplay?
2214    float mismatchThreshold;
2215    int   nProbes;
2216
2217    typedef ArbMatchResultPtrByStringMultiMap          MatchMap;
2218    typedef ArbMatchResultPtrByStringMultiMapConstIter MatchMapIter;
2219
2220    const MatchMap& results;
2221public:
2222    GetMatchesContext(float misThres, int numProbes)
2223        : mismatchThreshold(misThres),
2224          nProbes(numProbes),
2225          results(get_results_manager().resultsMap())
2226    {}
2227
2228    void detect(std::string speciesName, NodeMarkers& matches) const {
2229        std::pair<MatchMapIter,MatchMapIter> iter = results.equal_range(speciesName);
2230
2231        for (; iter.first != iter.second ; ++iter.first) {
2232            const ArbMatchResult *pMatchResult = iter.first->second;
2233            if (pMatchResult->weight() <= mismatchThreshold) {
2234                int nProbe = pMatchResult->index();
2235                matches.incMarker(nProbe);
2236            }
2237        }
2238        matches.incNodeSize();
2239    }
2240};
2241
2242static SmartPtr<GetMatchesContext> getMatchesContext;
2243
2244class ProbeCollDisplay : public MarkerDisplay {
2245    ArbProbe *find_probe(int markerIdx) const {
2246        const ArbProbePtrList&   rProbeList = get_probe_collection().probeList();
2247        ArbProbePtrListConstIter wanted     = rProbeList.begin();
2248
2249        if (markerIdx>=0 && markerIdx<int(rProbeList.size())) advance(wanted, markerIdx);
2250        else wanted = rProbeList.end();
2251
2252        return wanted == rProbeList.end() ? NULL : *wanted;
2253    }
2254
2255public:
2256    ProbeCollDisplay(int numProbes)
2257        : MarkerDisplay(numProbes)
2258    {}
2259
2260    // MarkerDisplay interface
2261    const char *get_marker_name(int markerIdx) const OVERRIDE {
2262        ArbProbe *probe = find_probe(markerIdx);
2263        return probe ? probe->name().c_str() : GBS_global_string("<invalid probeindex %i>", markerIdx);
2264    }
2265    void retrieve_marker_state(const char *speciesName, NodeMarkers& matches) OVERRIDE {
2266        getMatchesContext->detect(speciesName, matches);
2267    }
2268
2269    void handle_click(int markerIdx, AW_MouseButton, AWT_graphic_exports&) OVERRIDE {
2270        // select probe in selection list
2271        ArbProbe *probe = find_probe(markerIdx);
2272        if (probe) AW_root::SINGLETON->awar(AWAR_PC_SELECTED_PROBE)->write_string(probe->sequence().c_str());
2273#if defined(DEBUG)
2274        else fprintf(stderr, "ProbeCollDisplay::handle_click: no probe found for markerIdx=%i\n", markerIdx);
2275#endif
2276    }
2277};
2278
2279inline bool displays_probeColl_markers(MarkerDisplay *md) { return dynamic_cast<ProbeCollDisplay*>(md); }
2280
2281static void refresh_matchedProbesDisplay_cb(AW_root *root, AWT_canvas *ntw) {
2282    // setup parameters for display of probe collection matches and trigger tree refresh
2283    LocallyModify<bool> flag(allow_probe_match_event, false);
2284
2285    AWT_graphic_tree *agt     = DOWNCAST(AWT_graphic_tree*, ntw->gfx);
2286    bool              display = get_results_manager().hasResults();
2287
2288    MarkerDisplay *markerDisplay = agt->get_marker_display();
2289    bool           redraw        = false;
2290    if (display) {
2291        size_t probesCount = get_probe_collection().probeList().size();
2292        getMatchesContext  = new GetMatchesContext(root->awar(AWAR_PC_MISMATCH_THRESHOLD)->read_float(), probesCount);
2293
2294        if (displays_probeColl_markers(markerDisplay) && probesCount == size_t(markerDisplay->size())) {
2295            markerDisplay->flush_cache();
2296        }
2297        else {
2298            agt->set_marker_display(new ProbeCollDisplay(get_probe_collection().probeList().size()));
2299        }
2300        redraw = true;
2301    }
2302    else {
2303        if (displays_probeColl_markers(markerDisplay)) {
2304            agt->hide_marker_display();
2305            redraw = true;
2306        }
2307    }
2308
2309    if (redraw) root->awar(AWAR_TREE_REFRESH)->touch();
2310}
2311
2312// ----------------------------------------------------------------------------
2313
2314static void probe_match_with_specificity_event(AW_root *root, AWT_canvas *ntw) {
2315    if (allow_probe_match_event) {
2316        GB_ERROR error = NULL;
2317
2318        ProbeMatchSettings matchSettings(root);
2319        matchSettings.markHits  = 0;
2320        matchSettings.write2tmp = 0;
2321
2322        ArbMatchResultsManager& g_results_manager = get_results_manager();
2323        g_results_manager.reset();
2324
2325        // Using g_probe_collection instance of ArbProbeCollection, need to loop
2326        // through all the probes in the collect and then call probe_match_event,
2327        // collating the results as we go. The results can be obtained from the
2328        // g_spd->probeSeq list.
2329        const ArbProbePtrList& rProbeList = get_probe_collection().probeList();
2330
2331        const int nItems      = rProbeList.size();
2332        int       nItem       = 1;
2333        int       nHits       = 0;
2334        int       nProbeIndex = 0;
2335
2336        // This extra scope needed to ensure the arb_progress object is released
2337        // prior to the next one being used to show progress on write results to file
2338        {
2339            arb_progress progress("Matching probe collection", nItems);
2340
2341            ArbProbeCollection& g_probe_collection = get_probe_collection();
2342
2343            for (ArbProbePtrListConstIter ProbeIter = rProbeList.begin() ; ProbeIter != rProbeList.end() && !error; ++ProbeIter) {
2344                const ArbProbe *pProbe = *ProbeIter;
2345
2346                if (pProbe != 0) {
2347                    int                nMatches;
2348                    ArbMatchResultSet *pResultSet = g_results_manager.addResultSet(pProbe);
2349
2350                    // Update status - put after matching cause matching writes its own status messages
2351                    progress.subtitle(GBS_global_string("Matching probe %i of %i", nItem, nItems));
2352
2353                    // Perform match on pProbe
2354                    matchSettings.targetString  = pProbe->sequence();
2355                    matchSettings.maxMismatches = pProbe->allowedMismatches();
2356
2357                    int                   counter = -1;
2358                    ProbeMatchEventParam  match_event(ntw->gb_main, &counter);
2359
2360                    error = probe_match_event(matchSettings, &match_event);
2361
2362                    pResultSet->initialise(pProbe, nProbeIndex);
2363                    nProbeIndex++;
2364
2365                    if (g_spd && g_spd->getHeadline() && !error) {
2366                        ProbeMatchParser parser(pProbe->sequence().c_str(), g_spd->getHeadline());
2367
2368                        if (parser.get_error()) {
2369                            error = parser.get_error();
2370                        }
2371                        else {
2372                            int nStartFullName  = 0;
2373                            int nEndFullName    = 0;
2374
2375                            parser.getColumnRange("fullname", &nStartFullName, &nEndFullName);
2376
2377                            pResultSet->headline(g_spd->getHeadline(), nEndFullName);
2378
2379                            // Collate match results
2380                            nMatches = g_spd->probeSeq.size();
2381
2382                            for (int cn = 0 ; cn < nMatches && !error ; cn++) {
2383                                const std::string& sResult = g_spd->probeSeq[cn];
2384
2385                                ParsedProbeMatch parsed(sResult.c_str(), parser);
2386
2387                                if (parsed.get_error()) {
2388                                    error = parsed.get_error();
2389                                }
2390                                else {
2391                                    char       *pName      = parsed.get_column_content("name", true);
2392                                    char       *pFullName  = parsed.get_column_content("fullname", true);
2393                                    const char *pMatchPart = parsed.get_probe_region();
2394
2395                                    pResultSet->add(pName,
2396                                                    pFullName,
2397                                                    pMatchPart,
2398                                                    sResult.c_str(),
2399                                                    g_probe_collection.matchWeighting());
2400
2401                                    free(pName);
2402                                    free(pFullName);
2403                                }
2404                            }
2405                        }
2406                    }
2407
2408                    if (error) error = GBS_global_string("while matching probe #%i: %s", nItem, error);
2409
2410                    nItem++;
2411                }
2412                progress.inc_and_check_user_abort(error);
2413            }
2414        }
2415
2416        if (!error) {
2417            ArbWriteFile_Context Context;
2418
2419            arb_progress progress("Writing results to file", 100);
2420            progress.subtitle(g_results_manager.resultsFileName());
2421
2422            Context.pFile         = fopen(g_results_manager.resultsFileName(), "w");
2423            Context.pProgress     = &progress;
2424            Context.nLastPercent  = 0;
2425
2426            nHits = g_results_manager.enumerate_results(probe_match_with_specificity_enum_callback, (void*)&Context);
2427
2428            fclose(Context.pFile);
2429
2430            if (!error) error = progress.error_if_aborted();
2431            progress.done();
2432        }
2433
2434        root->awar(AWAR_PC_MATCH_NHITS)->write_int(nHits);
2435
2436        if (error) {
2437            aw_message(error);
2438
2439            // Clear the results set
2440            g_results_manager.reset();
2441        }
2442        else {
2443            // Open the Probe Match Specificity dialog to interactively show how the
2444            // matches target the phylongeny
2445            create_probe_match_specificity_control_window(root)->show();
2446
2447            double oldMaxWeight = g_results_manager.maximumWeight();
2448            g_results_manager.updateResults();
2449            double newMaxWeight = g_results_manager.maximumWeight();
2450
2451            if (newMaxWeight != oldMaxWeight) {
2452                // set new limits for scaler and force current value into limits
2453                newMaxWeight = std::max(newMaxWeight, 0.000001); // avoid invalid limits
2454                root->awar(AWAR_PC_MISMATCH_THRESHOLD)->set_minmax(0.0, newMaxWeight)->touch();
2455            }
2456        }
2457
2458        refresh_matchedProbesDisplay_cb(root, ntw);
2459    }
2460}
2461
2462static void auto_match_cb(AW_root *root, AWT_canvas *ntw) {
2463    if (root->awar(AWAR_PC_AUTO_MATCH)->read_int()) {
2464        probe_match_with_specificity_event(root, ntw);
2465    }
2466}
2467static void trigger_auto_match(AW_root *root) {
2468    root->awar(AWAR_PC_AUTO_MATCH)->touch();
2469}
2470
2471// ----------------------------------------------------------------------------
2472
2473static void probe_forget_matches_event(AW_window *aww, ArbPM_Context *pContext) {
2474    AW_root *root = aww->get_root();
2475
2476    get_results_manager().reset();
2477    root->awar(AWAR_PC_MATCH_NHITS)->write_int(0);
2478    refresh_matchedProbesDisplay_cb(root, pContext->ntw);
2479}
2480
2481static void selected_probe_changed_cb(AW_root *root) {
2482    char *pSequence = root->awar(AWAR_PC_SELECTED_PROBE)->read_string();
2483    if (pSequence) {
2484        const ArbProbe *pProbe = get_probe_collection().find(pSequence);
2485        if (pProbe) {
2486            const char *seq = pProbe->sequence().c_str();
2487            root->awar(AWAR_PC_TARGET_STRING)->write_string(seq);
2488            root->awar(AWAR_PC_TARGET_NAME)  ->write_string(pProbe->name().c_str());
2489
2490            root->awar(AWAR_TARGET_STRING)->write_string(seq); // copy to probe match & match in edit4
2491        }
2492    }
2493    free(pSequence);
2494}
2495
2496static void target_string_changed_cb(AW_root *root) {
2497    char *pSequence = root->awar(AWAR_PC_TARGET_STRING)->read_string();
2498    if (pSequence && pSequence[0]) {
2499        const ArbProbe *pProbe = get_probe_collection().find(pSequence);
2500        if (pProbe) root->awar(AWAR_PC_SELECTED_PROBE)->write_string(pSequence);
2501    }
2502    free(pSequence);
2503}
2504
2505static void match_changed_cb(AW_root *root) {
2506    // automatically adapt to last probe matched
2507    // (also adapts to last selected designed probe)
2508    char *pSequence = root->awar(AWAR_TARGET_STRING)->read_string();
2509    if (pSequence && pSequence[0]) {
2510        AW_awar *awar_target = root->awar(AWAR_PC_TARGET_STRING);
2511        if (strcmp(awar_target->read_char_pntr(), pSequence) != 0) {
2512            root->awar(AWAR_PC_TARGET_NAME)->write_string(""); // clear name
2513        }
2514        awar_target->write_string(pSequence);
2515    }
2516    free(pSequence);
2517}
2518
2519// ----------------------------------------------------------------------------
2520
2521AW_window *create_probe_match_with_specificity_window(AW_root *root, AWT_canvas *ntw) {
2522    static AW_window_simple *aws = 0; // the one and only probeSpec window
2523
2524    if (!aws) {
2525        root->awar(AWAR_PC_MISMATCH_THRESHOLD)->add_callback(makeRootCallback(refresh_matchedProbesDisplay_cb, ntw));
2526
2527        aws = new AW_window_simple;
2528
2529        aws->init(root, "PROBE_MATCH_WITH_SPECIFICITY", "PROBE MATCH WITH SPECIFICITY");
2530
2531        aws->load_xfig("pd_match_with_specificity.fig");
2532
2533        aws->at("close");
2534        aws->callback(AW_POPDOWN);
2535        aws->create_button("CLOSE", "CLOSE", "C");
2536
2537        aws->callback(makeHelpCallback("probespec.hlp"));
2538        aws->at("help");
2539        aws->create_button("HELP", "HELP", "H");
2540
2541        AW_selection_list *probes_id;
2542
2543        aws->at("probes");
2544        probes_id = aws->create_selection_list(AWAR_PC_SELECTED_PROBE, 110, 10, false);
2545        probes_id->insert_default("", "");
2546
2547        PM_Context.probes_id = probes_id;
2548        PM_Context.ntw       = ntw;
2549
2550        aws->callback(makeWindowCallback(probe_match_with_specificity_edit_event));
2551        aws->at("results");
2552        aws->create_button("RESULTS", "RESULTS", "R");
2553
2554        aws->at("pt_server");
2555        awt_create_PTSERVER_selection_button(aws, AWAR_PT_SERVER);
2556
2557        aws->at("nhits");
2558        aws->create_button(0, AWAR_PC_MATCH_NHITS);
2559
2560        aws->callback(makeCreateWindowCallback(create_probe_collection_window, &PM_Context));
2561        aws->at("edit");
2562        aws->create_button("EDIT", "EDIT", "E");
2563
2564        aws->callback(RootAsWindowCallback::simple(probe_match_with_specificity_event, ntw));
2565        aws->at("match");
2566        aws->create_button("MATCH", "MATCH", "M");
2567
2568        aws->callback(makeWindowCallback(probe_forget_matches_event, &PM_Context));
2569        aws->at("forget");
2570        aws->create_button("FORGET", "FORGET", "F");
2571
2572        aws->at("auto");
2573        aws->label("Auto match");
2574        aws->create_toggle(AWAR_PC_AUTO_MATCH);
2575
2576        AW_awar *awar_automatch = root->awar(AWAR_PC_AUTO_MATCH);
2577        awar_automatch->add_callback(makeRootCallback(auto_match_cb, ntw));
2578
2579        aws->callback(makeCreateWindowCallback(create_probe_match_specificity_control_window));
2580        aws->at("control");
2581        aws->create_autosize_button("CONTROL", "Display control", "D");
2582
2583        probe_match_update_probe_list(&PM_Context);
2584
2585        root->awar(AWAR_PC_SELECTED_PROBE)->add_callback(makeRootCallback(selected_probe_changed_cb));
2586        root->awar(AWAR_PC_TARGET_STRING)->add_callback(makeRootCallback(target_string_changed_cb));
2587        root->awar(AWAR_TARGET_STRING)->add_callback(makeRootCallback(match_changed_cb));
2588
2589        awar_automatch->touch(); // automatically run match if 'auto-match' is checked at startup
2590    }
2591
2592    return aws;
2593}
2594
2595// ----------------------------------------------------------------------------
2596
2597struct ArbPC_Context {
2598    AW_selection_list *selection_id;
2599    ArbPM_Context     *PM_Context;
2600
2601    ArbPC_Context()
2602        : selection_id(NULL),
2603          PM_Context(NULL)
2604    {}
2605};
2606
2607static ArbPC_Context PC_Context;
2608
2609// ----------------------------------------------------------------------------
2610
2611static void save_probe_list_to_DB(const ArbProbePtrList& rProbeList, AW_root *root) {
2612    std::string saved;
2613    for (ArbProbePtrListConstIter ProbeIter = rProbeList.begin() ; ProbeIter != rProbeList.end() ; ++ProbeIter) {
2614        const ArbProbe *pProbe = *ProbeIter;
2615        if (pProbe) {
2616            // Note: target sequences/names do not contain '#'/':' (see REPLACE_TARGET_CONTROL_CHARS)
2617            saved = saved + '#'+pProbe->name()+':'+pProbe->sequence();
2618        }
2619    }
2620
2621    root->awar(AWAR_PC_CURRENT_COLLECTION)->write_string(saved.empty() ? "" : saved.c_str()+1);
2622}
2623
2624static void show_probes_in_sellist(const ArbProbePtrList& rProbeList, AW_selection_list *sellist) {
2625    sellist->clear();
2626    sellist->insert_default("", "");
2627    for (ArbProbePtrListConstIter ProbeIter = rProbeList.begin() ; ProbeIter != rProbeList.end() ; ++ProbeIter) {
2628        const ArbProbe *pProbe = *ProbeIter;
2629        if (pProbe) {
2630            sellist->insert(pProbe->displayName().c_str(), pProbe->sequence().c_str());
2631        }
2632    }
2633    sellist->update();
2634}
2635
2636static void load_probe_collection(AW_window *aww, ArbPC_Context *Context, const char * const *awar_filename) {
2637    char *pFileName = aww->get_root()->awar(*awar_filename)->read_string();
2638
2639    ArbProbeCollection ProbeCollection;
2640    std::string        sErrorMessage;
2641
2642    if (ProbeCollection.openXML(pFileName, sErrorMessage)) {
2643        int    cn;
2644        char   buffer[256] = {0};
2645        float  weights[16] = {0.0};
2646        float  dWidth      = 1.0;
2647        float  dBias       = 0.0;
2648
2649        ArbProbeCollection& g_probe_collection = get_probe_collection();
2650        g_probe_collection = ProbeCollection;
2651
2652        g_probe_collection.getParameters(weights, dWidth, dBias);
2653
2654        AW_root *root = AW_root::SINGLETON;
2655        root->awar(AWAR_PC_MATCH_WIDTH)->write_float(dWidth);
2656        root->awar(AWAR_PC_MATCH_BIAS)->write_float(dBias);
2657
2658        for (cn = 0; cn < 16 ; cn++) {
2659            sprintf(buffer, AWAR_PC_MATCH_WEIGHTS"%i", cn);
2660
2661            root->awar(buffer)->write_float(weights[cn]);
2662        }
2663
2664        const ArbProbePtrList& rProbeList = g_probe_collection.probeList();
2665
2666        save_probe_list_to_DB(rProbeList, root);
2667        show_probes_in_sellist(rProbeList, Context->selection_id);
2668
2669        probe_match_update_probe_list(Context->PM_Context);
2670        aww->hide();
2671        trigger_auto_match(root);
2672    }
2673    else {
2674        // Print error message
2675        aw_message(sErrorMessage.c_str());
2676    }
2677
2678    free(pFileName);
2679}
2680
2681// ----------------------------------------------------------------------------
2682
2683static void probe_collection_update_parameters() {
2684    AW_root *root = AW_root::SINGLETON;
2685
2686    int cn;
2687    char buffer[256] = {0};
2688
2689    float weights[16] = {0.0};
2690    float dWidth = root->awar(AWAR_PC_MATCH_WIDTH)->read_float();
2691    float dBias  = root->awar(AWAR_PC_MATCH_BIAS)->read_float();
2692
2693    for (cn = 0; cn < 16 ; cn++) {
2694        sprintf(buffer, AWAR_PC_MATCH_WEIGHTS"%i", cn);
2695
2696        weights[cn] = root->awar(buffer)->read_float();
2697    }
2698
2699    ArbProbeCollection& g_probe_collection = get_probe_collection();
2700    g_probe_collection.setParameters(weights, dWidth, dBias);
2701
2702    save_probe_list_to_DB(g_probe_collection.probeList(), root);
2703}
2704
2705// ----------------------------------------------------------------------------
2706
2707static void save_probe_collection(AW_window *aww, const char * const *awar_filename) {
2708    char *pFileName = aww->get_root()->awar(*awar_filename)->read_string();
2709
2710    struct stat   FileStatus;
2711    int           nResult = ::stat(pFileName, &FileStatus);
2712    bool          bWrite  = true;
2713
2714    if (nResult == 0) {
2715        bWrite = (aw_question("probe_collection_save", "File already exists. Overwrite?", "YES,NO") == 0);
2716    }
2717
2718    if (bWrite) {
2719        probe_collection_update_parameters();
2720        get_probe_collection().saveXML(pFileName);
2721
2722        aww->hide();
2723    }
2724
2725    free(pFileName);
2726}
2727
2728// ----------------------------------------------------------------------------
2729
2730static void add_probe_to_collection_event(AW_window *aww, ArbPC_Context *pContext) {
2731    AW_selection_list *selection_id = pContext->selection_id;
2732    if (selection_id) {
2733        AW_root *root      = aww->get_root();
2734        char    *pSequence = root->awar(AWAR_PC_TARGET_STRING)->read_string();
2735        char    *pName     = root->awar(AWAR_PC_TARGET_NAME)->read_string();
2736
2737        GB_ERROR error = NULL;
2738        if (!pSequence || !pSequence[0]) {
2739            error = "Please enter a target string";
2740        }
2741        else if (get_probe_collection().find(pSequence)) {
2742            error = "Target string already in collection";
2743        }
2744
2745        if (!error) {
2746            const ArbProbe *pProbe = 0;
2747
2748            if (get_probe_collection().add(pName, pSequence, &pProbe) && (pProbe != 0)) {
2749                selection_id->insert(pProbe->displayName().c_str(), pSequence);
2750                selection_id->update();
2751                probe_match_update_probe_list(pContext->PM_Context);
2752                probe_collection_update_parameters();
2753
2754                root->awar(AWAR_PC_SELECTED_PROBE)->write_string(pSequence);
2755                trigger_auto_match(root);
2756            }
2757            else {
2758                error = "failed to add probe";
2759            }
2760        }
2761
2762        aw_message_if(error);
2763
2764        free(pName);
2765        free(pSequence);
2766    }
2767}
2768
2769static void modify_probe_event(AW_window *aww, ArbPC_Context *pContext) {
2770    AW_selection_list *selection_id = pContext->selection_id;
2771    if (selection_id) {
2772        AW_root *root            = aww->get_root();
2773        AW_awar *awar_selected   = root->awar(AWAR_PC_SELECTED_PROBE);
2774        char    *oldSequence     = awar_selected->read_string();
2775        char    *pSequence       = root->awar(AWAR_PC_TARGET_STRING)->read_string();
2776        char    *pName           = root->awar(AWAR_PC_TARGET_NAME)->read_string();
2777        bool     sequenceChanged = false;
2778
2779        GB_ERROR error = NULL;
2780        if (!pSequence || !pSequence[0]) {
2781            error = "Please enter a target string";
2782        }
2783        else if (!oldSequence || !oldSequence[0]) {
2784            error = "Please select probe to modify";
2785        }
2786        else {
2787            sequenceChanged = strcmp(oldSequence, pSequence) != 0;
2788            if (sequenceChanged) { // sequence changed -> test vs duplicate
2789                if (get_probe_collection().find(pSequence)) {
2790                    error = "Target string already in collection";
2791                }
2792            }
2793        }
2794
2795        if (!error) {
2796            const ArbProbe *pProbe = 0;
2797
2798            if (get_probe_collection().replace(oldSequence, pName, pSequence, &pProbe) && (pProbe != 0)) {
2799                AW_selection_list_iterator entry(selection_id, selection_id->get_index_of_selected());
2800                entry.set_displayed(pProbe->displayName().c_str());
2801                entry.set_value(pSequence);
2802                selection_id->update();
2803
2804                probe_match_update_probe_list(pContext->PM_Context);
2805                probe_collection_update_parameters();
2806
2807                awar_selected->write_string(pSequence);
2808                trigger_auto_match(root);
2809            }
2810            else {
2811                error = "failed to replace probe";
2812            }
2813        }
2814
2815        aw_message_if(error);
2816
2817        free(pName);
2818        free(pSequence);
2819        free(oldSequence);
2820    }
2821}
2822
2823static void remove_probe_from_collection_event(AW_window *aww, ArbPC_Context *pContext) {
2824    AW_selection_list *selection_id = pContext->selection_id;
2825    if (selection_id) {
2826        AW_root *root      = aww->get_root();
2827        char    *pSequence = root->awar(AWAR_PC_SELECTED_PROBE)->read_string();
2828        if (pSequence) {
2829            const ArbProbe *pProbe = get_probe_collection().find(pSequence);
2830            if (pProbe) {
2831                int idx = selection_id->get_index_of_selected();
2832                selection_id->delete_element_at(idx);
2833
2834                if (selection_id->size() < 1) {
2835                    selection_id->insert_default("", "");
2836                }
2837                selection_id->update();
2838                selection_id->select_element_at(idx); // select next probe for deletion
2839
2840                get_probe_collection().remove(pSequence);
2841                probe_match_update_probe_list(pContext->PM_Context);
2842                probe_collection_update_parameters();
2843
2844                trigger_auto_match(root);
2845            }
2846            free(pSequence);
2847        }
2848    }
2849}
2850
2851// ----------------------------------------------------------------------------
2852
2853static AW_window *probe_collection_load_prompt(AW_root *root, ArbPC_Context *pContext) {
2854    static char *awar_name = NULL; // do not free, bound to callback
2855    return awt_create_load_box(root, "Load", "probe collection",
2856                               ".", "xpc", &awar_name,
2857                               makeWindowCallback(load_probe_collection, pContext, (const char*const*)&awar_name));
2858}
2859static AW_window *probe_collection_save_prompt(AW_root *root) {
2860    static char *awar_name = NULL; // do not free, bound to callback
2861    return awt_create_load_box(root, "Save", "probe collection",
2862                               ".", "xpc", &awar_name,
2863                               makeWindowCallback(save_probe_collection, (const char*const*)&awar_name));
2864}
2865
2866// ----------------------------------------------------------------------------
2867
2868static void probe_match_update_probe_list(ArbPM_Context *pContext) {
2869    if (pContext) {
2870        AW_selection_list *sellist = pContext->probes_id;
2871        if (sellist) show_probes_in_sellist(get_probe_collection().probeList(), sellist);
2872    }
2873}
2874static void clear_probe_collection_event(AW_window *aww, ArbPC_Context *pContext) {
2875    if (get_probe_collection().clear()) {
2876        probe_match_update_probe_list(pContext->PM_Context);
2877        show_probes_in_sellist(get_probe_collection().probeList(), pContext->selection_id);
2878        trigger_auto_match(aww->get_root());
2879    }
2880}
2881
2882// ----------------------------------------------------------------------------
2883
2884static void probe_collection_close(AW_window *aww) {
2885    probe_collection_update_parameters();
2886    aww->hide();
2887}
2888
2889// ----------------------------------------------------------------------------
2890
2891static AW_window *create_probe_collection_window(AW_root *root, ArbPM_Context *pContext) {
2892    static AW_window_simple *aws = 0;     // the one and only probe match window
2893    char                     buffer[256];
2894
2895    pd_assert(pContext);
2896    PC_Context.PM_Context = pContext;
2897
2898    if (!aws) {
2899        aws = new AW_window_simple;
2900
2901        aws->init(root, "PROBE_COLLECTION", "PROBE COLLECTION");
2902
2903        aws->load_xfig("pd_match_probe_collection.fig");
2904
2905        aws->callback(probe_collection_close);
2906        aws->at("close");
2907        aws->create_button("CLOSE", "CLOSE", "C");
2908
2909        aws->callback(makeHelpCallback("probespec.hlp"));
2910        aws->at("help");
2911        aws->create_button("HELP", "HELP", "H");
2912
2913        AW_selection_list *selection_id;
2914
2915        aws->at("probes");
2916        selection_id = aws->create_selection_list(AWAR_PC_SELECTED_PROBE, 110, 10, false);
2917        selection_id->insert_default("", "");
2918
2919        PC_Context.selection_id = selection_id;
2920
2921        aws->at("string");
2922        aws->create_input_field(AWAR_PC_TARGET_STRING, 32);
2923
2924        aws->at("name");
2925        aws->create_input_field(AWAR_PC_TARGET_NAME, 32);
2926
2927        aws->callback(makeWindowCallback(add_probe_to_collection_event, &PC_Context));
2928        aws->at("add");
2929        aws->create_button("ADD", "ADD", "A");
2930
2931        aws->callback(makeWindowCallback(modify_probe_event, &PC_Context));
2932        aws->at("modify");
2933        aws->create_button("MODIFY", "MODIFY", "M");
2934
2935        aws->callback(makeWindowCallback(remove_probe_from_collection_event, &PC_Context));
2936        aws->at("remove");
2937        aws->create_button("REMOVE", "REMOVE", "R");
2938
2939        aws->callback(makeCreateWindowCallback(probe_collection_load_prompt, &PC_Context));
2940        aws->at("open");
2941        aws->create_button("LOAD", "LOAD", "L");
2942
2943        aws->callback(makeCreateWindowCallback(probe_collection_save_prompt));
2944        aws->at("save");
2945        aws->create_button("SAVE", "SAVE", "S");
2946
2947        aws->callback(makeWindowCallback(clear_probe_collection_event, &PC_Context));
2948        aws->at("clear");
2949        aws->create_button("CLEAR", "CLEAR", "L");
2950
2951        for (int i = 0 ; i < 16 ; i++) {
2952            sprintf(buffer, "%i", i);
2953            aws->at(buffer);
2954            sprintf(buffer, AWAR_PC_MATCH_WEIGHTS"%i", i);
2955            aws->create_input_field(buffer, 4);
2956            root->awar(buffer)->add_callback(trigger_auto_match);
2957        }
2958
2959        aws->at("width");
2960        aws->create_input_field(AWAR_PC_MATCH_WIDTH, 5);
2961        root->awar(AWAR_PC_MATCH_WIDTH)->add_callback(trigger_auto_match);
2962
2963        aws->at("bias");
2964        aws->create_input_field(AWAR_PC_MATCH_BIAS, 5);
2965        root->awar(AWAR_PC_MATCH_BIAS)->add_callback(trigger_auto_match);
2966
2967        show_probes_in_sellist(get_probe_collection().probeList(), selection_id);
2968    }
2969    return aws;
2970}
Note: See TracBrowser for help on using the repository browser.