1 // $Id: gc_locus.cpp,v 1.35 2011/03/08 19:22:00 bobgian Exp $
2 
3 /*
4   Copyright 2002  Mary Kuhner, Jon Yamato, and Joseph Felsenstein
5 
6   This software is distributed free of charge for non-commercial use
7   and is copyrighted.  Of course, we do not guarantee that the software
8   works, and are not responsible for any damage you may cause or have.
9 */
10 
11 #include <cassert>
12 
13 #include "gc_creation_info.h"
14 #include "gc_errhandling.h"
15 #include "gc_data.h"            // for ToWxString
16 #include "gc_default.h"
17 #include "gc_locus.h"
18 #include "gc_locus_err.h"
19 #include "gc_strings.h"
20 #include "gc_strings_locus.h"
21 #include "gc_structures_err.h"
22 #include "wx/log.h"
23 #include "wx/string.h"
24 #include "wx/tokenzr.h"
25 
26 //------------------------------------------------------------------------------------
27 
gcLocus()28 gcLocus::gcLocus()
29     :
30     m_blessed(false),
31     m_hasRegion(false),
32     m_regionId(gcdefault::badIndex),
33     m_inducedByFile(false),
34     m_fileId(gcdefault::badIndex),
35     m_dataType(sdatatype_NONE_SET),
36     m_hasNumMarkers(false),
37     m_numMarkers(0),
38     m_hasTotalLength(false),
39     m_totalLength(0),
40     m_hasLinkedUserValue(false),
41     m_linkedUserValue(false),
42     m_hasOffset(false),
43     m_offset(1),
44     m_hasMapPosition(false),
45     m_mapPosition(1),
46     m_hasUnphasedMarkers(false)
47 {
48     assert(m_unphasedMarkers.NumMarkers() == 0);
49     m_locations.clear();    // shouldn't be necessary
50 }
51 
~gcLocus()52 gcLocus::~gcLocus()
53 {
54 }
55 
56 bool
GetBlessed() const57 gcLocus::GetBlessed() const
58 {
59     return m_blessed;
60 }
61 
62 void
DebugDump(wxString prefix) const63 gcLocus::DebugDump(wxString prefix) const
64 {
65     wxLogDebug("%slocus %s (locus id %ld)", // EWDUMPOK
66                prefix.c_str(),
67                GetName().c_str(),
68                (long)GetId());
69     wxLogDebug("%sdatatype %s",(prefix+gcstr::indent).c_str(),ToWxString(GetDataType()).c_str());  // EWDUMPOK
70     wxLogDebug("%s%s markers",(prefix+gcstr::indent).c_str(),GetNumMarkersString().c_str());  // EWDUMPOK
71     wxLogDebug("%s%s total length",(prefix+gcstr::indent).c_str(),GetLengthString().c_str());   // EWDUMPOK
72     wxLogDebug("%s%s offset",(prefix+gcstr::indent).c_str(),GetOffsetString().c_str()); // EWDUMPOK
73     wxLogDebug("%s%s map position",(prefix+gcstr::indent).c_str(),GetMapPositionString().c_str());  // EWDUMPOK
74     wxLogDebug("%slocations:%s",(prefix+gcstr::indent).c_str(),GetLocationsAsString().c_str()); // EWDUMPOK
75     if(GetLinked())
76     {
77         wxLogDebug("%slinked",(prefix+gcstr::indent).c_str());  // EWDUMPOK
78     }
79     else
80     {
81         wxLogDebug("%sunlinked",(prefix+gcstr::indent).c_str());    // EWDUMPOK
82     }
83 }
84 
85 bool
HasLocations() const86 gcLocus::HasLocations() const
87 {
88     return !(m_locations.empty());
89 }
90 
91 std::vector<long>
GetLocations() const92 gcLocus::GetLocations() const
93 {
94     return m_locations;
95 }
96 
97 wxString
GetLocationsAsString() const98 gcLocus::GetLocationsAsString() const
99 {
100     wxString locationString = " ";
101     for(size_t index=0; index < m_locations.size(); index++)
102     {
103         locationString += wxString::Format("%ld ",m_locations[index]);
104     }
105     return locationString;
106 }
107 
108 bool
HasLocationZero() const109 gcLocus::HasLocationZero() const
110 {
111     for(size_t i = 0; i < m_locations.size(); i++)
112     {
113         long loc = m_locations[i];
114         if(loc == 0) return true;
115     }
116     return false;
117 }
118 
119 wxString
GetDataTypeString() const120 gcLocus::GetDataTypeString() const
121 {
122     return ToWxString(m_dataType);
123 }
124 
125 gcSpecificDataType
GetDataType() const126 gcLocus::GetDataType() const
127 {
128     return m_dataType;
129 }
130 
131 void
SetDataType(gcSpecificDataType type)132 gcLocus::SetDataType(gcSpecificDataType type)
133 {
134     m_dataType = type;
135 }
136 
137 bool
HasLength() const138 gcLocus::HasLength() const
139 {
140     if(HasTotalLength())
141     {
142         return true;
143     }
144     if(GetDataType() == sdatatype_DNA)
145     {
146         return HasNumMarkers();
147     }
148     return false;
149 }
150 
151 size_t
GetLength() const152 gcLocus::GetLength() const
153 {
154     if(HasTotalLength())
155     {
156         return GetTotalLength();
157     }
158     if(HasNumMarkers())
159     {
160         if(GetDataType() == sdatatype_DNA)
161         {
162             return GetNumMarkers();
163         }
164         if(GetNumMarkers() == 1)
165         {
166             return 1;
167         }
168         else
169         {
170             throw gc_locus_without_length(GetName());
171         }
172     }
173     return gcdefault::badLength;
174 }
175 
176 wxString
GetLengthString() const177 gcLocus::GetLengthString() const
178 {
179     if(HasLength())
180     {
181         return wxString::Format("%d",(int)GetLength());
182     }
183     return gcstr::unknown;
184 }
185 
186 bool
HasTotalLength() const187 gcLocus::HasTotalLength() const
188 {
189     return m_hasTotalLength;
190 }
191 
192 size_t
GetTotalLength() const193 gcLocus::GetTotalLength() const
194 {
195     assert(HasTotalLength());
196     return m_totalLength;
197 }
198 
199 wxString
GetTotalLengthString() const200 gcLocus::GetTotalLengthString() const
201 {
202     if(HasTotalLength())
203     {
204         return wxString::Format("%d",(int)GetTotalLength());
205     }
206     return gcstr::unknown;
207 }
208 
209 void
SetTotalLength(size_t totalLength)210 gcLocus::SetTotalLength(size_t totalLength)
211 {
212     if(HasNumMarkers())
213     {
214         if(totalLength < GetNumMarkers())
215         {
216             throw gc_locus_err(wxString::Format(gcerr::lengthTooShort,(int)totalLength,(int)GetNumMarkers()).c_str());
217         }
218     }
219     m_hasTotalLength = true;
220     m_totalLength = totalLength;
221 }
222 
223 void
UnsetTotalLength()224 gcLocus::UnsetTotalLength()
225 {
226     m_hasTotalLength = false;
227 }
228 
229 bool
HasNumMarkers() const230 gcLocus::HasNumMarkers() const
231 {
232     return m_hasNumMarkers;
233 }
234 
235 size_t
GetNumMarkers() const236 gcLocus::GetNumMarkers() const
237 {
238     if(!HasNumMarkers())
239     {
240         wxString msg = wxString::Format(gcerr_locus::unsetNumMarkers,GetName().c_str());
241         throw gc_implementation_error(msg.c_str());
242     }
243     return m_numMarkers;
244 }
245 
246 wxString
GetNumMarkersString() const247 gcLocus::GetNumMarkersString() const
248 {
249     if(HasNumMarkers())
250     {
251         return wxString::Format("%d",(int)GetNumMarkers());
252     }
253     return gcstr::unknown;
254 }
255 
256 void
SetNumMarkers(size_t numMarkers)257 gcLocus::SetNumMarkers(size_t numMarkers)
258 {
259     if(numMarkers == 0)
260     {
261         throw gc_num_markers_zero();
262     }
263     m_hasNumMarkers = true;
264     m_numMarkers = numMarkers;
265 }
266 
267 bool
HasOffset() const268 gcLocus::HasOffset() const
269 {
270     return m_hasOffset;
271 }
272 
273 long
GetOffset() const274 gcLocus::GetOffset() const
275 {
276     if(!HasOffset())
277     {
278         wxString msg = wxString::Format(gcerr_locus::unsetOffset,GetName().c_str());
279         throw gc_implementation_error(msg.c_str());
280     }
281     return m_offset;
282 }
283 
284 wxString
GetOffsetString() const285 gcLocus::GetOffsetString() const
286 {
287     if(HasOffset())
288     {
289         return wxString::Format("%d",(int)GetOffset());
290     }
291     return gcstr::unknown;
292 }
293 
294 void
UnsetNumMarkers()295 gcLocus::UnsetNumMarkers()
296 {
297     m_hasNumMarkers = false;
298 }
299 
300 bool
HasRegion() const301 gcLocus::HasRegion() const
302 {
303     return m_hasRegion;
304 }
305 
306 size_t
GetRegionId() const307 gcLocus::GetRegionId() const
308 {
309     if(!HasRegion())
310     {
311         wxString msg = wxString::Format(gcerr::unsetRegionId,GetName().c_str());
312         throw gc_implementation_error(msg.c_str());
313     }
314     return m_regionId;
315 }
316 
317 void
SetFileId(size_t id)318 gcLocus::SetFileId(size_t id)
319 {
320     m_inducedByFile = true;
321     m_fileId = id;
322 }
323 
324 void
UnsetFileId()325 gcLocus::UnsetFileId()
326 {
327     m_inducedByFile = false;
328 }
329 
330 void
SetRegionId(size_t id)331 gcLocus::SetRegionId(size_t id)
332 {
333     m_hasRegion = true;
334     m_regionId = id;
335 }
336 
337 void
UnsetRegionId()338 gcLocus::UnsetRegionId()
339 {
340     m_hasRegion = false;
341 }
342 
343 bool
HasLinkedUserValue() const344 gcLocus::HasLinkedUserValue() const
345 {
346     return m_hasLinkedUserValue;
347 }
348 
349 bool
GetLinkedUserValue() const350 gcLocus::GetLinkedUserValue() const
351 {
352     if(!HasLinkedUserValue())
353     {
354         wxString msg = wxString::Format(gcerr_locus::unsetLinkedUserValue,GetName().c_str());
355         throw gc_implementation_error(msg.c_str());
356     }
357     return m_linkedUserValue;
358 }
359 
360 bool
GetLinked() const361 gcLocus::GetLinked() const
362 {
363     if(HasLinkedUserValue())
364     {
365         return GetLinkedUserValue();
366     }
367     if(HasTotalLength())
368     {
369         return true;
370     }
371     if(HasLocations())
372     {
373         return true;
374     }
375     switch(GetDataType())
376     {
377         case sdatatype_NONE_SET:
378             // EWFIX.P4 -- should be able to determine values
379             // by reading data structures
380             return true;
381             break;
382         case sdatatype_DNA:
383         case sdatatype_SNP:
384             return true;
385             break;
386         case sdatatype_KALLELE:
387         case sdatatype_MICROSAT:
388             return false;
389             break;
390     }
391     assert(false);
392     return true;
393 }
394 
395 wxString
GetLinkedString() const396 gcLocus::GetLinkedString() const
397 {
398     bool val = GetLinked();
399     if(val) return gcstr::linkageYes;
400     return gcstr::linkageNo;
401 }
402 
403 wxString
GetLinkedUserValueString() const404 gcLocus::GetLinkedUserValueString() const
405 {
406     if(HasLinkedUserValue())
407     {
408         bool val = GetLinkedUserValue();
409         if(val) return gcstr::linkageYes;
410         return gcstr::linkageNo;
411     }
412     else
413     {
414         return gcstr::unknown;
415     }
416 }
417 
418 void
SetLinkedUserValue(bool linked)419 gcLocus::SetLinkedUserValue(bool linked)
420 {
421     if(! linked)
422     {
423         if(GetDataType() == sdatatype_DNA || GetDataType() == sdatatype_SNP)
424         {
425             throw gc_unlinked_nuc();
426         }
427     }
428     m_hasLinkedUserValue = true;
429     m_linkedUserValue = linked;
430 }
431 
432 bool
HasMapPosition() const433 gcLocus::HasMapPosition() const
434 {
435     return m_hasMapPosition;
436 }
437 
438 long
GetMapPosition() const439 gcLocus::GetMapPosition() const
440 {
441     if(!HasMapPosition())
442     {
443         wxString msg = wxString::Format(gcerr::unsetMapPosition,GetName().c_str());
444         throw gc_implementation_error(msg.c_str());
445     }
446     return m_mapPosition;
447 }
448 
449 wxString
GetMapPositionString() const450 gcLocus::GetMapPositionString() const
451 {
452     if(HasMapPosition())
453     {
454         return wxString::Format("%d",(int)GetMapPosition());
455     }
456     return gcstr::unknown;
457 }
458 
459 void
SetMapPosition(long mapPosition)460 gcLocus::SetMapPosition(long mapPosition)
461 {
462     // we don't test the value since during use of the
463     // GUI, the user needs to pass through impossible
464     // states
465     m_hasMapPosition = true;
466     m_mapPosition = mapPosition;
467 }
468 
469 void
UnsetMapPosition()470 gcLocus::UnsetMapPosition()
471 {
472     m_hasMapPosition = false;
473 }
474 
475 bool
HasUnphasedMarkers() const476 gcLocus::HasUnphasedMarkers() const
477 {
478     return m_hasUnphasedMarkers;
479 }
480 
481 const gcUnphasedMarkers *
GetUnphasedMarkers() const482 gcLocus::GetUnphasedMarkers() const
483 {
484     assert(HasUnphasedMarkers());
485     return &m_unphasedMarkers;
486 }
487 
488 wxString
GetUnphasedMarkersAsString() const489 gcLocus::GetUnphasedMarkersAsString() const
490 {
491     assert(HasUnphasedMarkers());
492     return m_unphasedMarkers.AsString();
493 }
494 
495 void
SetUnphasedMarkers(gcUnphasedMarkers markers)496 gcLocus::SetUnphasedMarkers(gcUnphasedMarkers markers)
497 {
498     m_hasUnphasedMarkers = true;
499     m_unphasedMarkers = markers;
500 }
501 
502 void
SetBlessed(bool blessed)503 gcLocus::SetBlessed(bool blessed)
504 {
505     m_blessed = blessed;
506 }
507 
508 void
SetCreationInfo(const gcCreationInfo & creationInfo)509 gcLocus::SetCreationInfo(const gcCreationInfo & creationInfo)
510 {
511     m_creationInfo = creationInfo;
512 }
513 
514 void
SetOffset(long offset)515 gcLocus::SetOffset(long offset)
516 {
517     // we don't test the value since during use of the
518     // GUI, the user needs to pass through impossible
519     // states
520     m_offset = offset;
521     m_hasOffset = true;
522 }
523 
524 void
SetLocations(wxString locationString)525 gcLocus::SetLocations(wxString locationString)
526 {
527     wxStringTokenizer tokenizer(locationString);
528     m_locations.clear();
529     while(tokenizer.HasMoreTokens())
530     {
531         wxString token = tokenizer.GetNextToken();
532         long location;
533         if(!token.ToLong(&location))
534         {
535             wxString msg = wxString::Format(gcerr::notALocation,locationString.c_str());
536             throw gc_data_error(msg.c_str());
537         }
538         if(!m_locations.empty())
539             // cannot check the first one!
540         {
541             long previous = m_locations.back();
542             if(location <= previous)
543             {
544                 throw gc_locations_out_of_order(GetName(),previous,location);
545             }
546         }
547         m_locations.push_back(location);
548     }
549     if(HasNumMarkers())
550     {
551         if(m_locations.size() != GetNumMarkers())
552         {
553             throw gc_set_locations_err(GetName(),locationString,GetNumMarkers(),m_locations.size());
554         }
555     }
556     else
557     {
558         SetNumMarkers(m_locations.size());
559     }
560 }
561 
562 void
LocusMergeLogic(bool doSettings,gcLocus & locusRef)563 gcLocus::LocusMergeLogic(bool doSettings, gcLocus & locusRef)
564 {
565     // data type
566     if(GetDataType() != sdatatype_NONE_SET)
567     {
568         if(locusRef.GetDataType() != sdatatype_NONE_SET)
569         {
570             if(locusRef.GetDataType() != GetDataType())
571             {
572                 throw gc_locus_user_data_type_mismatch(GetName(),locusRef.GetName(),GetDataType(),locusRef.GetDataType());
573             }
574         }
575     }
576 
577     // num Markers
578     if(HasNumMarkers())
579     {
580         if(locusRef.HasNumMarkers())
581         {
582             if(locusRef.GetNumMarkers() != GetNumMarkers())
583             {
584                 throw gc_locus_site_count_mismatch(GetName(),locusRef.GetName(),GetNumMarkers(),locusRef.GetNumMarkers());
585             }
586         }
587     }
588 
589     // EWFIX.P3 -- this is probably not correct
590     // total length
591     if(HasTotalLength())
592     {
593         if(locusRef.HasTotalLength())
594         {
595             if(locusRef.GetLength() != GetLength())
596             {
597                 throw gc_locus_length_mismatch(GetName(),locusRef.GetName(),GetLength(),locusRef.GetLength());
598             }
599         }
600     }
601 
602     // user-set linked value
603     if(HasLinkedUserValue())
604     {
605         if(locusRef.HasLinkedUserValue())
606         {
607             if(locusRef.GetLinkedUserValue() != GetLinkedUserValue())
608             {
609                 throw gc_locus_user_linked_mismatch(GetName(),locusRef.GetName(),GetLinkedUserValue(),locusRef.GetLinkedUserValue());
610             }
611         }
612     }
613 
614     // offset
615     if(HasOffset())
616     {
617         if(locusRef.HasOffset())
618         {
619             if(locusRef.GetOffset() != GetOffset())
620             {
621                 throw gc_locus_offset_mismatch(GetName(),locusRef.GetName(),GetOffset(),locusRef.GetOffset());
622             }
623         }
624     }
625 
626     // map position
627     if(HasMapPosition())
628     {
629         if(locusRef.HasMapPosition())
630         {
631             if(locusRef.GetMapPosition() != GetMapPosition())
632             {
633                 throw gc_locus_map_position_mismatch(GetName(),locusRef.GetName(),GetMapPosition(),locusRef.GetMapPosition());
634             }
635         }
636     }
637 
638     if(doSettings)
639         // this is a real merge
640     {
641         // order is important -- setting data type and then num Markers can
642         // result in setting the length
643         if(GetDataType() == sdatatype_NONE_SET)             SetDataType(locusRef.GetDataType());
644         if(!HasNumMarkers() && locusRef.HasNumMarkers())    SetNumMarkers(locusRef.GetNumMarkers());
645         if(!HasTotalLength() && locusRef.HasTotalLength())  SetTotalLength(locusRef.GetTotalLength());
646         if(!HasLinkedUserValue() && locusRef.HasLinkedUserValue()) SetLinkedUserValue(locusRef.GetLinkedUserValue());
647         if(!HasOffset() && locusRef.HasOffset())            SetOffset(locusRef.GetOffset());
648         if(!HasMapPosition() && locusRef.HasMapPosition())  SetMapPosition(locusRef.GetMapPosition());
649     }
650 }
651 
652 bool
CanMergeWith(gcLocus & locus)653 gcLocus::CanMergeWith(gcLocus & locus)
654 {
655     try
656     {
657         LocusMergeLogic(false,locus);
658     }
659     catch (const gc_locus_err& e)
660     {
661         return false;
662     }
663     return true;
664 }
665 
666 void
MergeWith(gcLocus & locus)667 gcLocus::MergeWith(gcLocus & locus)
668 {
669     LocusMergeLogic(true,locus);
670 }
671 
672 wxString
GetLongName() const673 gcLocus::GetLongName() const
674 {
675     return wxString::Format("%s %s",GetName().c_str(),m_creationInfo.GetDescriptiveName().c_str());
676 }
677 
678 //____________________________________________________________________________________
679