/**
* Copyright (c) 2019
*
* @summary chart class
* @author Elitza Vasileva
* @author Bernhard Pointner
*/
class FilterDimensionsLogicalOperators {
constructor(_dimensions, _cat_identifier, _cat_identifier_start) {
this.dimensions = _dimensions; // crossfilter dimensions list
this.cat_identifier = _cat_identifier;
this.cat_identifier_start = _cat_identifier_start;
this.filters = []; // ex: [{index: 0, match: 0, operator: "AND"}]
this.operatorsLookup = {"AND":"&&","OR":"||","NOT":"!"};
}
/**
* Adds a filter on a dimension specified by the index
* @param index
* @param match
* @param operator the operator to be applied
*/
addFilterOnDimensionIndex(index,match,operator) {
// change filter type if index already exists but with different operator
let found_filter_with_different_op = this.filters.filter(filter => filter.index == index && filter.operator != operator);
if(found_filter_with_different_op.length == 1) {
// update filter
found_filter_with_different_op.operator = operator;
return;
}
let found_filter_with_same_op = this.filters.filter(filter => filter.index == index && filter.operator == operator);
if(found_filter_with_same_op.length == 1) {
// remove filter
this.removeFilterOnDimensionIndex(index);
return;
}
let found_filter = this.filters.filter(filter => filter.index == index);
if(found_filter.length == 0) {
// add filter
this.filters.push({index:index,match:match,operator:operator});
return;
}
}
/**
* Remove a filter on a specific dimension
* @param index
*/
removeFilterOnDimensionIndex(index) {
this.filters = this.filters.filter(filter => filter.index != index);
}
/**
* Evaluates the expression result of a single row
* @param row the row to be evaluated
* @param i the index
* @returns {boolean}
*/
evaluateRow(row,i) {
// uses eval() function: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/eval
let expression = 1;
let operator = "";
for(let i=0;i<this.filters.length;i++) {
operator = this.operatorsLookup[this.filters[i].operator];
if(i==0 && this.filters[i].operator == "NOT") {
expression = operator + (row[this.cat_identifier + (this.filters[i].index + this.cat_identifier_start)] == this.filters[i].match ? 1 : 0);
}
else if(i==0 && this.filters[i].operator != "NOT") {
expression = "" + (row[this.cat_identifier + (this.filters[i].index + this.cat_identifier_start)] == this.filters[i].match ? 1 : 0);
}
else if(this.filters[i].operator == "NOT") {
expression += "&&" + operator + (row[this.cat_identifier + (this.filters[i].index + this.cat_identifier_start)] == this.filters[i].match ? 1 : 0);
}
else {
expression += operator + (row[this.cat_identifier + (this.filters[i].index + this.cat_identifier_start)] == this.filters[i].match ? 1 : 0);
}
}
let result = this.evaluateExpression(""+expression);
return result; // boolean
}
/**
* Own method for evaluating an expression containing only the operators AND, OR or NOT
* @param expression the expression to be evaluated
* @returns {boolean}
*/
evaluateExpression(expression) {
let ors = expression.split("||");
let resultingExpression = [];
for(let i=0;i<ors.length;i++) {
let ands = ors[i].split("&&").map(value => value.length==2 ? !value[1] : value);
let amountZero = ands.filter(value => value.length==2 ? +(!value[1]) == 0 : +value == 0).length;
resultingExpression.push(!(amountZero>0));
}
return resultingExpression.filter(value => value).length > 0;
}
/**
* Resets the filter
*/
resetFilter() {
this.filters = []; // ex: [{index: 0, math: 0, operator: "AND"}]
}
}