1 /**
2  * UGENE - Integrated Bioinformatics Tools.
3  * Copyright (C) 2008-2021 UniPro <ugene@unipro.ru>
4  * http://ugene.net
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19  * MA 02110-1301, USA.
20  */
21 
22 #include "Marker.h"
23 
24 #include <U2Core/DNASequence.h>
25 #include <U2Core/QVariantUtils.h>
26 
27 #include <U2Lang/MarkerUtils.h>
28 #include <U2Lang/WorkflowEnv.h>
29 
30 static const QString LENGTH_SLOT_ID("length-marker");
31 static const QString ANN_COUNT_SLOT_ID("ann-count-marker");
32 static const QString ANN_VALUE_SLOT_ID("ann-value-marker");
33 static const QString FILENAME_SLOT_ID("filename-marker");
34 
35 namespace U2 {
36 
37 const QString MarkerTypes::SEQ_LENGTH_MARKER_ID("sequence-length");
38 const QString MarkerTypes::SEQ_NAME_MARKER_ID("sequence-name");
39 const QString MarkerTypes::ANNOTATION_COUNT_MARKER_ID("annotations-count");
40 const QString MarkerTypes::ANNOTATION_LENGTH_MARKER_ID("annotation-length");
41 const QString MarkerTypes::QUAL_INT_VALUE_MARKER_ID("qualifier-int-value");
42 const QString MarkerTypes::QUAL_TEXT_VALUE_MARKER_ID("qualifier-text-value");
43 const QString MarkerTypes::QUAL_FLOAT_VALUE_MARKER_ID("qualifier-float-value");
44 const QString MarkerTypes::TEXT_MARKER_ID("text");
45 
getDataTypeById(const QString & typeId)46 MarkerDataType MarkerTypes::getDataTypeById(const QString &typeId) {
47     if (SEQ_LENGTH_MARKER_ID == typeId) {
48         return INTEGER;
49     } else if (ANNOTATION_COUNT_MARKER_ID == typeId) {
50         return INTEGER;
51     } else if (ANNOTATION_LENGTH_MARKER_ID == typeId) {
52         return INTEGER;
53     } else if (QUAL_INT_VALUE_MARKER_ID == typeId) {
54         return INTEGER;
55     } else if (QUAL_TEXT_VALUE_MARKER_ID == typeId) {
56         return STRING;
57     } else if (QUAL_FLOAT_VALUE_MARKER_ID == typeId) {
58         return FLOAT;
59     } else if (TEXT_MARKER_ID == typeId) {
60         return STRING;
61     } else if (SEQ_NAME_MARKER_ID == typeId) {
62         return STRING;
63     } else {
64         assert(0);
65         return MarkerDataType();
66     }
67 }
68 
SEQ_LENGTH()69 const Descriptor MarkerTypes::SEQ_LENGTH() {
70     return Descriptor(MarkerTypes::SEQ_LENGTH_MARKER_ID, tr("Length markers"), tr("Length markers group."));
71 }
SEQ_NAME()72 const Descriptor MarkerTypes::SEQ_NAME() {
73     return Descriptor(MarkerTypes::SEQ_NAME_MARKER_ID, tr("Sequence name markers"), tr("Sequence name markers group."));
74 }
ANNOTATION_COUNT()75 const Descriptor MarkerTypes::ANNOTATION_COUNT() {
76     return Descriptor(MarkerTypes::ANNOTATION_COUNT_MARKER_ID, tr("Annotation count markers"), tr("Annotation count markers group."));
77 }
ANNOTATION_LENGTH()78 const Descriptor MarkerTypes::ANNOTATION_LENGTH() {
79     return Descriptor(MarkerTypes::ANNOTATION_LENGTH_MARKER_ID, tr("Annotation length markers"), tr("Annotation length markers group."));
80 }
QUAL_INT_VALUE()81 const Descriptor MarkerTypes::QUAL_INT_VALUE() {
82     return Descriptor(MarkerTypes::QUAL_INT_VALUE_MARKER_ID, tr("Qualifier integer value markers"), tr("Qualifier integer value markers group."));
83 }
QUAL_FLOAT_VALUE()84 const Descriptor MarkerTypes::QUAL_FLOAT_VALUE() {
85     return Descriptor(MarkerTypes::QUAL_FLOAT_VALUE_MARKER_ID, tr("Qualifier float value markers"), tr("Qualifier float value markers group."));
86 }
QUAL_TEXT_VALUE()87 const Descriptor MarkerTypes::QUAL_TEXT_VALUE() {
88     return Descriptor(MarkerTypes::QUAL_TEXT_VALUE_MARKER_ID, tr("Qualifier text value markers"), tr("Qualifier text value markers group."));
89 }
TEXT()90 const Descriptor MarkerTypes::TEXT() {
91     return Descriptor(MarkerTypes::TEXT_MARKER_ID, tr("Text markers"), tr("Text markers group."));
92 }
93 
getSlotByMarkerType(const QString & markerId,const QString & slotName)94 const Descriptor MarkerSlots::getSlotByMarkerType(const QString &markerId, const QString &slotName) {
95     if (markerId == MarkerTypes::SEQ_LENGTH_MARKER_ID) {
96         return Descriptor(slotName, slotName, tr("Sequence length marker."));
97     } else if (markerId == MarkerTypes::ANNOTATION_COUNT_MARKER_ID) {
98         return Descriptor(slotName, slotName, tr("Annotation count marker."));
99     } else if (markerId == MarkerTypes::ANNOTATION_LENGTH_MARKER_ID) {
100         return Descriptor(slotName, slotName, tr("Annotation length marker."));
101     } else if (markerId == MarkerTypes::QUAL_INT_VALUE_MARKER_ID) {
102         return Descriptor(slotName, slotName, tr("Qualifier integer value marker."));
103     } else if (markerId == MarkerTypes::QUAL_TEXT_VALUE_MARKER_ID) {
104         return Descriptor(slotName, slotName, tr("Qualifier text value marker."));
105     } else if (markerId == MarkerTypes::QUAL_FLOAT_VALUE_MARKER_ID) {
106         return Descriptor(slotName, slotName, tr("Qualifier float value marker."));
107     } else if (markerId == MarkerTypes::TEXT_MARKER_ID) {
108         return Descriptor(slotName, slotName, tr("Text marker."));
109     } else if (markerId == MarkerTypes::SEQ_NAME_MARKER_ID) {
110         return Descriptor(slotName, slotName, tr("Sequence name marker."));
111     } else {
112         assert(0);
113         return Descriptor();
114     }
115 }
116 
IN_MARKER_SEQ_PORT()117 const QString MarkerPorts::IN_MARKER_SEQ_PORT() {
118     return "in-marked-seq";
119 }
OUT_MARKER_SEQ_PORT()120 const QString MarkerPorts::OUT_MARKER_SEQ_PORT() {
121     return "out-marked-seq";
122 }
123 
createInstanse(const QString & type,const QVariant & additionalParam)124 Marker *MarkerFactory::createInstanse(const QString &type, const QVariant &additionalParam) {
125     Marker *m = nullptr;
126     if (type == MarkerTypes::QUAL_INT_VALUE_MARKER_ID || type == MarkerTypes::QUAL_TEXT_VALUE_MARKER_ID || type == MarkerTypes::QUAL_FLOAT_VALUE_MARKER_ID) {
127         m = new QualifierMarker(type, "NewQualMarker", additionalParam.toString());
128     } else if (MarkerTypes::ANNOTATION_LENGTH_MARKER_ID == type || MarkerTypes::ANNOTATION_COUNT_MARKER_ID == type) {
129         m = new AnnotationMarker(type, "NewQualMarker", additionalParam.toString());
130     } else if (MarkerTypes::TEXT_MARKER_ID == type) {
131         m = new TextMarker(type, "NewTextMarker");
132     } else {
133         m = new SequenceMarker(type, "NewSequenceMarker");
134     }
135 
136     if (NONE != m->hasAdditionalParameter()) {
137         m->setAdditionalParameter(additionalParam);
138     }
139 
140     return m;
141 }
142 
143 /************************************************************************/
144 /* Marker */
145 /************************************************************************/
Marker(const QString & markerType,const QString & markerName)146 Marker::Marker(const QString &markerType, const QString &markerName)
147     : type(markerType), name(markerName) {
148     dataType = MarkerTypes::getDataTypeById(markerType);
149     values.insert(MarkerUtils::REST_OPERATION, tr("Rest"));
150 }
151 
Marker(const Marker & m)152 Marker::Marker(const Marker &m)
153     : QObject(), type(m.type), name(m.name), dataType(m.dataType), values(m.values) {
154 }
155 
addValue(QString name,QString value)156 void Marker::addValue(QString name, QString value) {
157     values.insert(name, value);
158 }
159 
hasAdditionalParameter()160 ParameterState Marker::hasAdditionalParameter() {
161     return NONE;
162 }
163 
setAdditionalParameter(const QVariant &)164 void Marker::setAdditionalParameter(const QVariant &) {
165 }
166 
getAdditionalParameter()167 QVariant Marker::getAdditionalParameter() {
168     return QVariant();
169 }
170 
getAdditionalParameterName()171 QString Marker::getAdditionalParameterName() {
172     return "";
173 }
174 
getMarkingResult(const QVariant & object)175 QString Marker::getMarkingResult(const QVariant &object) {
176     foreach (QString val, values.keys()) {
177         if (MarkerUtils::REST_OPERATION == val) {
178             continue;
179         }
180         QVariantList expr;
181         bool res = MarkerUtils::stringToValue(dataType, val, expr);
182         if (!res) {
183             continue;
184         }
185 
186         bool marked = false;
187         switch (dataType) {
188             case INTEGER:
189                 marked = getMarkerIntResult(object, expr);
190                 break;
191             case FLOAT:
192                 marked = getMarkerFloatResult(object, expr);
193                 break;
194             case BOOLEAN:
195                 // marked = getMarkerBooleanResult(object, expr);
196                 break;
197             case STRING:
198                 marked = getMarkerStringResult(object, expr);
199                 break;
200         }
201         if (marked) {
202             return values.value(val);
203         }
204     }
205 
206     return values.value(MarkerUtils::REST_OPERATION);
207 }
208 
getMarkerIntResult(const QVariant & object,QVariantList & expr)209 bool Marker::getMarkerIntResult(const QVariant &object, QVariantList &expr) {
210     int obj = object.toInt();
211     QString operation = expr.at(0).toString();
212 
213     if (MarkerUtils::LESS_OPERATION == operation) {
214         int val = expr.at(1).toInt();
215         if (obj <= val) {
216             return true;
217         }
218     } else if (MarkerUtils::GREATER_OPERATION == operation) {
219         int val = expr.at(1).toInt();
220         if (obj >= val) {
221             return true;
222         }
223     } else if (MarkerUtils::INTERVAL_OPERATION == operation) {
224         int val1 = expr.at(1).toInt();
225         int val2 = expr.at(2).toInt();
226 
227         if (obj >= val1 && obj <= val2) {
228             return true;
229         }
230     }
231 
232     return false;
233 }
234 
getMarkerFloatResult(const QVariant & object,QVariantList & expr)235 bool Marker::getMarkerFloatResult(const QVariant &object, QVariantList &expr) {
236     float obj = object.toFloat();
237     QString operation = expr.at(0).toString();
238 
239     if (MarkerUtils::LESS_OPERATION == operation) {
240         float val = expr.at(1).toFloat();
241         if (obj <= val) {
242             return true;
243         }
244     } else if (MarkerUtils::GREATER_OPERATION == operation) {
245         float val = expr.at(1).toFloat();
246         if (obj >= val) {
247             return true;
248         }
249     } else if (MarkerUtils::INTERVAL_OPERATION == operation) {
250         float val1 = expr.at(1).toFloat();
251         float val2 = expr.at(2).toFloat();
252 
253         if (obj >= val1 && obj <= val2) {
254             return true;
255         }
256     }
257 
258     return false;
259 }
260 
getMarkerStringResult(const QVariant & object,QVariantList & expr)261 bool Marker::getMarkerStringResult(const QVariant &object, QVariantList &expr) {
262     QString obj = object.toString();
263     QString operation = expr.at(0).toString();
264     QString val = expr.at(1).toString();
265 
266     if (MarkerUtils::STARTS_OPERATION == operation) {
267         return obj.startsWith(val);
268     } else if (MarkerUtils::ENDS_OPERATION == operation) {
269         return obj.endsWith(val);
270     } else if (MarkerUtils::CONTAINS_OPERATION == operation) {
271         return obj.contains(val);
272     } else if (MarkerUtils::REGEXP_OPERATION == operation) {
273         QRegExp rx(val);
274         rx.setPatternSyntax(QRegExp::Wildcard);
275 
276         return rx.exactMatch(obj);
277     }
278 
279     return false;
280 }
281 
getName() const282 const QString &Marker::getName() const {
283     return name;
284 }
285 
getType() const286 const QString &Marker::getType() const {
287     return type;
288 }
289 
getValues() const290 const QMap<QString, QString> &Marker::getValues() const {
291     return values;
292 }
293 
getValues()294 QMap<QString, QString> &Marker::getValues() {
295     return values;
296 }
297 
setName(const QString & newName)298 void Marker::setName(const QString &newName) {
299     name = newName;
300 }
301 
toString() const302 const QString Marker::toString() const {
303     QString res;
304 
305     foreach (QString key, values.keys()) {
306         res += key + " : " + values.value(key) + "; ";
307     }
308     return res;
309 }
310 
311 /************************************************************************/
312 /* SequencerMarker */
313 /************************************************************************/
getMarkingResult(const QVariant & object)314 QString SequenceMarker::getMarkingResult(const QVariant &object) {
315     DNASequence seq = object.value<DNASequence>();
316 
317     if (MarkerTypes::SEQ_LENGTH_MARKER_ID == type) {
318         return Marker::getMarkingResult(seq.length());
319     } else if (MarkerTypes::SEQ_NAME_MARKER_ID == type) {
320         return Marker::getMarkingResult(seq.getName());
321     } else {
322         assert(0);
323         return values.value(MarkerUtils::REST_OPERATION);
324     }
325 }
326 
getGroup()327 MarkerGroup SequenceMarker::getGroup() {
328     return SEQUENCE;
329 }
330 
clone()331 Marker *SequenceMarker::clone() {
332     return new SequenceMarker(*this);
333 }
334 
335 /************************************************************************/
336 /* QualifierMarker */
337 /************************************************************************/
getMarkingResult(const QVariant & object)338 QString QualifierMarker::getMarkingResult(const QVariant &object) {
339     const QString rest = values.value(MarkerUtils::REST_OPERATION);
340 
341     QList<SharedAnnotationData> anns;
342     foreach (const QVariant &ann, object.toList()) {
343         SAFE_POINT(ann.canConvert<SharedAnnotationData>(), "Invalid annotation data encountered!", QString());
344         anns << ann.value<SharedAnnotationData>();
345     }
346 
347     for (const SharedAnnotationData &ann : qAsConst(anns)) {
348         foreach (const U2Qualifier &qual, ann->qualifiers) {
349             if (qual.name == qualName) {
350                 bool ok = false;
351                 QVariant value;
352                 if (MarkerTypes::QUAL_INT_VALUE_MARKER_ID == type) {
353                     value = qVariantFromValue(qual.value.toInt(&ok));
354                 } else if (MarkerTypes::QUAL_FLOAT_VALUE_MARKER_ID == type) {
355                     value = qVariantFromValue(qual.value.toFloat(&ok));
356                 } else if (MarkerTypes::QUAL_TEXT_VALUE_MARKER_ID == type) {
357                     value = qVariantFromValue(qual.value);
358                     ok = true;
359                 } else {
360                     FAIL("Unexpected marker type!", rest);
361                 }
362                 SAFE_POINT(ok, "Variant conversion error!", QString());
363                 QString mark = Marker::getMarkingResult(value);
364                 if (rest != mark) {
365                     return mark;
366                 }
367             }
368         }
369     }
370     return rest;
371 }
372 
getGroup()373 MarkerGroup QualifierMarker::getGroup() {
374     return QUALIFIER;
375 }
376 
getQualifierName() const377 const QString &QualifierMarker::getQualifierName() const {
378     return qualName;
379 }
380 
clone()381 Marker *QualifierMarker::clone() {
382     return new QualifierMarker(*this);
383 }
384 
hasAdditionalParameter()385 ParameterState QualifierMarker::hasAdditionalParameter() {
386     return REQUIRED;
387 }
388 
setAdditionalParameter(const QVariant & param)389 void QualifierMarker::setAdditionalParameter(const QVariant &param) {
390     qualName = param.toString();
391 }
392 
getAdditionalParameter()393 QVariant QualifierMarker::getAdditionalParameter() {
394     return qualName;
395 }
396 
getAdditionalParameterName()397 QString QualifierMarker::getAdditionalParameterName() {
398     return tr("Qualifier name");
399 }
400 
401 /************************************************************************/
402 /* AnnotationMarker */
403 /************************************************************************/
getMarkingResult(const QVariant & object)404 QString AnnotationMarker::getMarkingResult(const QVariant &object) {
405     QList<SharedAnnotationData> anns;
406     foreach (const QVariant &ann, object.toList()) {
407         SAFE_POINT(ann.canConvert<SharedAnnotationData>(), "Invalid annotation data encountered!", QString());
408         anns << ann.value<SharedAnnotationData>();
409     }
410 
411     if (MarkerTypes::ANNOTATION_COUNT_MARKER_ID == type) {
412         int count = 0;
413         if (annName.isEmpty()) {
414             count = anns.size();
415         } else {
416             foreach (const SharedAnnotationData &ann, anns) {
417                 if (ann->name == annName) {
418                     count++;
419                 }
420             }
421         }
422         return Marker::getMarkingResult(qVariantFromValue(count));
423     } else if (MarkerTypes::ANNOTATION_LENGTH_MARKER_ID == type) {
424         return values.value(MarkerUtils::REST_OPERATION);
425     } else {
426         assert(0);
427     }
428 
429     return values.value(MarkerUtils::REST_OPERATION);
430 }
431 
getGroup()432 MarkerGroup AnnotationMarker::getGroup() {
433     return ANNOTATION;
434 }
435 
getAnnotationName() const436 const QString &AnnotationMarker::getAnnotationName() const {
437     return annName;
438 }
439 
clone()440 Marker *AnnotationMarker::clone() {
441     return new AnnotationMarker(*this);
442 }
443 
hasAdditionalParameter()444 ParameterState AnnotationMarker::hasAdditionalParameter() {
445     return NOT_REQUIRED;
446 }
447 
setAdditionalParameter(const QVariant & param)448 void AnnotationMarker::setAdditionalParameter(const QVariant &param) {
449     annName = param.toString();
450 }
451 
getAdditionalParameter()452 QVariant AnnotationMarker::getAdditionalParameter() {
453     return annName;
454 }
455 
getAdditionalParameterName()456 QString AnnotationMarker::getAdditionalParameterName() {
457     return tr("Annotation name");
458 }
459 
460 /************************************************************************/
461 /* TextMarker */
462 /************************************************************************/
getMarkingResult(const QVariant & object)463 QString TextMarker::getMarkingResult(const QVariant &object) {
464     if (MarkerTypes::TEXT_MARKER_ID == type) {
465         return Marker::getMarkingResult(object);
466     } else {
467         assert(0);
468     }
469 
470     return values.value(MarkerUtils::REST_OPERATION);
471 }
472 
getGroup()473 MarkerGroup TextMarker::getGroup() {
474     return TEXT;
475 }
476 
clone()477 Marker *TextMarker::clone() {
478     return new TextMarker(*this);
479 }
480 
481 }  // namespace U2
482