//ֲ
Selectors.Getters = {
 //ո,ʾݱǩidĳ
 ' ': function(found, self, tag, id, uniques){
  var items = Selectors.Utils.getByTagAndID(self, tag, id);
  for (var i = 0, l = items.length; i < l; i++){
   var item = items[i];
   if (Selectors.Utils.chk(item, uniques)) found.push(item);
  }
  return found;
 },
 
 //ں>ʾӽڵĲ
 '>': function(found, self, tag, id, uniques){
  var children = Selectors.Utils.getByTagAndID(self, tag, id);
  for (var i = 0, l = children.length; i < l; i++){
   var child = children[i];
   if (child.parentNode == self && Selectors.Utils.chk(child, uniques)) found.push(child);
  }
  return found;
 },
 
 //Ӻ+ʾֵܽڵĲ
 '+': function(found, self, tag, id, uniques){
  while ((self = self.nextSibling)){
   if (self.nodeType == 1){
    if (Selectors.Utils.chk(self, uniques) && Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
    break;
   }
  }
  return found;
 },
 
 //˺~ʾֵܽڵĲ
 '~': function(found, self, tag, id, uniques){
  
  while ((self = self.nextSibling)){
   if (self.nodeType == 1){
    if (!Selectors.Utils.chk(self, uniques)) break;
    if (Selectors.Filters.byTag(self, tag) && Selectors.Filters.byID(self, id)) found.push(self);
   } 
  }
  return found;
 }
 
};

//
Selectors.Filters = {

 //ݱǩ
 byTag: function(self, tag){
  return (tag == '*' || (self.tagName && self.tagName.toLowerCase() == tag));
 },
 
 //id
 byID: function(self, id){
  return (!id || (self.id && self.id == id));
 },
 
 //CSS
 byClass: function(self, klass){
  return (self.className && self.className.contains(klass, ' '));
 },
 
 //α
 byPseudo: function(self, parser, argument, local){
  return parser.call(self, argument, local);
 },
 
 //Թ
 byAttribute: function(self, name, operator, value){
  //ȡֵ
  var result = Element.prototype.getProperty.call(self, name);
  if (!result) return false;
  if (!operator || value == undefined) return true;
  //ֵ
  switch (operator){
   //
   case '=': return (result == value);
   //
   case '*=': return (result.contains(value));
   //ͷ
   case '^=': return (result.substr(0, value.length) == value);
   //β
   case '$=': return (result.substr(result.length - value.length) == value);
   //
   case '!=': return (result != value);
   //ոָ
   case '~=': return result.contains(value, ' ');
   //ӷָ
   case '|=': return result.contains(value, '-');
  }
  return false;
 }
 
};

//α
Selectors.Pseudo = new Hash({
 
 // w3c pseudo selectors
 
 //:empty,ƥ䲻ıĽڵ
 empty: function(){
  return !(this.innerText || this.textContent || '').length;
 },
 
 //:not,ƥָǩ
 not: function(selector){
  return !Element.match(this, selector);
 },
 
 //:contains,ƥڵаַָĽڵ
 contains: function(text){
  return (this.innerText || this.textContent || '').contains(text);
 },
 
 //:first-child,ƥһڵ
 'first-child': function(){
  return Selectors.Pseudo.index.call(this, 0);
 },
 
 //:last-child,ƥһڵ
 'last-child': function(){
  var element = this;
  while ((element = element.nextSibling)){
   if (element.nodeType == 1) return false;
  }
  return true;
 },
 
 //:only-child,ƥһӽڵȫΪElementĽڵ
 'only-child': function(){
  var prev = this;
  while ((prev = prev.previousSibling)){
   if (prev.nodeType == 1) return false;
  }
  var next = this;
  while ((next = next.nextSibling)){
   if (next.nodeType == 1) return false;
  }
  return true;
 },
 
 //:nth-child,ƥnڵ
 'nth-child': function(argument, local){
  argument = (argument == undefined) ? 'n' : argument;
  var parsed = Selectors.Utils.parseNthArgument(argument);
  //nthαĴת
  if (parsed.special != 'n') return Selectors.Pseudo[parsed.special].call(this, parsed.a, local);
  var count = 0;
  local.positions = local.positions || {};
  var uid = $uid(this);
  //ûλñǵļ¼
  if (!local.positions[uid]){
   var self = this;
   //ǰֵܽڵ
   while ((self = self.previousSibling)){
    //ԷElementڵ
    if (self.nodeType != 1) continue;
    count ++;
    var position = local.positions[$uid(self)];
    //бλõֵܽڵ,λú󼴿ѭ
    if (position != undefined){
     count = position + count;
     break;
    }
   }
   local.positions[uid] = count;
  }
  //a*n + bж,count = a*n + bƳ
  return (local.positions[uid] % parsed.a == parsed.b);
 },
 
 // custom pseudo selectors
 
 //:index,ƥָĽڵ
 index: function(index){
  var element = this, count = 0;
  //ǰ㵱ǰ
  while ((element = element.previousSibling)){
   if (element.nodeType == 1 && ++count > index) return false;
  }
  return (count == index);
 },
 
 //:even,ƥΪżĽڵ
 even: function(argument, local){
  return Selectors.Pseudo['nth-child'].call(this, '2n+1', local);
 },

 //:odd,ƥΪĽڵ
 odd: function(argument, local){
  return Selectors.Pseudo['nth-child'].call(this, '2n', local);
 }
 
});

