////////////////////////////////////////////////////////////////////////////////////
// Plugin: abstract base class for manipulation of rawdata (sort, deduplicate, range merging, etc)
// these components can be conditionally added to the converter

function Plugin(name){
	//interface for plugin
	this.name=name;
}
Plugin.prototype.name="Plugin";
Plugin.prototype.process=function(arrRules){
	throw new CustomError("Method must be overridden",1002,"Plugin::process - This method must be overridden");
	//throw('Plugin.process(): This method must be overridden');
}

////////////////////////////////////////////////////////////////////////////////////
// Sort (by ip/comment)

function Sort(name){
	this.Plugin = Plugin;
	this.Plugin(name);
}

Sort.prototype=new Plugin;
Sort.prototype.process=function(arrRules){
	ui.debug('Sorting rules');
	arrRules.sort(this.comparator);
	return arrRules;
}
Sort.prototype.comparator=function(a,b){return 0;}


function SortByIP(){
	this.Sort = Sort;
	this.Sort("Sort by Start IP");
}
SortByIP.prototype=new Sort;
SortByIP.prototype.comparator=function(a,b){
	//return ((a.action=="deny")? maxIP:0)-((b.action=="deny")? maxIP:0)+
	return (a.range.startIP-b.range.startIP)+((a.range.endIP-b.range.endIP)/maxIP);
}

function SortByComment(){
	this.Sort = Sort;
	this.Sort("Sort by Comment");
}
SortByComment.prototype=new Sort;
SortByComment.prototype.comparator=function(a,b){
	var ca=a.comment.toUpperCase();
	var cb=b.comment.toUpperCase();
	return ((ca==cb)?0:((ca>cb)?1:-1));;
}

function SortByRuleType(){
	this.Sort = Sort;
	this.Sort("Sort by Comment");
}
SortByRuleType.prototype=new Sort;
SortByRuleType.prototype.comparator=function(a,b){
	return ((a.action=="deny")? maxIP:0)-((b.action=="deny")? maxIP:0)+(a.range.startIP-b.range.startIP)+((a.range.endIP-b.range.endIP)/maxIP);
}

////////////////////////////////////////////////////////////////////////////////////
// Merger by range - find overlapping/contiguous ranges

function Merger(name){
	this.Plugin = Plugin;
	this.Plugin("Range merger");
}

Merger.prototype=new Plugin;

Merger.prototype.process=function(arrRules){
    //assumes arrRules is sorted by startIP and then endIP
    var newRules=new Array();
    var rc,rd; //range to check
	ui.debug('Merging Rules');
    newRules.push(arrRules[0]);
    for(var i=1;i<(arrRules.length);i++){
		rc=(arrRules[i]);
		if(rc.action==newRules[newRules.length-1].action){
			//check for intersection
			var shouldMerge = rc.range.intersects(newRules[newRules.length-1].range);
			//if merge adjacent then check for adjacency
			if (settings.listCleaning==3) shouldMerge = shouldMerge || rc.range.isAdjacent(newRules[newRules.length-1].range);
			//should we merge the ranges?
			if(shouldMerge){
				rd=newRules.pop();
				ui.debug("Merging Rules : "+rd.toString()+" and "+rc.toString());
				newRules.push(this.merge(rd,rc));
			}else{
				newRules.push(rc);
			}
		}else{
			newRules.push(rc);
		}
	}
    return newRules;
}

Merger.prototype.merge=function(r1,r2){
	//given two ranges merges them and returns the result
	var re=Math.max(r1.range.endIP,r2.range.endIP);
	var mtch=(r1.comment.toUpperCase().contains(r2.comment.toUpperCase()));
	mtch=mtch || (r2.comment.toUpperCase().contains(r1.comment.toUpperCase()))
	var cmt=(mtch?r1.comment:(r1.comment+"  and  "+r2.comment));
    return new Rule(decToIP(r1.range.startIP),decToIP(re),null,r1.action,cmt);
}
