$jsxt = function() {
    var templates = Array.fromObject(arguments);
    var res = {
        "apply": function(node) {
            if (!node)
                return;
            if (typeof node == "string")
                node = document.getElementById(node);
            if (node.documentElement)
                node = node.documentElement;
            var flag = true;
            for (var i = 0; i < templates.length; i++) {
                if (templates[i].predicate(node)) {
                    flag = templates[i].action.call(res, node);
                    break;
                }
            }
            if (flag || flag == undefined) {
                $dom.childNodes(node).foreach(function(v) {
                    res.apply(v);
                });
            }
        },
        "transform": function(nd) {
            if (!nd)
                return undefined;
            if (typeof nd == "string")
                nd = document.getElementById(nd);
            if (nd.documentElement)
                nd = nd.documentElement;
            for (var i = 0; i < templates.length; i++) {
                if (templates[i].predicate(nd))
                    return templates[i].action.call(res, nd);
            }
            return undefined;
        }
    }
    return res;
}

$jsxt.template = function(predicate, fn) {
    return {
        "predicate": predicate,
        "action": fn
    }
}

$jsxt.pTrue = function() {
    return function(v) {
        return true;
    }
}

$jsxt.pFalse = function() {
    return function(v) {
        return false;
    }
}

$jsxt.pNot = function(p) {
    return function(v) {
        return !p(v);
    }
}

$jsxt.pAnd = function() {
    var args = Array.fromObject(arguments);
    return function(v) {
        for (var i = 0; i < args.length; i++)
            if (!(args[i])(v))
                return false;
        return true;
    }
}

$jsxt.pOr = function() {
    var args = Array.fromObject(arguments);
    return function(v) {
        for (var i = 0; i < args.length; i++)
            if ((args[i])(v))
                return true;
        return false;
    }
}

$jsxt.pId = function(s) {
    return function(v) {
        return v.id == s;
    }
}

$jsxt.pClass = function(s) {
    return function(v) {
        if (v.className) {
            return v.className.split(/\s+/).accumulate(false, function(res, v) {
                return res || v == s;
            });
        } else
            return false;
    }
}

$jsxt.pName = function(s) {
    return function(v) {
        return v.nodeName == s;
    }
}

$jsxt.pParent = function(p) {
    return function(v) {
        return p(v.parentNode);
    }
}

$jsxt.pChild = function(p) {
    return function(v) {
        for (var i in $dom.childNodes(v))
            if (p(i))
                return true;
        return false;
    }
}

