module.exports = sortByProcedure;

/*

sort the parts of the passed selector,
as there is potential for optimization
(some types of selectors are faster than others)

*/

var procedure = require(“./procedure.json”);

var attributes = {

__proto__: null,
exists: 10,
equals: 8,
not: 7,
start: 6,
end: 6,
any: 5,
hyphen: 4,
element: 4

};

function sortByProcedure(arr){

var procs = arr.map(getProcedure);
for(var i = 1; i < arr.length; i++){
        var procNew = procs[i];

        if(procNew < 0) continue;

        for(var j = i - 1; j >= 0 && procNew < procs[j]; j--){
                var token = arr[j + 1];
                arr[j + 1] = arr[j];
                arr[j] = token;
                procs[j + 1] = procs[j];
                procs[j] = procNew;
        }
}

}

function getProcedure(token){

var proc = procedure[token.type];

if(proc === procedure.attribute){
        proc = attributes[token.action];

        if(proc === attributes.equals && token.name === "id"){
                //prefer ID selectors (eg. #ID)
                proc = 9;
        }

        if(token.ignoreCase){
                //ignoreCase adds some overhead, prefer "normal" token
                //this is a binary operation, to ensure it's still an int
                proc >>= 1;
        }
} else if(proc === procedure.pseudo){
        if(!token.data){
                proc = 3;
        } else if(token.name === "has" || token.name === "contains"){
                proc = 0; //expensive in any case
        } else if(token.name === "matches" || token.name === "not"){
                proc = 0;
                for(var i = 0; i < token.data.length; i++){
                        //TODO better handling of complex selectors
                        if(token.data[i].length !== 1) continue;
                        var cur = getProcedure(token.data[i][0]);
                        //avoid executing :has or :contains
                        if(cur === 0){
                                proc = 0;
                                break;
                        }
                        if(cur > proc) proc = cur;
                }
                if(token.data.length > 1 && proc > 0) proc -= 1;
        } else {
                proc = 1;
        }
}
return proc;

}