source: branches/properties/PROBE_DESIGN/probe_collection.cxx

Last change on this file was 16766, checked in by westram, 7 years ago
File size: 50.0 KB
Line 
1// ----------------------------------------------------------------------------
2// probe_collection.cxx
3// ----------------------------------------------------------------------------
4// Implementations of classes used to create and manage probe collections in Arb.
5// ----------------------------------------------------------------------------
6
7
8#include "probe_collection.hxx"
9#include <xercesc/dom/DOM.hpp>
10#include <xercesc/dom/DOMDocument.hpp>
11#include <xercesc/dom/DOMDocumentType.hpp>
12#include <xercesc/dom/DOMElement.hpp>
13#include <xercesc/dom/DOMImplementation.hpp>
14#include <xercesc/dom/DOMImplementationLS.hpp>
15#include <xercesc/dom/DOMNodeIterator.hpp>
16#include <xercesc/dom/DOMNodeList.hpp>
17#include <xercesc/dom/DOMText.hpp>
18#include <xercesc/parsers/XercesDOMParser.hpp>
19#include <xercesc/util/XMLUni.hpp>
20#include <math.h>
21#include <arbdbt.h>
22#include <algorithm>
23
24using namespace xercesc;
25
26const size_t ArbMIN_PROBE_LENGTH = 6;
27
28typedef std::pair<const std::string, ArbMatchResult*> ArbMatchResultPtrStringPair;
29typedef std::pair<const double,      ArbMatchResult*> ArbMatchResultPtrDoublePair;
30
31// ----------------------------------------------------------------------------
32// Provide access to global objects
33// ----------------------------------------------------------------------------
34
35ArbProbeCollection& get_probe_collection() {
36    static ArbProbeCollection g_probe_collection;
37    return g_probe_collection;
38}
39ArbMatchResultsManager& get_results_manager() {
40    static ArbMatchResultsManager g_results_manager;
41    return g_results_manager;
42}
43
44static ArbStringCache& get_string_cache() {
45    static ArbStringCache g_string_cache;
46    return g_string_cache;
47}
48
49// ----------------------------------------------------------------------------
50// ArbStringCache method implementations
51// ----------------------------------------------------------------------------
52void ArbStringCache::open() {
53    char *uniqueName   = GB_unique_filename("ArbString", "cache");
54    char *pTmpFileName = GB_create_tempfile(uniqueName);
55
56    if (pTmpFileName) {
57        WriteCacheFile  = fopen(pTmpFileName, "wb");
58        ReadCacheFile   = fopen(pTmpFileName, "rb");
59        IsOpen          = WriteCacheFile && ReadCacheFile;
60        FileName        = pTmpFileName;
61    }
62
63    free(pTmpFileName);
64    free(uniqueName);
65}
66
67// ----------------------------------------------------------------------------
68
69void ArbStringCache::close() {
70    if (ReadCacheFile) {
71        fclose(ReadCacheFile);
72        ReadCacheFile = NULp;
73    }
74
75    if (WriteCacheFile) {
76        fclose(WriteCacheFile);
77        unlink(FileName.c_str());
78        WriteCacheFile = NULp;
79    }
80
81    if (ReadBuffer) {
82        delete [] ReadBuffer;
83        ReadBuffer = NULp;
84    }
85
86    ReadBufferLength  = 0;
87    IsOpen            = false;
88}
89
90// ----------------------------------------------------------------------------
91
92bool ArbStringCache::allocReadBuffer(int nLength) const {
93    if (nLength + 1 > ReadBufferLength) {
94        if (ReadBuffer) {
95            delete [] ReadBuffer;
96        }
97
98        ReadBufferLength  = nLength + 1;
99        ReadBuffer        = new char[ReadBufferLength];
100    }
101
102    return ReadBuffer;
103}
104
105// ----------------------------------------------------------------------------
106
107ArbStringCache::ArbStringCache() {
108    IsOpen            = false;
109    WriteCacheFile    = NULp;
110    ReadCacheFile     = NULp;
111    ReadBuffer        = NULp;
112    ReadBufferLength  = 0;
113
114    open();
115}
116
117// ----------------------------------------------------------------------------
118
119ArbStringCache::~ArbStringCache() {
120    close();
121}
122
123// ----------------------------------------------------------------------------
124
125bool ArbStringCache::saveString(const char *pString, ArbCachedString& rCachedString) {
126    bool bSaved = saveString(pString, strlen(pString), rCachedString);
127
128    return bSaved;
129}
130
131// ----------------------------------------------------------------------------
132
133bool ArbStringCache::saveString(const char *pString, int nLength, ArbCachedString& rCachedString) {
134    bool bSaved = false;
135
136    if (IsOpen && pString) {
137        rCachedString.Len = nLength;
138
139        fgetpos(WriteCacheFile, &rCachedString.Pos);
140        fwrite(pString, nLength * sizeof(char), 1, WriteCacheFile);
141
142        bSaved = true;
143    }
144
145    return bSaved;
146}
147
148// ----------------------------------------------------------------------------
149
150bool ArbStringCache::loadString(std::string& rString, const ArbCachedString& rCachedString) const {
151    bool bLoaded = false;
152
153    if (IsOpen                  &&
154        (rCachedString.Len > 0) &&
155        allocReadBuffer(rCachedString.Len))
156    {
157        fpos_t nPos = rCachedString.Pos;
158        fsetpos(ReadCacheFile, &nPos);
159
160        size_t read = fread(ReadBuffer, sizeof(char), rCachedString.Len, ReadCacheFile);
161        if (read == size_t(rCachedString.Len)) {
162            ReadBuffer[rCachedString.Len] = '\0';
163
164            rString = ReadBuffer;
165            bLoaded = true;
166        }
167    }
168
169    return bLoaded;
170}
171
172// ----------------------------------------------------------------------------
173
174void ArbStringCache::flush() {
175    if (IsOpen) {
176        // Close and re-open to delete old cache file and create a new one
177        close();
178        open();
179    }
180}
181
182
183// ----------------------------------------------------------------------------
184// ArbProbeMatchWeighting method implementations
185// ----------------------------------------------------------------------------
186int ArbProbeMatchWeighting::toIndex(char nC) const {
187    int nIndex = 0;
188
189    switch (nC) {
190        case 'A':
191        case 'a': {
192            nIndex = 0;
193            break;
194        }
195
196        case 'C':
197        case 'c': {
198            nIndex = 1;
199            break;
200        }
201
202        case 'G':
203        case 'g': {
204            nIndex = 2;
205            break;
206        }
207
208        case 'U':
209        case 'u':
210        case 'T':
211        case 't': {
212            nIndex = 3;
213            break;
214        }
215
216        default: {
217            arb_assert(0);
218            break;
219        }
220    }
221
222    return nIndex;
223}
224
225// ----------------------------------------------------------------------------
226
227double ArbProbeMatchWeighting::positionalWeight(int nPos, int nLength) const {
228    double dS       = -(::log(10) / Width);
229    double dP       = ((2.0 * nPos - nLength) / nLength) - Bias;
230    double dWeight  = ::exp(dS * dP * dP);
231
232    return dWeight;
233}
234
235// ----------------------------------------------------------------------------
236
237void ArbProbeMatchWeighting::copy(const ArbProbeMatchWeighting& rCopy) {
238    Width = rCopy.Width;
239    Bias  = rCopy.Bias;
240
241    for (int cx = 0 ; cx < 4 ; cx++) {
242        for (int cy = 0 ; cy < 4 ; cy++) {
243            PenaltyMatrix[cy][cx] = rCopy.PenaltyMatrix[cy][cx];
244        }
245    }
246}
247
248// ----------------------------------------------------------------------------
249
250ArbProbeMatchWeighting::ArbProbeMatchWeighting()
251    : ArbRefCount(),
252      PenaltyMatrix()
253{
254    float aDefaultValues[16] = {
255        0.0, 1.0, 1.0, 1.0,
256        1.0, 0.0, 1.0, 1.0,
257        1.0, 1.0, 0.0, 1.0,
258        1.0, 1.0, 1.0, 0.0
259    };
260
261    float dWidth = 1.0;
262    float dBias  = 0.0;
263
264    initialise(aDefaultValues, dWidth, dBias);
265}
266
267// ----------------------------------------------------------------------------
268
269ArbProbeMatchWeighting::ArbProbeMatchWeighting(const float aValues[16], float dWidth, float dBias)
270    : ArbRefCount(),
271      PenaltyMatrix()
272{
273    Width = 1.0;
274    Bias  = 0.0;
275
276    initialise(aValues, dWidth, dBias);
277}
278
279// ----------------------------------------------------------------------------
280
281ArbProbeMatchWeighting::ArbProbeMatchWeighting(const ArbProbeMatchWeighting& rCopy)
282    : ArbRefCount(),
283      PenaltyMatrix()
284{
285    copy(rCopy);
286}
287
288// ----------------------------------------------------------------------------
289
290ArbProbeMatchWeighting::~ArbProbeMatchWeighting() {
291    // Do Nothing
292}
293
294// ----------------------------------------------------------------------------
295
296ArbProbeMatchWeighting& ArbProbeMatchWeighting::operator = (const ArbProbeMatchWeighting& rCopy) {
297    copy(rCopy);
298    return *this;
299}
300
301// ----------------------------------------------------------------------------
302
303void ArbProbeMatchWeighting::initialise(const float aValues[16], float dWidth, float dBias) {
304    Width = dWidth;
305    Bias  = dBias;
306
307    int cz = 0;
308
309    for (int cx = 0 ; cx < 4 ; cx++) {
310        for (int cy = 0 ; cy < 4 ; cy++) {
311            PenaltyMatrix[cy][cx] = aValues[cz];
312
313            cz++;
314        }
315    }
316}
317
318// ----------------------------------------------------------------------------
319
320bool ArbProbeMatchWeighting::initialise(const char *pCSValues, const char *pCSWidth, const char *pCSBias) {
321    bool bInitialised = false;
322
323    if (pCSValues && pCSWidth && pCSBias) {
324        float dWidth = 0;
325        float dBias  = 0;
326        float aValues[16] = {
327            0.0, 1.0, 1.0, 1.0,
328            1.0, 0.0, 1.0, 1.0,
329            1.0, 1.0, 0.0, 1.0,
330            1.0, 1.0, 1.0, 0.0
331        };
332
333        int nItems = ::sscanf(pCSValues,
334                              "%f%f%f%f"
335                              "%f%f%f%f"
336                              "%f%f%f%f"
337                              "%f%f%f%f",
338                              aValues,      aValues + 1,  aValues + 2,  aValues + 3,
339                              aValues + 4,  aValues + 5,  aValues + 6,  aValues + 7,
340                              aValues + 8,  aValues + 9,  aValues + 10, aValues + 11,
341                              aValues + 12, aValues + 13, aValues + 14, aValues + 15);
342
343        nItems += ::sscanf(pCSWidth, "%f", &dWidth);
344        nItems += ::sscanf(pCSBias, "%f", &dBias);
345
346        if (nItems == (16 + 2)) {
347            initialise(aValues, dWidth, dBias);
348
349            bInitialised = true;
350        }
351    }
352
353    return bInitialised;
354}
355
356// ----------------------------------------------------------------------------
357
358void ArbProbeMatchWeighting::getParameters(float aValues[16], float& dWidth, float& dBias) const {
359    int cz = 0;
360
361    for (int cx = 0 ; cx < 4 ; cx++) {
362        for (int cy = 0 ; cy < 4 ; cy++) {
363            aValues[cz] = PenaltyMatrix[cy][cx];
364
365            cz++;
366        }
367    }
368
369    dWidth  = Width;
370    dBias   = Bias;
371}
372
373// ----------------------------------------------------------------------------
374
375void ArbProbeMatchWeighting::writeXML(FILE *hFile, const char *pPrefix) const {
376    bool bFirst = true;
377
378    ::fprintf(hFile, "%s<match_weighting width=\"%g\" bias=\"%g\">\n", pPrefix, Width, Bias);
379    ::fprintf(hFile, "%s  <penalty_matrix values=\"", pPrefix);
380
381    for (int cx = 0 ; cx < 4 ; cx++) {
382        for (int cy = 0 ; cy < 4 ; cy++) {
383            if (bFirst) {
384                ::fprintf(hFile, "%g", PenaltyMatrix[cy][cx]);
385
386                bFirst = false;
387            }
388            else {
389                ::fprintf(hFile, " %g", PenaltyMatrix[cy][cx]);
390            }
391        }
392    }
393
394    ::fprintf(hFile, "\"/>\n");
395    ::fprintf(hFile, "%s</match_weighting>\n", pPrefix);
396}
397
398// ----------------------------------------------------------------------------
399
400double ArbProbeMatchWeighting::matchWeight(const char *pSequenceA, const char *pSequenceB) const {
401    double dWeight = -1.0;
402
403    if (pSequenceA && pSequenceB) {
404        int nLengthA = strlen(pSequenceA);
405        int nLengthB = strlen(pSequenceB);
406        int nLength  = (nLengthA < nLengthB) ? nLengthA : nLengthB;
407
408        const char *pA = pSequenceA;
409        const char *pB = pSequenceB;
410
411        dWeight = 0.0;
412
413        for (int cn = 0 ; cn < nLength ; cn++) {
414            switch (*pA) {
415                case 'N':
416                case 'n': {
417                    // Wildcard match so don't penalise it
418                    break;
419                }
420
421                default: {
422                    switch (*pB) {
423                        case 'N':
424                        case 'n': {
425                            // Wildcard match so don't penalise it
426                            break;
427                        }
428
429                        default: {
430                            dWeight += PenaltyMatrix[toIndex(*pA)][toIndex(*pB)] * positionalWeight(cn, nLength);
431                            break;
432                        }
433                    }
434                    break;
435                }
436            }
437
438            pA++;
439            pB++;
440        }
441    }
442    else {
443        arb_assert(0);
444    }
445
446    return dWeight;
447}
448
449// ----------------------------------------------------------------------------
450
451double ArbProbeMatchWeighting::matchWeightResult(const char *pProbeSequence, const char *pMatchResult) const {
452    double dWeight = -1.0;
453
454    if (pProbeSequence && pMatchResult) {
455        int nMatchLength;
456        int nLengthResult = strlen(pMatchResult);
457        int nLength       = strlen(pProbeSequence);
458
459        const char *pS = pProbeSequence;
460        const char *pR = pMatchResult;
461        int         cn;
462
463        if (nLength <= nLengthResult) {
464            nMatchLength = nLength;
465        }
466        else {
467            nMatchLength = nLengthResult;
468        }
469
470        dWeight = 0.0;
471
472        for (cn = 0 ; cn < nMatchLength ; cn++) {
473            char cB;
474
475            switch (*pR) {
476                case '-':
477                case '=': {
478                    cB = *pS;
479                    break;
480                }
481
482                // I have no idea about this one. There is no mention in Arb about what
483                // .... means in terms of match results so I'll just assume it to be the
484                // same as U
485                case '.': {
486                    cB = 'U';
487                    break;
488                }
489
490                default: {
491                    cB = *pR;
492                    break;
493                }
494            }
495
496            switch (*pS) {
497                case 'N':
498                case 'n': {
499                    // Wildcard match so don't penalise it
500                    break;
501                }
502
503                default: {
504                    switch (cB) {
505                        case 'N':
506                        case 'n': {
507                            // Wildcard match so don't penalise it
508                            break;
509                        }
510
511                        default: {
512                            dWeight += PenaltyMatrix[toIndex(*pS)][toIndex(cB)] * positionalWeight(cn, nLength);
513                            break;
514                        }
515                    }
516                    break;
517                }
518            }
519
520            pS++;
521            pR++;
522        }
523
524        int nNoMatch = toIndex('U');
525
526        for (; cn < nLength ; cn++) {
527            dWeight += PenaltyMatrix[toIndex(*pS)][nNoMatch] * positionalWeight(cn, nLength);
528
529            pS++;
530        }
531    }
532    else {
533        arb_assert(0);
534    }
535
536    return dWeight;
537}
538
539
540// ----------------------------------------------------------------------------
541// ArbProbe method implementations
542// ----------------------------------------------------------------------------
543ArbProbe::ArbProbe()
544    : ArbRefCount(),
545      Name(),
546      Sequence(),
547      DisplayName()
548{
549    // Do nothing
550}
551
552// ----------------------------------------------------------------------------
553
554ArbProbe::ArbProbe(const char *pName, const char *pSequence)
555    : ArbRefCount(),
556      Name(),
557      Sequence(),
558      DisplayName()
559{
560    nameAndSequence(pName, pSequence);
561}
562
563// ----------------------------------------------------------------------------
564
565ArbProbe::ArbProbe(const ArbProbe& rCopy)
566    : ArbRefCount(),
567      Name(),
568      Sequence(),
569      DisplayName()
570{
571    // Note that we do a copy of Name and Sequence via c_str() because std:string
572    // shares internal buffers between strings if using a copy constructor and
573    // this can potentially result in memory corrupting if the owner string is deleted
574    // (REFCOUNT_HACK)
575    nameAndSequence(rCopy.Name.c_str(), rCopy.Sequence.c_str());
576}
577
578// ----------------------------------------------------------------------------
579
580ArbProbe::~ArbProbe() {
581    // Do nothing
582}
583
584// ----------------------------------------------------------------------------
585
586void ArbProbe::writeXML(FILE *hFile, const char *pPrefix) const {
587    ::fprintf(hFile, "%s<probe seq=\"%s\" name=\"%s\"/>\n", pPrefix, Sequence.c_str(), Name.c_str());
588}
589
590// ----------------------------------------------------------------------------
591
592void ArbProbe::nameAndSequence(const char *pName, const char *pSequence) { // REFCOUNT_HACK
593    if (pName) {
594        Name = pName;
595    }
596    else {
597        Name = "";
598    }
599
600    if (pSequence) {
601        Sequence = pSequence;
602    }
603    else {
604        Sequence = "";
605
606        arb_assert(0);
607    }
608
609    DisplayName = Name + ":" + Sequence;
610}
611
612// ----------------------------------------------------------------------------
613
614int ArbProbe::allowedMismatches() const {
615    size_t nProbe_Length     = Sequence.length();
616    size_t nAllowedMistaches = (nProbe_Length - ArbMIN_PROBE_LENGTH) / 2;
617
618    // Arb probe server doesn't seem to like having more that 20 mis-matches.
619    if (nAllowedMistaches > 20) {
620        nAllowedMistaches = 20;
621    }
622
623    return nAllowedMistaches;
624}
625
626
627// ----------------------------------------------------------------------------
628// ArbProbeCollection method implementations
629// ----------------------------------------------------------------------------
630void ArbProbeCollection::flush() {
631    ArbProbePtrListIter Iter;
632
633    for (Iter = ProbeList.begin() ; Iter != ProbeList.end() ; ++Iter) {
634        ArbProbe *pProbe = *Iter;
635
636        if (pProbe) {
637            pProbe->free();
638        }
639    }
640
641    ProbeList.clear();
642}
643
644// ----------------------------------------------------------------------------
645
646void ArbProbeCollection::copy(const ArbProbePtrList& rList) {
647    ArbProbePtrListConstIter  Iter;
648
649    for (Iter = rList.begin() ; Iter != rList.end() ; ++Iter) {
650        ArbProbe *pProbe = *Iter;
651
652        if (pProbe) {
653            ProbeList.push_back(pProbe);
654            pProbe->lock();
655        }
656    }
657}
658
659// ----------------------------------------------------------------------------
660
661ArbProbeCollection::ArbProbeCollection()
662    : ArbRefCount(),
663      Name(),
664      ProbeList(),
665      MatchWeighting()
666{
667    HasChanged = false;
668}
669
670// ----------------------------------------------------------------------------
671
672ArbProbeCollection::ArbProbeCollection(const char *pName)
673    : ArbRefCount(),
674      Name(),
675      ProbeList(),
676      MatchWeighting()
677{
678    // Note that we do a copy of Name via c_str() because std:string shares
679    // internal buffers between strings if using a copy constructor and this can
680    // potentially result in memory corrupting if the owner string is deleted
681    // (REFCOUNT_HACK)
682    name(pName);
683
684    HasChanged = false;
685}
686
687// ----------------------------------------------------------------------------
688
689ArbProbeCollection::ArbProbeCollection(const ArbProbeCollection& rCopy)
690    : ArbRefCount(),
691      Name(),
692      ProbeList(),
693      MatchWeighting(rCopy.MatchWeighting)
694{
695    name(rCopy.name().c_str());
696    copy(rCopy.ProbeList);
697
698    HasChanged = false;
699}
700
701// ----------------------------------------------------------------------------
702
703ArbProbeCollection::~ArbProbeCollection() {
704    flush();
705}
706
707// ----------------------------------------------------------------------------
708
709ArbProbeCollection& ArbProbeCollection::operator = (const ArbProbeCollection& rCopy) {
710    flush();
711    name(rCopy.name().c_str());
712    copy(rCopy.ProbeList);
713
714    MatchWeighting  = rCopy.MatchWeighting;
715    HasChanged      = false;
716
717    return *this;
718}
719
720// ----------------------------------------------------------------------------
721
722static bool elementHasName(DOMElement *pElement, const char *pName) {
723    bool bHasName = false;
724
725    if (pName) {
726        XMLCh *pNameStr;
727
728        pNameStr  = XMLString::transcode(pName);
729        bHasName  = XMLString::equals(pElement->getTagName(), pNameStr);
730        XMLString::release(&pNameStr);
731    }
732
733    return bHasName;
734}
735
736// ----------------------------------------------------------------------------
737
738static bool isElement(DOMNode *pNode, DOMElement*& pElement, const char *pName) {
739    bool  bIsElement = false;
740
741    if (pNode) {
742        short nNodeType = pNode->getNodeType();
743
744        if (nNodeType == DOMNode::ELEMENT_NODE) {
745            pElement = dynamic_cast<xercesc::DOMElement*>(pNode);
746
747            if (pName) {
748                bIsElement = elementHasName(pElement, pName);
749            }
750            else {
751                bIsElement = true;
752            }
753        }
754    }
755
756    return bIsElement;
757}
758
759// ----------------------------------------------------------------------------
760
761bool ArbProbeCollection::openXML(const char *pFileAndPath, std::string& rErrorMessage) {
762    bool bOpened = false;
763
764    rErrorMessage = "";
765
766    if (pFileAndPath && pFileAndPath[0]) {
767        struct stat   FileStatus;
768        int           nResult = ::stat(pFileAndPath, &FileStatus);
769
770        if ((nResult == 0) && !S_ISDIR(FileStatus.st_mode)) {
771            flush();
772
773            XMLPlatformUtils::Initialize();
774
775            // We need braces to ensure Parser goes out of scope be Terminate() is called
776            {
777                XercesDOMParser Parser;
778
779                Parser.setValidationScheme(XercesDOMParser::Val_Never);
780                Parser.setDoNamespaces(false);
781                Parser.setDoSchema(false);
782                Parser.setLoadExternalDTD(false);
783
784                try {
785                    Parser.parse(pFileAndPath);
786
787                    DOMDocument *pDoc  = Parser.getDocument();
788                    DOMElement  *pRoot = pDoc->getDocumentElement();
789
790                    if (pRoot && elementHasName(pRoot, "probe_collection")) {
791                        char        *pNameAttr          = NULp;
792                        XMLCh       *pNameAttrStr       = XMLString::transcode("name");
793                        DOMNodeList *pPC_Children;
794                        XMLSize_t    nPC_Count;
795                        bool         bHasProbeList      = false;
796                        bool         bHasMatchWeighting = false;
797
798                        pNameAttr = XMLString::transcode(pRoot->getAttribute(pNameAttrStr));
799                        name(pNameAttr);
800                        XMLString::release(&pNameAttr);
801
802                        pPC_Children  = pRoot->getChildNodes();
803                        nPC_Count     = pPC_Children->getLength();
804
805                        for (XMLSize_t cx = 0 ; cx < nPC_Count ; ++cx) {
806                            DOMNode    *pPC_Node    = pPC_Children->item(cx);
807                            DOMElement *pPC_Element = NULp;
808
809                            if (isElement(pPC_Node, pPC_Element, "probe_list")) {
810                                DOMNodeList *pPL_Children;
811                                XMLSize_t    nPL_Count;
812                                XMLCh       *pSeqAttrStr;
813
814                                pSeqAttrStr   = XMLString::transcode("seq");
815                                pPL_Children  = pPC_Element->getChildNodes();
816                                nPL_Count     = pPL_Children->getLength();
817
818                                for (XMLSize_t cy = 0 ; cy < nPL_Count ; ++cy) {
819                                    DOMNode    *pPL_Node    = pPL_Children->item(cy);
820                                    DOMElement *pPL_Element = NULp;
821                                    char       *pSeqAttr    = NULp;
822
823                                    if (isElement(pPL_Node, pPL_Element, "probe")) {
824                                        pNameAttr = XMLString::transcode(pPL_Element->getAttribute(pNameAttrStr));
825                                        pSeqAttr  = XMLString::transcode(pPL_Element->getAttribute(pSeqAttrStr));
826
827                                        add(pNameAttr, pSeqAttr);
828
829                                        XMLString::release(&pNameAttr);
830                                        XMLString::release(&pSeqAttr);
831
832                                        bHasProbeList = true;
833                                    }
834                                }
835                            }
836                            else if (isElement(pPC_Node, pPC_Element, "match_weighting")) {
837                                DOMNodeList *pMW_Children;
838                                XMLSize_t    nMW_Count;
839                                XMLCh       *pWidthAttrStr = XMLString::transcode("width");
840                                XMLCh       *pBiasAttrStr  = XMLString::transcode("bias");
841                                char        *pWidthStr     = XMLString::transcode(pPC_Element->getAttribute(pWidthAttrStr));
842                                char        *pBiasStr      = XMLString::transcode(pPC_Element->getAttribute(pBiasAttrStr));
843
844                                pMW_Children    = pPC_Element->getChildNodes();
845                                nMW_Count       = pMW_Children->getLength();
846
847                                for (XMLSize_t cy = 0 ; cy < nMW_Count ; ++cy) {
848                                    DOMNode    *pPM_Node    = pMW_Children->item(cy);
849                                    DOMElement *pPM_Element = NULp;
850
851                                    if (isElement(pPM_Node, pPM_Element, "penalty_matrix")) {
852                                        XMLCh *pValuesAttrStr = XMLString::transcode("values");
853                                        char  *pValuesAttr    = XMLString::transcode(pPM_Element->getAttribute(pValuesAttrStr));
854
855                                        if (MatchWeighting.initialise(pValuesAttr, pWidthStr, pBiasStr)) {
856                                            bHasMatchWeighting = true;
857                                        }
858                                        else {
859                                            rErrorMessage = "Too few penalty_matrix values";
860                                        }
861
862                                        XMLString::release(&pValuesAttrStr);
863                                        XMLString::release(&pValuesAttr);
864                                    }
865                                }
866
867                                XMLString::release(&pWidthAttrStr);
868                                XMLString::release(&pBiasAttrStr);
869                                XMLString::release(&pWidthStr);
870                                XMLString::release(&pBiasStr);
871                            }
872                        }
873
874                        XMLString::release(&pNameAttrStr);
875
876                        bOpened = bHasProbeList && bHasMatchWeighting;
877
878                        if (!bHasProbeList) {
879                            rErrorMessage += "\nprobe_list missing or empty";
880                        }
881
882                        if (!bHasMatchWeighting) {
883                            rErrorMessage += "\nmatch_weighting missing or empty";
884                        }
885                    }
886
887                    if (bOpened) {
888                        HasChanged  = false;
889                    }
890                }
891                catch (xercesc::DOMException& e1) {
892                    char *message = xercesc::XMLString::transcode(e1.getMessage());
893
894                    rErrorMessage  = "Error parsing file: ";
895                    rErrorMessage += message;
896
897                    XMLString::release(&message);
898                }
899                catch (xercesc::XMLException& e2) {
900                    char *message = xercesc::XMLString::transcode(e2.getMessage());
901
902                    rErrorMessage  = "Error parsing file: ";
903                    rErrorMessage += message;
904
905                    XMLString::release(&message);
906                }
907            }
908
909            XMLPlatformUtils::Terminate();
910        }
911        else if (nResult == EACCES) {
912            rErrorMessage = "Search permission is denied";
913        }
914        else if (nResult == EIO) {
915            rErrorMessage = "Error reading from the file system";
916        }
917        else if (nResult == ELOOP) {
918            rErrorMessage = "Loop exists in symbolic links";
919        }
920        else if (nResult == ENAMETOOLONG) {
921            rErrorMessage = "Path name too long";
922        }
923        else if (nResult == ENOENT) {
924            rErrorMessage = "Component of path existing file or missing";
925        }
926        else if (nResult == ENOTDIR) {
927            rErrorMessage = "Component of path not a directory";
928        }
929        else if (nResult == EOVERFLOW) {
930            rErrorMessage = "";
931        }
932    }
933    else {
934        rErrorMessage = "Please select a file to load";
935    }
936
937    return bOpened;
938}
939
940// ----------------------------------------------------------------------------
941
942bool ArbProbeCollection::saveXML(const char *pFileAndPath) const {
943    bool bSaved = false;
944
945    if (pFileAndPath) {
946        FILE *hFile = ::fopen(pFileAndPath, "wt");
947
948        if (hFile) {
949            ArbProbePtrListConstIter  Iter;
950
951            ::fprintf(hFile, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
952            ::fprintf(hFile, "<!DOCTYPE probe_collection>\n");
953            ::fprintf(hFile, "<probe_collection name=\"%s\">\n", Name.c_str());
954            ::fprintf(hFile, "  <probe_list>\n");
955
956            for (Iter = ProbeList.begin() ; Iter != ProbeList.end() ; ++Iter) {
957                const ArbProbe *pProbe = *Iter;
958
959                if (pProbe) {
960                    pProbe->writeXML(hFile, "    ");
961                }
962            }
963
964            ::fprintf(hFile, "  </probe_list>\n");
965
966            MatchWeighting.writeXML(hFile, "  ");
967
968            ::fprintf(hFile, "</probe_collection>\n");
969
970            ::fclose(hFile);
971
972            HasChanged = false;
973        }
974    }
975
976    return bSaved;
977}
978
979// ----------------------------------------------------------------------------
980
981void ArbProbeCollection::setParameters(const float aValues[16], float dWidth, float dBias) {
982    MatchWeighting.setParameters(aValues, dWidth, dBias);
983
984    HasChanged = true;
985}
986
987// ----------------------------------------------------------------------------
988
989void ArbProbeCollection::getParameters(float aValues[16], float& dWidth, float& dBias) const {
990    MatchWeighting.getParameters(aValues, dWidth, dBias);
991}
992
993// ----------------------------------------------------------------------------
994
995struct hasSequence {
996    std::string seq;
997    hasSequence(std::string seq_) : seq(seq_) {}
998    bool operator()(const ArbProbe *probe) {
999        return probe && probe->sequence() == seq;
1000    }
1001};
1002
1003const ArbProbe *ArbProbeCollection::find(const char *pSequence) const {
1004    if (pSequence) {
1005        ArbProbePtrListConstIter found = find_if(ProbeList.begin(), ProbeList.end(), hasSequence(pSequence));
1006        if (found != ProbeList.end()) {
1007            return *found;
1008        }
1009    }
1010    return NULp;
1011}
1012
1013// ----------------------------------------------------------------------------
1014
1015bool ArbProbeCollection::add(const char *pName, const char *pSequence, const ArbProbe **ppProbe) {
1016    bool bAdded = false;
1017
1018    if (pSequence && (strlen(pSequence) >= ArbMIN_PROBE_LENGTH)) {
1019        ArbProbe *pNewProbe = new ArbProbe(pName, pSequence);
1020
1021        if (pNewProbe) {
1022            ProbeList.push_back(pNewProbe);
1023
1024            if (ppProbe) *ppProbe = pNewProbe;
1025
1026            HasChanged  = true;
1027            bAdded      = true;
1028        }
1029    }
1030
1031    return bAdded;
1032}
1033
1034bool ArbProbeCollection::replace(const char *oldSequence, const char *pName, const char *pSequence, const ArbProbe **ppProbe) {
1035    bool bReplaced = false;
1036
1037    if (oldSequence && pSequence && (strlen(pSequence) >= ArbMIN_PROBE_LENGTH)) {
1038        ArbProbePtrListIter found = find_if(ProbeList.begin(), ProbeList.end(), hasSequence(oldSequence));
1039        if (found != ProbeList.end()) {
1040            (*found)->free();
1041            *found = new ArbProbe(pName, pSequence);
1042
1043            if (ppProbe) *ppProbe = *found;
1044
1045            HasChanged = true;
1046            bReplaced  = true;
1047        }
1048    }
1049
1050    return bReplaced;
1051}
1052
1053
1054// ----------------------------------------------------------------------------
1055
1056bool ArbProbeCollection::remove(const char *pSequence) {
1057    bool bRemoved  = false;
1058
1059    if (pSequence) {
1060        ArbProbePtrListIter Iter;
1061        std::string         rSequence(pSequence);
1062
1063        for (Iter = ProbeList.begin() ; Iter != ProbeList.end() ; ++Iter) {
1064            ArbProbe *pTestProbe = *Iter;
1065
1066            if (pTestProbe && pTestProbe->sequence() == rSequence) {
1067                ProbeList.erase(Iter);
1068
1069                pTestProbe->free();
1070
1071                HasChanged  = true;
1072                bRemoved    = true;
1073                break;
1074            }
1075        }
1076    }
1077
1078    return bRemoved;
1079}
1080
1081// ----------------------------------------------------------------------------
1082
1083bool ArbProbeCollection::clear() {
1084    bool bClear = false;
1085
1086    if (ProbeList.size() > 0) {
1087        flush();
1088
1089        HasChanged  = true;
1090        bClear      = true;
1091    }
1092
1093    return bClear;
1094}
1095
1096// ----------------------------------------------------------------------------
1097
1098void ArbProbeCollection::name(const char *pName) { // REFCOUNT_HACK
1099    if (pName) {
1100        Name = pName;
1101    }
1102    else {
1103        Name = "";
1104    }
1105
1106    HasChanged = true;
1107}
1108
1109
1110// ----------------------------------------------------------------------------
1111// ArbMatchResult method implementations
1112// ----------------------------------------------------------------------------
1113ArbMatchResult::ArbMatchResult()
1114    : ArbRefCount(),
1115      CachedResultA(),
1116      CachedResultB()
1117{
1118    Probe   = NULp;
1119    Weight  = 0.0;
1120    Padding = 0;
1121    Index   = 0;
1122}
1123
1124// ----------------------------------------------------------------------------
1125
1126ArbMatchResult::ArbMatchResult(const ArbProbe *pProbe, const char *pResult, int nSplitPoint, double dWeight)
1127    : ArbRefCount(),
1128      CachedResultA(),
1129      CachedResultB()
1130{
1131    ArbStringCache& g_string_cache = get_string_cache();
1132    g_string_cache.saveString(pResult, nSplitPoint, CachedResultA);
1133    g_string_cache.saveString(pResult + nSplitPoint, CachedResultB);
1134
1135    Probe   = pProbe;
1136    Weight  = dWeight;
1137    Padding = 0;
1138    Index   = 0;
1139
1140    if (Probe) {
1141        Probe->lock();
1142    }
1143}
1144
1145// ----------------------------------------------------------------------------
1146
1147ArbMatchResult::ArbMatchResult(const ArbMatchResult& rCopy)
1148    : ArbRefCount(),
1149      CachedResultA(rCopy.CachedResultA),
1150      CachedResultB(rCopy.CachedResultB)
1151{
1152    Probe   = rCopy.Probe;
1153    Weight  = rCopy.Weight;
1154    Padding = rCopy.Padding;
1155    Index   = rCopy.Index;
1156
1157    if (Probe) {
1158        Probe->lock();
1159    }
1160}
1161
1162// ----------------------------------------------------------------------------
1163
1164ArbMatchResult::~ArbMatchResult() {
1165    if (Probe) {
1166        Probe->free();
1167    }
1168}
1169
1170// ----------------------------------------------------------------------------
1171
1172ArbMatchResult& ArbMatchResult::operator = (const ArbMatchResult& rCopy) {
1173    Probe         = rCopy.Probe;
1174    CachedResultA = rCopy.CachedResultA;
1175    CachedResultB = rCopy.CachedResultB;
1176    Padding       = rCopy.Padding;
1177    Weight        = rCopy.Weight;
1178
1179    if (Probe) {
1180        Probe->lock();
1181    }
1182
1183    return *this;
1184}
1185
1186// ----------------------------------------------------------------------------
1187
1188void ArbMatchResult::addedHeadline(std::string& rHeadline) {
1189    rHeadline = "---error--probe-----------------";
1190}
1191
1192// ----------------------------------------------------------------------------
1193
1194void ArbMatchResult::weightAndResult(std::string& rDest) const {
1195    char        sBuffer[64] = {0};
1196    std::string sResult;
1197
1198    result(sResult);
1199    sprintf(sBuffer, "%8g %22.22s   ", Weight, Probe ? Probe->name().c_str() : "");
1200
1201    rDest  = sBuffer;
1202    rDest += sResult;
1203}
1204
1205// ----------------------------------------------------------------------------
1206
1207void ArbMatchResult::result(std::string& sResult) const {
1208    std::string sResultA;
1209    std::string sResultB;
1210
1211    ArbStringCache& g_string_cache = get_string_cache();
1212    g_string_cache.loadString(sResultA, CachedResultA);
1213    g_string_cache.loadString(sResultB, CachedResultB);
1214
1215    sResult.append(sResultA);
1216
1217    if (Padding > 0) {
1218        sResult.append(Padding, ' ');
1219    }
1220
1221    sResult.append(sResultB);
1222}
1223
1224
1225// ----------------------------------------------------------------------------
1226// ArbMatchResultSet method implementations
1227// ----------------------------------------------------------------------------
1228void ArbMatchResultSet::flush() {
1229    ArbMatchResultPtrByStringMultiMapIter Iter;
1230
1231    for (Iter = ResultMap.begin() ; Iter != ResultMap.end() ; ++Iter) {
1232        ArbMatchResult *pResult = (*Iter).second;
1233
1234        if (pResult) {
1235            pResult->free();
1236        }
1237    }
1238
1239    ResultMap.clear();
1240    CommentList.clear();
1241
1242    Headline    = "";
1243    EndFullName = 0;
1244}
1245
1246// ----------------------------------------------------------------------------
1247
1248void ArbMatchResultSet::copy(const ArbMatchResultPtrByStringMultiMap& rMap) {
1249    ArbMatchResultPtrByStringMultiMapConstIter Iter;
1250
1251    for (Iter = rMap.begin() ; Iter != rMap.end() ; ++Iter) {
1252        const std::string&    sKey    = (*Iter).first;
1253        const ArbMatchResult *pResult = (*Iter).second;
1254
1255        if (pResult) {
1256            ArbMatchResult *pCopy = new ArbMatchResult(*pResult);
1257
1258            if (pCopy) {
1259                ResultMap.insert(ArbMatchResultPtrStringPair(sKey, pCopy));
1260            }
1261        }
1262    }
1263
1264    ResultMap.clear();
1265    CommentList.clear();
1266}
1267
1268// ----------------------------------------------------------------------------
1269
1270ArbMatchResultSet::ArbMatchResultSet()
1271    : ArbRefCount(),
1272      Headline(),
1273      ResultMap(),
1274      CommentList()
1275{
1276    Probe       = NULp;
1277    Index       = 0;
1278    EndFullName = 0;
1279}
1280
1281// ----------------------------------------------------------------------------
1282
1283ArbMatchResultSet::ArbMatchResultSet(const ArbProbe *pProbe)
1284    : ArbRefCount(),
1285      Headline(),
1286      ResultMap(),
1287      CommentList()
1288{
1289    Probe       = NULp;
1290    Index       = 0;
1291    EndFullName = 0;
1292
1293    initialise(pProbe, 0);
1294}
1295
1296// ----------------------------------------------------------------------------
1297
1298ArbMatchResultSet::ArbMatchResultSet(const ArbMatchResultSet& rCopy)
1299    : ArbRefCount(),
1300      Headline(rCopy.Headline.c_str()),
1301      ResultMap(),
1302      CommentList(rCopy.CommentList)
1303{
1304    Probe       = NULp;
1305    Index       = 0;
1306    EndFullName = 0;
1307
1308    initialise(rCopy.Probe, rCopy.Index);
1309    copy(rCopy.ResultMap);
1310
1311    EndFullName = rCopy.EndFullName;
1312}
1313
1314// ----------------------------------------------------------------------------
1315
1316ArbMatchResultSet::~ArbMatchResultSet() {
1317    flush();
1318
1319    if (Probe) {
1320        Probe->free();
1321    }
1322}
1323
1324// ----------------------------------------------------------------------------
1325
1326void ArbMatchResultSet::initialise(const ArbProbe *pProbe, int nIndex) {
1327    Probe = pProbe;
1328    Index = nIndex;
1329
1330    if (Probe) {
1331        Probe->lock();
1332    }
1333
1334    flush();
1335}
1336
1337// ----------------------------------------------------------------------------
1338
1339bool ArbMatchResultSet::add(const char *pName,
1340                            const char *pFullName,
1341                            const char *pMatchPart,
1342                            const char *pResult,
1343                            const ArbProbeMatchWeighting& rMatchWeighting)
1344{
1345    bool bAdded = false;
1346
1347    if (pResult && pName && pFullName && pMatchPart && Probe && Probe->sequence().length() > 0) {
1348        double          dWeight;
1349        const char     *pMatchStart = pMatchPart;
1350        bool            bContinue   = true;
1351        std::string     sKey(pName);
1352        ArbMatchResult *pMatchResult;
1353
1354        while (bContinue) {
1355            switch (*pMatchStart) {
1356                case '-': {
1357                    pMatchStart++;
1358
1359                    bContinue = false;
1360                    break;
1361                }
1362
1363                case '\0':
1364                case '=': {
1365                    bContinue = false;
1366                    break;
1367                }
1368
1369                default: {
1370                    pMatchStart++;
1371
1372                    bContinue = true;
1373                }
1374            }
1375        }
1376
1377        dWeight       = rMatchWeighting.matchWeightResult(Probe->sequence().c_str(), pMatchStart);
1378        pMatchResult  = new ArbMatchResult(Probe, pResult, EndFullName, dWeight);
1379
1380        if (pMatchResult) {
1381            pMatchResult->index(Index);
1382            ResultMap.insert(ArbMatchResultPtrStringPair(sKey, pMatchResult));
1383
1384            bAdded = true;
1385        }
1386    }
1387
1388    return bAdded;
1389}
1390
1391// ----------------------------------------------------------------------------
1392
1393bool ArbMatchResultSet::isMatched(const ArbStringList& rCladeList,
1394                                  bool& bPartialMatch,
1395                                  double dThreshold,
1396                                  double dCladeMarkedThreshold,
1397                                  double dCladePartiallyMarkedThreshold) const
1398{
1399    bool  bMatched    = false;
1400    int   nCladeSize  = rCladeList.size();
1401
1402    if (nCladeSize > 0) {
1403        int nMatchedSize          = (int)(nCladeSize * dCladeMarkedThreshold + 0.5);
1404        int nPartiallyMatchedSize = (int)(nCladeSize * dCladePartiallyMarkedThreshold + 0.5);
1405        int nMatchedCount         = 0;
1406
1407        for (ArbStringListConstIter Iter = rCladeList.begin() ; Iter != rCladeList.end() ; ++Iter) {
1408            const std::string&  rName = *Iter;
1409
1410            if (isMatched(rName, dThreshold)) {
1411                nMatchedCount++;
1412            }
1413        }
1414
1415        bMatched      = (nMatchedCount >= nMatchedSize);
1416        bPartialMatch = false;
1417
1418        // Only check for partial match if we don't have a match. If a partial
1419        // match is found then isMatched() should return true.
1420        if (!bMatched) {
1421            bPartialMatch = (nMatchedCount >= nPartiallyMatchedSize);
1422            bMatched      = bPartialMatch;
1423        }
1424    }
1425
1426    return bMatched;
1427}
1428
1429// ----------------------------------------------------------------------------
1430
1431bool ArbMatchResultSet::isMatched(const std::string& rName, double dThreshold) const {
1432    bool bMatched = false;
1433
1434    ArbMatchResultPtrByStringMultiMapConstIter Iter = ResultMap.find(rName);
1435
1436    if (Iter != ResultMap.end()) {
1437        const ArbMatchResult *pResult = (*Iter).second;
1438
1439        bMatched = pResult->weight() <= dThreshold;
1440    }
1441
1442    return bMatched;
1443}
1444
1445// ----------------------------------------------------------------------------
1446
1447bool ArbMatchResultSet::addComment(const char *pComment) {
1448    bool bAdded = false;
1449
1450    if (pComment && Probe && Probe->sequence().length() > 0) {
1451        CommentList.push_back(std::string(pComment));
1452
1453        bAdded = true;
1454    }
1455
1456    return bAdded;
1457}
1458
1459// ----------------------------------------------------------------------------
1460
1461void ArbMatchResultSet::findMaximumWeight(double& dMaximumWeight) const {
1462    ArbMatchResultPtrByStringMultiMapConstIter Iter;
1463
1464    for (Iter = ResultMap.begin() ; Iter != ResultMap.end() ; ++Iter) {
1465        const ArbMatchResult *pResult = (*Iter).second;
1466
1467        if (pResult && dMaximumWeight < pResult->weight()) {
1468            dMaximumWeight = pResult->weight();
1469        }
1470    }
1471}
1472
1473// ----------------------------------------------------------------------------
1474
1475void ArbMatchResultSet::enumerateResults(ArbMatchResultPtrByDoubleMultiMap& rMap, int nMaxFullName) {
1476    ArbMatchResultPtrByStringMultiMapIter Iter;
1477
1478    for (Iter = ResultMap.begin() ; Iter != ResultMap.end() ; ++Iter) {
1479        ArbMatchResult *pResult = (*Iter).second;
1480
1481        if (pResult) {
1482            pResult->padding(nMaxFullName - EndFullName);
1483            rMap.insert(ArbMatchResultPtrDoublePair(pResult->weight(), pResult));
1484        }
1485    }
1486}
1487
1488
1489// ----------------------------------------------------------------------------
1490// ArbMatchResultsManager method implementations
1491// ----------------------------------------------------------------------------
1492void ArbMatchResultsManager::flush() {
1493    ArbMatchResultPtrByStringMultiMapIter Iter;
1494
1495    for (Iter = ResultsMap.begin() ; Iter != ResultsMap.end() ; ++Iter) {
1496        ArbMatchResult *pMatchResult = (*Iter).second;
1497
1498        if (pMatchResult) {
1499            pMatchResult->free();
1500        }
1501    }
1502
1503    ResultsMap.clear();
1504}
1505
1506// ----------------------------------------------------------------------------
1507
1508void ArbMatchResultsManager::initFileName() {
1509    char *uniqueName   = GB_unique_filename("ArbMatchResults", "txt");
1510    char *pTmpFileName = GB_create_tempfile(uniqueName);
1511
1512    if (pTmpFileName) {
1513        ResultsFileName = pTmpFileName;
1514    }
1515
1516    free(pTmpFileName);
1517    free(uniqueName);
1518}
1519
1520// ----------------------------------------------------------------------------
1521
1522ArbMatchResultsManager::ArbMatchResultsManager()
1523    : ResultsMap(),
1524      ResultSetMap(),
1525      ResultsFileName()
1526{
1527    MaximumWeight = 0.0;
1528    initFileName();
1529}
1530
1531// ----------------------------------------------------------------------------
1532
1533ArbMatchResultsManager::ArbMatchResultsManager(const ArbMatchResultsManager& rCopy)
1534    : ResultsMap(),
1535      ResultSetMap(rCopy.ResultSetMap),
1536      ResultsFileName()
1537{
1538    MaximumWeight = rCopy.MaximumWeight;
1539    updateResults();
1540    initFileName();
1541}
1542
1543// ----------------------------------------------------------------------------
1544
1545ArbMatchResultsManager::~ArbMatchResultsManager() {
1546    ResultSetMap.clear();
1547    flush();
1548
1549    if (ResultsFileName.length() > 0) {
1550        unlink(ResultsFileName.c_str());
1551    }
1552
1553    // This assumes that there is only ever on instance of ArbMatchResultsManager
1554    // which is true at the moment. Slightly dodgey but it will stop the cache
1555    // file from ballooning out too much.
1556    get_string_cache().flush();
1557}
1558
1559// ----------------------------------------------------------------------------
1560
1561void ArbMatchResultsManager::reset() {
1562    ResultSetMap.clear();
1563    flush();
1564
1565    if (ResultsFileName.length() > 0) {
1566        unlink(ResultsFileName.c_str());
1567    }
1568
1569    // This assumes that there is only ever on instance of ArbMatchResultsManager
1570    // which is true at the moment. Slightly dodgey but it will stop the cache
1571    // file from ballooning out too much.
1572    get_string_cache().flush();
1573}
1574
1575// ----------------------------------------------------------------------------
1576
1577ArbMatchResultSet *ArbMatchResultsManager::addResultSet(const ArbProbe *pProbe) {
1578    ArbMatchResultSet *pResultSet = NULp;
1579
1580    if (pProbe) {
1581        pResultSet = (ArbMatchResultSet*)findResultSet(pProbe->sequence().c_str());
1582
1583        if (!pResultSet) {
1584            ResultSetMap[pProbe->sequence()] = ArbMatchResultSet();
1585
1586            pResultSet = (ArbMatchResultSet*)findResultSet(pProbe->sequence().c_str());
1587        }
1588    }
1589
1590    return pResultSet;
1591}
1592
1593// ----------------------------------------------------------------------------
1594
1595const ArbMatchResultSet *ArbMatchResultsManager::findResultSet(const char *pProbeSequence) const {
1596    const ArbMatchResultSet *pResultSet = NULp;
1597
1598    if (pProbeSequence) {
1599        ArbMatchResultSetByStringMapConstIter Iter = ResultSetMap.find(std::string(pProbeSequence));
1600
1601        if (Iter != ResultSetMap.end()) {
1602            pResultSet = &((*Iter).second);
1603        }
1604    }
1605
1606    return pResultSet;
1607}
1608
1609// ----------------------------------------------------------------------------
1610
1611void ArbMatchResultsManager::updateResults() {
1612    ArbMatchResultSetByStringMapIter            Iter;
1613    ArbMatchResultPtrByStringMultiMapConstIter  IterR;
1614
1615    flush();
1616
1617    MaximumWeight = 0.0;
1618
1619    for (Iter = ResultSetMap.begin() ; Iter != ResultSetMap.end() ; ++Iter) {
1620        ArbMatchResultSet&  rMatchResultSet = (*Iter).second;
1621
1622        rMatchResultSet.findMaximumWeight(MaximumWeight);
1623
1624        for (IterR = rMatchResultSet.resultMap().begin() ; IterR != rMatchResultSet.resultMap().end() ; ++IterR) {
1625            const std::string&    rKey         = (*IterR).first;
1626            const ArbMatchResult *pMatchResult = (*IterR).second;
1627
1628            pMatchResult->lock();
1629            ResultsMap.insert(ArbMatchResultPtrStringPair(rKey, (ArbMatchResult*)pMatchResult));
1630        }
1631    }
1632}
1633
1634// ----------------------------------------------------------------------------
1635
1636int ArbMatchResultsManager::enumerate_results(ArbMatchResultsEnumCallback pCallback, void *pContext) {
1637    int nResults = 0;
1638
1639    bool bAborted = false;
1640
1641    if (pCallback) {
1642        ArbMatchResultPtrByDoubleMultiMap rResultsMap;
1643
1644        // Need to compile the results sorted in ascending match weight.
1645        ArbMatchResultSetByStringMapIter  Iter;
1646        int                               nItem         = 0;
1647        int                               nItems        = 1;
1648        int                               nMaxFullName  = 0;
1649        std::string                       sHeadline;
1650
1651        for (Iter = ResultSetMap.begin() ; (Iter != ResultSetMap.end()) && !bAborted ; ++Iter) {
1652            ArbMatchResultSet&  rMatchResultSet = (*Iter).second;
1653
1654            if (rMatchResultSet.endFullName() > nMaxFullName) {
1655                ArbMatchResult::addedHeadline(sHeadline);
1656
1657                sHeadline   += rMatchResultSet.headline();
1658                nMaxFullName = rMatchResultSet.endFullName();
1659            }
1660        }
1661
1662        if (pCallback(pContext, sHeadline.c_str(), true, nItem, nItems)) {
1663            bAborted = true;
1664        }
1665
1666        for (Iter = ResultSetMap.begin() ; (Iter != ResultSetMap.end()) && !bAborted ; ++Iter) {
1667            ArbMatchResultSet&  rMatchResultSet = (*Iter).second;
1668
1669            rMatchResultSet.enumerateResults(rResultsMap, nMaxFullName);
1670
1671            ArbStringListConstIter CommentIter;
1672
1673            for (CommentIter = rMatchResultSet.commentList().begin() ;
1674                 CommentIter != rMatchResultSet.commentList().begin() ;
1675                 ++CommentIter)
1676            {
1677                const std::string& rComment = *CommentIter;
1678
1679                if (pCallback(pContext, rComment.c_str(), true, nItem, nItems)) {
1680                    bAborted = true;
1681                    break;
1682                }
1683            }
1684        }
1685
1686        ArbMatchResultPtrByDoubleMultiMapIter ResIter;
1687
1688        nItems = rResultsMap.size();
1689
1690        for (ResIter = rResultsMap.begin() ; (ResIter != rResultsMap.end()) && !bAborted ; ++ResIter) {
1691            const ArbMatchResult *pResult = (*ResIter).second;
1692
1693            if (pResult) {
1694                std::string sResult;
1695
1696                pResult->weightAndResult(sResult);
1697
1698                if (pCallback(pContext, sResult.c_str(), false, nItem, nItems)) {
1699                    bAborted = true;
1700                    break;
1701                }
1702
1703                nResults++;
1704                nItem++;
1705            }
1706        }
1707    }
1708
1709    return nResults;
1710}
1711
1712// ----------------------------------------------------------------------------
1713
1714const char *ArbMatchResultsManager::resultsFileName() const {
1715    return ResultsFileName.c_str();
1716}
1717
1718// ----------------------------------------------------------------------------
1719
1720void ArbMatchResultsManager::openResultsFile() const {
1721    pid_t pid = fork();
1722
1723    if (pid == 0) {
1724        // We are the child process. Execute system command to open the file.
1725        std::string sCommand("\"xdg-open ");
1726
1727        sCommand += ResultsFileName;
1728        sCommand += "\"";
1729
1730        execl("/bin/sh", sCommand.c_str(), (char *)NULp);
1731        exit(0);
1732    }
1733}
Note: See TracBrowser for help on using the repository browser.