/****** cr.0.js *******/ 

/* global andMask:false, maxArrayLen:false, FMT:false */
var CR = {};

CR.Predicates = {};

/**
 * go through all conditions, collecting all the evalResults of CR.evaluateCondition, and then apply the reactions.
 * First we apply false reactions to clear state.  Then we apply positive reactions in reverse order, making sure to
 * only apply a reaction once.
 * @param cs
 * @param subject
 */
CR.checkAllAndApply = function (cs, subject) {
    var evalResults;

    if (!cs || cs.length === 0) {
        return;
    }

    evalResults = cs.map(function(condition) {
        return CR.evaluateCondition(condition, subject);
    });

    subject.setReactions(evalResults);
};

CR.evaluateCondition = function (c, subject) {
    var resultMask = [];

    if (!c.predicates || c.predicates.length === 0 || !c.reactions) {
        return false;
    }

    c.predicates
        .filter(function(predicate) {
            return !!predicate.type;
        }).forEach(function(predicate, i) {
            var evalResult = CR.PredicateEval(predicate.type, predicate, subject);

            if (i === 0) {
                resultMask = evalResult;
            } else {
                resultMask = andMask(resultMask, evalResult);
            }
        });

    return {
        mask: resultMask,
        reactions: c.reactions
    };
};

CR.PredicateEval = function (pid, ctx, subject) {
    var l = CR.Resolve(ctx.left, subject);
    var r = CR.Resolve(ctx.right, subject);
    var len = maxArrayLen(l, r);
    var p;
    var result = [];
    var i;
    var _l;
    var _r;

    if (!l || !r) {
        return [false];
    }

    p = CR.GetPredicate(pid);

    for (i = 0; i < len; i++) {
        _l = l[i];
        _r = r[i];
        if (_l == undefined) _l = l[0];
        if (_r == undefined) _r = r[0];

        if (p.type === "num") {
            result[i] = p.compare(FMT.convertToNumber(_l), FMT.convertToNumber(_r));
        } else {
            if (typeof _l != "string") _l = ""+_l;
            if (typeof _r != "string") _r = ""+_r;
            result[i] = p.compare(_l, _r);
        }
    }

    return result;
};

/**
 *
 * @param pid
 */

CR.GetPredicate = function (pid) {
    var p = CR.Predicates[pid];

    if (!p) {
        throw "no predicate: " + pid;
    }

    return p;
};

/**
 * Resolves a data array/scalar given a pathObject and a base object from which to calculate relative paths.
 *
 *
 * @param pathObj object which describes the location of data.
 *
 *	- klip: the klip to look in (defaults to  base)
 *	- self : if true, use the base object
 *	- prop : property name
 *	- cx: the component to look in
 *	- idx : the data index to pull ( defaults to -1 -- last item)
 *	- raw : a raw constant value to use
 *
 *
 * @param base
 */
CR.Resolve = function (pathObj, base) {
    var data;
    var klip;
    var target;

    if (!pathObj) return false;
	if (pathObj.raw) return [pathObj.raw];
	if (pathObj.rawList) return pathObj.rawList;

	if (pathObj.self) {
		data = base.getFilteredData();
		if (!data){
			return undefined;
		}
	}

	if (pathObj.cx) {
		klip = base.getKlip();
		if (!klip) return; // during cx creation this might get called -- and we don't have a klip yet....so abort

		target = klip.getComponentById(pathObj.cx);

        if (!target){
            data = [];
        }else{
            data = target.getFilteredData();
        }
    }


	if (!data) return undefined;
	else if (!_.isArray(data)) return [data];
	else if (data.length == 0) return undefined;
	else if (data.length == 1) return data[0];
};;/****** cr.predicates.js *******/ 

/* global CR:false */
CR.Predicates["eq"] = {
    id: "eq",
    type: "num",
    name: "Equal To",
    text: "is equal to",
    optionLabel: "=",

    compare : function(l, r) {
        return l == r;
    }
};

CR.Predicates["ne"] = {
    id: "ne",
    type: "num",
    name: "Not Equal To",
    text: "is not equal to",
    optionLabel: "!=",

    compare: function(l, r) {
        return l != r;
    }
};

CR.Predicates["gt"] = {
    id: "gt",
    type: "num",
    name: "Greater Than",
    text: "is greater than",
    optionLabel: ">",

    compare: function(l, r) {
        return l > r;
    }
};

CR.Predicates["gteq"] = {
    id:"gteq",
    type: "num",
    name: "Greater Than Equal to",
    text: "is greater than or equal to",
    optionLabel: ">=",

    compare: function(l, r) {
        return l >= r;
    }
};

CR.Predicates["lt"] = {
    id: "lt",
    type: "num",
    name: "Less Than",
    text: "is less than",
    optionLabel: "<",

    compare: function(l, r) {
        return l < r;
    }
};

CR.Predicates["lteq"] = {
    id: "lteq",
    type: "num",
    name: "Less Than",
    text: "is less than or equal to",
    optionLabel: "<=",

    compare: function(l, r) {
        return l <= r;
    }
};

CR.Predicates["contain"] = {
    id: "contain",
    type: "txt",
    name: "Contains",
    text: "contains",
    optionLabel: "contains",

    compare: function(l, r) {
        return l.indexOf(r) != -1;
    }
};

CR.Predicates["notContain"] = {
    id: "notContain",
    type: "txt",
    name: "Does Not Contain",
    text: "does not contain",
    optionLabel: "does not contain",

    compare: function(l,r) {
        return l.indexOf(r) == -1;
    }
};;