1 /*
2  * (C) Copyright 2007-2015 Diomidis Spinellis
3  *
4  * You may only use this code if you agree to the terms of the CScout
5  * Source Code License agreement (see License.txt).
6  * If you do not agree to the terms, do not use the code.
7  *
8  * Encapsulates a (user interface) metrics query part
9  * Can be used to evaluate elements referenced through E against M metrics
10  *
11  */
12 
13 #ifndef MQUERY_
14 #define MQUERY_
15 
16 #include <vector>
17 #include <sstream>
18 
19 using namespace std;
20 
21 #include "query.h"
22 #include "swill.h"
23 #include "metrics.h"
24 
25 template <class M, class E>
26 class MQuery {
27 	// Query arguments
28 	char match_type;	// Type of boolean match
29 	int sort_order;		// Order to use for sorting
30 	bool reverse;		// Reverse the sort order
31 	vector <int> op;
32 	vector <int> n;
33 public:
MQuery()34 	MQuery() :
35 		sort_order(-1),
36 		reverse(0),
37 		op(M::metric_max, 0),
38 		n(M::metric_max, 0)
39 	{
40 		for (int i = 0; i < M::metric_max; i++) {
41 			ostringstream argspec;
42 
43 			argspec << "|i(c" << i << ")";
44 			argspec << "i(n" << i << ")";
45 			op[i] = n[i] = 0;
46 			(void)swill_getargs(argspec.str().c_str(), &(op[i]), &(n[i]));
47 		}
48 		if (!swill_getargs("i(order)", &sort_order))
49 			sort_order = -1;
50 		reverse = !!swill_getvar("reverse");
51 	}
52 
53 	// Accessor methods
set_match_type(char mt)54 	void set_match_type(char mt) { match_type = mt; }
get_sort_order()55 	int get_sort_order() const { return (sort_order); }
get_reverse()56 	bool get_reverse() const { return (reverse); }
57 
58 	// Return the URL for re-executing this query part
param_url()59 	string param_url() const {
60 		ostringstream url;
61 
62 		for (int i = 0; i < M::metric_max; i++)
63 			if (op[i]) {
64 				url << "&c" << i << '=' << op[i];
65 				url << "&n" << i << '=' << n[i];
66 			}
67 		if (sort_order != -1)
68 			url << "&order=" << sort_order;
69 		if (reverse)
70 			url << "&reverse=1";
71 		return url.str();
72 	}
73 
74 	// Evaluate the stored query against e
eval(E e)75 	bool eval(E e) {
76 		bool add;
77 
78 		switch (match_type) {
79 		default:
80 		case 'Y':	// anY match
81 			add = false;
82 			for (int j = 0; j < M::metric_max; j++)
83 				if (op[j] && Query::apply(op[j], e.metrics().get_metric(j), n[j])) {
84 					add = true;
85 					break;
86 				}
87 			break;
88 		case 'L':	// alL match
89 		case 'T':	// exactT match
90 			add = true;
91 			for (int j = 0; j < M::metric_max; j++)
92 				if (op[j] && !Query::apply(op[j], e.metrics().get_metric(j), n[j])) {
93 					add = false;
94 					break;
95 				}
96 			break;
97 		case 'E':	// excludE match
98 			add = true;
99 			for (int j = 0; j < M::metric_max; j++)
100 				if (op[j] && Query::apply(op[j], e.metrics().get_metric(j), n[j])) {
101 					add = false;
102 					break;
103 				}
104 			break;
105 		}
106 		return (add);
107 	}
108 
109 	// Generate a form's metrics query part
metrics_query_form(FILE * of)110 	static void metrics_query_form(FILE *of) {
111 		fputs("<table>"
112 		"<tr><th>Sort-by</th><th>Metric</th><th>Compare</th><th>Value</th></tr>\n", of);
113 		for (int i = 0; i < M::metric_max; i++) {
114 			if (Metrics::is_internal<M>(i))
115 				continue;
116 			fprintf(of, "<tr><td><input type=\"radio\" name=\"order\" value=\"%d\"> </td>\n", i);
117 			fprintf(of, "<td>%s</td><td><select name=\"c%d\" value=\"1\">\n",
118 				Metrics::get_name<M>(i).c_str(), i);
119 			Query::equality_selection(of);
120 			fprintf(of, "</td><td><INPUT TYPE=\"text\" NAME=\"n%d\" SIZE=5 MAXLENGTH=10></td></tr>\n", i);
121 		}
122 		fputs(	"<tr>"
123 			"<td><input type=\"radio\" name=\"order\" value=\"-1\" CHECKED></td>\n"
124 			"<td>Entity name</td>"
125 			"<td></td><td></td></tr>"
126 			"</table>\n"
127 			"<p>"
128 			"<input type=\"checkbox\" name=\"reverse\" value=\"0\">Reverse sort order\n", of);
129 	}
130 };
131 
132 #endif /* MQUERY_ */
133