/*
Dependencies:
    lib_js/
            string.js
            node.js
*/

function Filter(){
}

Filter.prototype.apply=function(elem){
    alert("Filter.apply is abstract! If you think you have overriden this method, check the presence of the prototype keyword!");
};

function Filters(){};

/*Combining filters*/
Filters.Or=function(){
    if(arguments.length<2)
        alert("Improper use of Or filter: at least 2 filters should be provided!");
    this.filters=arguments;
};
Filters.Or.prototype=new Filter;
Filters.Or.prototype.apply=function(elem){
    var nb=this.filters.length;
    for(var i=0;i<nb;i++){
        if(this.filters[i].apply(elem))
            return true;
    }
    return false;
};

Filters.And=function(){
    if(arguments.length<2)
        alert("Improper use of And filter: at least 2 filters should be provided!");
    this.filters=arguments;
}
Filters.And.prototype=new Filter;
Filters.And.prototype.apply=function(elem){
    var nb=this.filters.length;
    for(var i=0;i<nb;i++){
        if(!this.filters[i].apply(elem))
            return false;
    }
    return true;
};

Filters.Not=function(filter){
    this.filter=filter;
}
Filters.Not.prototype=new Filter;
Filters.Not.prototype.apply=function(elem){
    return !this.filter.apply(elem);
};

/*Customized filters*/

//selects element if className matches
Filters.ClassNameMatches=function(className){
    this.className=className;
};
Filters.ClassNameMatches.prototype=new Filter;
Filters.ClassNameMatches.prototype.apply=function(elem){
    return elem.nodeType==Node.ELEMENT_NODE && elem.className==this.className;
};

//selects element if tagName matches
Filters.TagNameMatches=function(tagName){
    this.tagName=tagName;
}
Filters.TagNameMatches.prototype=new Filter;
Filters.TagNameMatches.prototype.apply=function(elem){
    return elem.nodeType==Node.ELEMENT_NODE && elem.tagName==this.tagName;
};

/*selects element if:
    1.element.NodeType == Node.ELEMENT_NODE
    2.element.className starts with given prefix
*/
Filters.ClassNameStartsWith=function(classNamePrefix){
    this.prefix=classNamePrefix;
}
Filters.ClassNameStartsWith.prototype=new Filter;
Filters.ClassNameStartsWith.prototype.apply=function(elem){
    return elem.nodeType==Node.ELEMENT_NODE && elem.className && elem.className.startsWith(this.prefix);
};

/*selects element if:
    1.element.NodeType == Node.ELEMENT_NODE
    2.element.className ends with given suffix
*/
Filters.ClassNameEndsWith=function(classNameSuffix){
    this.suffix=classNameSuffix;
}
Filters.ClassNameEndsWith.prototype=new Filter;
Filters.ClassNameEndsWith.prototype.apply=function(elem){
    return elem.nodeType==Node.ELEMENT_NODE && elem.className.endsWith(this.suffix);
};

/*selects element if:
    1.element.NodeType == Node.ELEMENT_NODE
    2.element.className contains given class (className may contain multiple classes)
*/
Filters.ContainsClass=function(singleClass){
    this.singleClass=singleClass;
}
Filters.ContainsClass.prototype=new Filter;
Filters.ContainsClass.prototype.apply=function(elem){
    if(elem.nodeType!=Node.ELEMENT_NODE)return false;
    var classes=elem.className.split(" ");
    for(var i in classes){
        if(classes[i]==this.singleClass)
            return true;
    }
    return false;
};

/*selects element if:
    1.element.NodeType == Node.ELEMENT_NODE
    2.element.id matches given id
*/
Filters.IdMatches=function(id){
    this.id=id;
}
Filters.IdMatches.prototype=new Filter;
Filters.IdMatches.prototype.apply=function(elem){
    return elem.nodeType==Node.ELEMENT_NODE && elem.id && elem.id==this.id;
};

Filters.NodeTypeMatches=function(nodeType){
    this.nodeType=nodeType;
}
Filters.NodeTypeMatches.prototype=new Filter;
Filters.NodeTypeMatches.prototype.apply=function(elem){
    return elem.nodeType==this.nodeType;
};
