gan_selector_html.php
protected function parse_conditions() {
		$p =& $this->parser;
		$tok = $p->token;

		if ($tok === CSSQueryTokenizer::TOK_NULL) {
			$this->error('Invalid search pattern(1): Empty string!');
			return false;
		}
		$conditions_all = array();

		//Tags
		while ($tok !== CSSQueryTokenizer::TOK_NULL) {
			$conditions = array('tags' => array(), 'attributes' => array());

			if ($tok === CSSQueryTokenizer::TOK_ALL) {
				$tok = $p->next();
				if (($tok === CSSQueryTokenizer::TOK_PIPE) && ($tok = $p->next()) && ($tok !== CSSQueryTokenizer::TOK_ALL)) {
					if (($tag = $this->parse_getIdentifier()) === false) {
						return false;
					}
					$conditions['tags'][] = array(
						'tag' => $tag,
						'compare' => 'name'
					);
					$tok = $p->next_no_whitespace();
				} else {
					$conditions['tags'][''] = array(
						'tag' => '',
						'match' => false
					);
					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$tok = $p->next_no_whitespace();
					}
				}
			} elseif ($tok === CSSQueryTokenizer::TOK_PIPE) {
				$tok = $p->next();
				if ($tok === CSSQueryTokenizer::TOK_ALL) {
					$conditions['tags'][] = array(
						'tag' => '',
						'compare' => 'namespace',
					);
				} elseif (($tag = $this->parse_getIdentifier()) !== false) {
					$conditions['tags'][] = array(
						'tag' => $tag,
						'compare' => 'total',
					);
				} else {
					return false;
				}
				$tok = $p->next_no_whitespace();
			} elseif ($tok === CSSQueryTokenizer::TOK_BRACE_OPEN) {
				$tok = $p->next_no_whitespace();
				$last_mode = 'or';

				while (true) {
					$match = true;
					$compare = 'total';

					if ($tok === CSSQueryTokenizer::TOK_NOT) {
						$match = false;
						$tok = $p->next_no_whitespace();
					}

					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$this->next();
							$compare = 'name';
							if (($tag = $this->parse_getIdentifier()) === false) {
								return false;
							}
						}
					} elseif ($tok === CSSQueryTokenizer::TOK_PIPE) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_ALL) {
							$tag = '';
							$compare = 'namespace';
						} elseif (($tag = $this->parse_getIdentifier()) === false) {
							return false;
						}
						$tok = $p->next_no_whitespace();
					} else {
						if (($tag = $this->parse_getIdentifier()) === false) {
							return false;
						}
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$tok = $p->next();

							if ($tok === CSSQueryTokenizer::TOK_ALL) {
								$compare = 'namespace';
							} elseif (($tag_name = $this->parse_getIdentifier()) !== false) {
								$tag = $tag.':'.$tag_name;
							} else {
								return false;
							}

							$tok = $p->next_no_whitespace();
						}
					}
					if ($tok === CSSQueryTokenizer::TOK_WHITESPACE) {
						$tok = $p->next_no_whitespace();
					}

					$conditions['tags'][] = array(
						'tag' => $tag,
						'match' => $match,
						'operator' => $last_mode,
						'compare' => $compare
					);
					switch($tok) {
						case CSSQueryTokenizer::TOK_COMMA:
							$tok = $p->next_no_whitespace();
							$last_mode = 'or';
							continue 2;
						case CSSQueryTokenizer::TOK_PLUS:
							$tok = $p->next_no_whitespace();
							$last_mode = 'and';
							continue 2;
						case CSSQueryTokenizer::TOK_BRACE_CLOSE:
							$tok = $p->next();
							break 2;
						default:
							$this->error('Expected closing brace or comma at pos %pos%!');
							return false;
					}
				}
			} elseif (($tag = $this->parse_getIdentifier(false)) !== false) {
				$tok = $p->next();
				if ($tok === CSSQueryTokenizer::TOK_PIPE) {
					$tok = $p->next();

					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$conditions['tags'][] = array(
							'tag' => $tag,
							'compare' => 'namespace'
						);
					} elseif (($tag_name = $this->parse_getIdentifier()) !== false) {
						$tag = $tag.':'.$tag_name;
						$conditions['tags'][] = array(
							'tag' => $tag,
							'match' => true
						);
					} else {
						return false;
					}

					$tok = $p->next();
                } elseif ($tag === 'text' && $tok === CSSQueryTokenizer::TOK_BRACE_OPEN) {
                    $pos = $p->getPos();
                    $tok = $p->next();
                    if ($tok === CSSQueryTokenizer::TOK_BRACE_CLOSE) {
                        $conditions['tags'][] = array(
                            'tag' => '~text~',
                            'match' => true
                        );
                        $p->next();
                    } else {
                        $p->setPos($pos);
                    }
				} else {
					$conditions['tags'][] = array(
						'tag' => $tag,
						'match' => true
					);
				}
			} else {
				unset($conditions['tags']);
			}

			//Class
			$last_mode = 'or';
			if ($tok === CSSQueryTokenizer::TOK_CLASS) {
				$p->next();
				if (($class = $this->parse_getIdentifier()) === false) {
					return false;
				}

				$conditions['attributes'][] = array(
					'attribute' => 'class',
					'operator_value' => 'contains_word',
					'value' => $class,
					'operator_result' => $last_mode
				);
				$last_mode = 'and';
				$tok = $p->next();
			}

			//ID
			if ($tok === CSSQueryTokenizer::TOK_ID) {
				$p->next();
				if (($id = $this->parse_getIdentifier()) === false) {
					return false;
				}

				$conditions['attributes'][] = array(
					'attribute' => 'id',
					'operator_value' => 'equals',
					'value' => $id,
					'operator_result' => $last_mode
				);
				$last_mode = 'and';
				$tok = $p->next();
			}

			//Attributes
			if ($tok === CSSQueryTokenizer::TOK_BRACKET_OPEN) {
				$tok = $p->next_no_whitespace();

				while (true) {
					$match = true;
					$compare = 'total';
					if ($tok === CSSQueryTokenizer::TOK_NOT) {
						$match = false;
						$tok = $p->next_no_whitespace();
					}

					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$tok = $p->next();
							if (($attribute = $this->parse_getIdentifier()) === false) {
								return false;
							}
							$compare = 'name';
							$tok = $p->next();
						} else {
							$this->error('Expected pipe at pos %pos%!');
							return false;
						}
					} elseif ($tok === CSSQueryTokenizer::TOK_PIPE) {
						$tok = $p->next();
						if (($tag = $this->parse_getIdentifier()) === false) {
							return false;
						}
						$tok = $p->next_no_whitespace();
					} elseif (($attribute = $this->parse_getIdentifier()) !== false) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$tok = $p->next();

							if (($attribute_name = $this->parse_getIdentifier()) !== false) {
								$attribute = $attribute.':'.$attribute_name;
							} else {
								return false;
							}

							$tok = $p->next();
						}
					} else {
						return false;
					}
					if ($tok === CSSQueryTokenizer::TOK_WHITESPACE) {
						$tok = $p->next_no_whitespace();
					}

					$operator_value = '';
					$val = '';
					switch($tok) {
						case CSSQueryTokenizer::TOK_COMPARE_PREFIX:
						case CSSQueryTokenizer::TOK_COMPARE_CONTAINS:
						case CSSQueryTokenizer::TOK_COMPARE_CONTAINS_WORD:
						case CSSQueryTokenizer::TOK_COMPARE_ENDS:
						case CSSQueryTokenizer::TOK_COMPARE_EQUALS:
						case CSSQueryTokenizer::TOK_COMPARE_NOT_EQUAL:
						case CSSQueryTokenizer::TOK_COMPARE_REGEX:
						case CSSQueryTokenizer::TOK_COMPARE_STARTS:
						case CSSQueryTokenizer::TOK_COMPARE_BIGGER_THAN:
						case CSSQueryTokenizer::TOK_COMPARE_SMALLER_THAN:
							$operator_value = $p->getTokenString(($tok === CSSQueryTokenizer::TOK_COMPARE_EQUALS) ? 0 : -1);
							$p->next_no_whitespace();

							if (($val = $this->parse_getIdentifier()) === false) {
								return false;
							}

							$tok = $p->next_no_whitespace();
							break;
					}

					if ($operator_value && $val) {
						$conditions['attributes'][] = array(
							'attribute' => $attribute,
							'operator_value' => $operator_value,
							'value' => $val,
							'match' => $match,
							'operator_result' => $last_mode,
							'compare' => $compare
						);
					} else {
						$conditions['attributes'][] = array(
							'attribute' => $attribute,
							'value' => $match,
							'operator_result' => $last_mode,
							'compare' => $compare
						);
					}

					switch($tok) {
						case CSSQueryTokenizer::TOK_COMMA:
							$tok = $p->next_no_whitespace();
							$last_mode = 'or';
							continue 2;
						case CSSQueryTokenizer::TOK_PLUS:
							$tok = $p->next_no_whitespace();
							$last_mode = 'and';
							continue 2;
						case CSSQueryTokenizer::TOK_BRACKET_CLOSE:
							$tok = $p->next();
							break 2;
						default:
							$this->error('Expected closing bracket or comma at pos %pos%!');
							return false;
					}
				}
			}

			if (count($conditions['attributes']) < 1) {
				unset($conditions['attributes']);
			}

			while($tok === CSSQueryTokenizer::TOK_COLON) {
				if (count($conditions) < 1) {
					$conditions['tags'] = array(array(
						'tag' => '',
						'match' => false
					));
				}

				$tok = $p->next();
				if (($filter = $this->parse_getIdentifier()) === false) {
					return false;
				}

				if (($tok = $p->next()) === CSSQueryTokenizer::TOK_BRACE_OPEN) {
					$start = $p->pos;
					$count = 1;
					while ((($tok = $p->next()) !== CSSQueryTokenizer::TOK_NULL) && !(($tok === CSSQueryTokenizer::TOK_BRACE_CLOSE) && (--$count === 0))) {
						if ($tok === CSSQueryTokenizer::TOK_BRACE_OPEN) {
							++$count;
						}
					}


					if ($tok !== CSSQueryTokenizer::TOK_BRACE_CLOSE) {
						$this->error('Expected closing brace at pos %pos%!');
						return false;
					}
					$len = $p->pos - 1 - $start;
					$params = (($len > 0) ? substr($p->doc, $start + 1, $len) : '');
					$tok = $p->next();
				} else {
					$params = '';
				}

				$conditions['filters'][] = array('filter' => $filter, 'params' => $params);
			}
			if (count($conditions) < 1) {
				$this->error('Invalid search pattern(2): No conditions found!');
				return false;
			}
			$conditions_all[] = $conditions;

			if ($tok === CSSQueryTokenizer::TOK_WHITESPACE) {
				$tok = $p->next_no_whitespace();
			}

			if ($tok === CSSQueryTokenizer::TOK_COMMA) {
				$tok = $p->next_no_whitespace();
				continue;
			} else {
				break;
			}
		}

		return $conditions_all;
	}
protected function parse_conditions() {
		$p =& $this->parser;
		$tok = $p->token;

		if ($tok === CSSQueryTokenizer::TOK_NULL) {
			$this->error('Invalid search pattern(1): Empty string!');
			return false;
		}
		$conditions_all = array();

		//Tags
		while ($tok !== CSSQueryTokenizer::TOK_NULL) {
			$conditions = array('tags' => array(), 'attributes' => array());

			if ($tok === CSSQueryTokenizer::TOK_ALL) {
				$tok = $p->next();
				if (($tok === CSSQueryTokenizer::TOK_PIPE) && ($tok = $p->next()) && ($tok !== CSSQueryTokenizer::TOK_ALL)) {
					if (($tag = $this->parse_getIdentifier()) === false) {
						return false;
					}
					$conditions['tags'][] = array(
						'tag' => $tag,
						'compare' => 'name'
					);
					$tok = $p->next_no_whitespace();
				} else {
					$conditions['tags'][''] = array(
						'tag' => '',
						'match' => false
					);
					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$tok = $p->next_no_whitespace();
					}
				}
			} elseif ($tok === CSSQueryTokenizer::TOK_PIPE) {
				$tok = $p->next();
				if ($tok === CSSQueryTokenizer::TOK_ALL) {
					$conditions['tags'][] = array(
						'tag' => '',
						'compare' => 'namespace',
					);
				} elseif (($tag = $this->parse_getIdentifier()) !== false) {
					$conditions['tags'][] = array(
						'tag' => $tag,
						'compare' => 'total',
					);
				} else {
					return false;
				}
				$tok = $p->next_no_whitespace();
			} elseif ($tok === CSSQueryTokenizer::TOK_BRACE_OPEN) {
				$tok = $p->next_no_whitespace();
				$last_mode = 'or';

				while (true) {
					$match = true;
					$compare = 'total';

					if ($tok === CSSQueryTokenizer::TOK_NOT) {
						$match = false;
						$tok = $p->next_no_whitespace();
					}

					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$this->next();
							$compare = 'name';
							if (($tag = $this->parse_getIdentifier()) === false) {
								return false;
							}
						}
					} elseif ($tok === CSSQueryTokenizer::TOK_PIPE) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_ALL) {
							$tag = '';
							$compare = 'namespace';
						} elseif (($tag = $this->parse_getIdentifier()) === false) {
							return false;
						}
						$tok = $p->next_no_whitespace();
					} else {
						if (($tag = $this->parse_getIdentifier()) === false) {
							return false;
						}
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$tok = $p->next();

							if ($tok === CSSQueryTokenizer::TOK_ALL) {
								$compare = 'namespace';
							} elseif (($tag_name = $this->parse_getIdentifier()) !== false) {
								$tag = $tag.':'.$tag_name;
							} else {
								return false;
							}

							$tok = $p->next_no_whitespace();
						}
					}
					if ($tok === CSSQueryTokenizer::TOK_WHITESPACE) {
						$tok = $p->next_no_whitespace();
					}

					$conditions['tags'][] = array(
						'tag' => $tag,
						'match' => $match,
						'operator' => $last_mode,
						'compare' => $compare
					);
					switch($tok) {
						case CSSQueryTokenizer::TOK_COMMA:
							$tok = $p->next_no_whitespace();
							$last_mode = 'or';
							continue 2;
						case CSSQueryTokenizer::TOK_PLUS:
							$tok = $p->next_no_whitespace();
							$last_mode = 'and';
							continue 2;
						case CSSQueryTokenizer::TOK_BRACE_CLOSE:
							$tok = $p->next();
							break 2;
						default:
							$this->error('Expected closing brace or comma at pos %pos%!');
							return false;
					}
				}
			} elseif (($tag = $this->parse_getIdentifier(false)) !== false) {
				$tok = $p->next();
				if ($tok === CSSQueryTokenizer::TOK_PIPE) {
					$tok = $p->next();

					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$conditions['tags'][] = array(
							'tag' => $tag,
							'compare' => 'namespace'
						);
					} elseif (($tag_name = $this->parse_getIdentifier()) !== false) {
						$tag = $tag.':'.$tag_name;
						$conditions['tags'][] = array(
							'tag' => $tag,
							'match' => true
						);
					} else {
						return false;
					}

					$tok = $p->next();
                } elseif ($tag === 'text' && $tok === CSSQueryTokenizer::TOK_BRACE_OPEN) {
                    $pos = $p->getPos();
                    $tok = $p->next();
                    if ($tok === CSSQueryTokenizer::TOK_BRACE_CLOSE) {
                        $conditions['tags'][] = array(
                            'tag' => '~text~',
                            'match' => true
                        );
                        $p->next();
                    } else {
                        $p->setPos($pos);
                    }
				} else {
					$conditions['tags'][] = array(
						'tag' => $tag,
						'match' => true
					);
				}
			} else {
				unset($conditions['tags']);
			}

			//Class
			$last_mode = 'or';
			if ($tok === CSSQueryTokenizer::TOK_CLASS) {
				$p->next();
				if (($class = $this->parse_getIdentifier()) === false) {
					return false;
				}

				$conditions['attributes'][] = array(
					'attribute' => 'class',
					'operator_value' => 'contains_word',
					'value' => $class,
					'operator_result' => $last_mode
				);
				$last_mode = 'and';
				$tok = $p->next();
			}

			//ID
			if ($tok === CSSQueryTokenizer::TOK_ID) {
				$p->next();
				if (($id = $this->parse_getIdentifier()) === false) {
					return false;
				}

				$conditions['attributes'][] = array(
					'attribute' => 'id',
					'operator_value' => 'equals',
					'value' => $id,
					'operator_result' => $last_mode
				);
				$last_mode = 'and';
				$tok = $p->next();
			}

			//Attributes
			if ($tok === CSSQueryTokenizer::TOK_BRACKET_OPEN) {
				$tok = $p->next_no_whitespace();

				while (true) {
					$match = true;
					$compare = 'total';
					if ($tok === CSSQueryTokenizer::TOK_NOT) {
						$match = false;
						$tok = $p->next_no_whitespace();
					}

					if ($tok === CSSQueryTokenizer::TOK_ALL) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$tok = $p->next();
							if (($attribute = $this->parse_getIdentifier()) === false) {
								return false;
							}
							$compare = 'name';
							$tok = $p->next();
						} else {
							$this->error('Expected pipe at pos %pos%!');
							return false;
						}
					} elseif ($tok === CSSQueryTokenizer::TOK_PIPE) {
						$tok = $p->next();
						if (($tag = $this->parse_getIdentifier()) === false) {
							return false;
						}
						$tok = $p->next_no_whitespace();
					} elseif (($attribute = $this->parse_getIdentifier()) !== false) {
						$tok = $p->next();
						if ($tok === CSSQueryTokenizer::TOK_PIPE) {
							$tok = $p->next();

							if (($attribute_name = $this->parse_getIdentifier()) !== false) {
								$attribute = $attribute.':'.$attribute_name;
							} else {
								return false;
							}

							$tok = $p->next();
						}
					} else {
						return false;
					}
					if ($tok === CSSQueryTokenizer::TOK_WHITESPACE) {
						$tok = $p->next_no_whitespace();
					}

					$operator_value = '';
					$val = '';
					switch($tok) {
						case CSSQueryTokenizer::TOK_COMPARE_PREFIX:
						case CSSQueryTokenizer::TOK_COMPARE_CONTAINS:
						case CSSQueryTokenizer::TOK_COMPARE_CONTAINS_WORD:
						case CSSQueryTokenizer::TOK_COMPARE_ENDS:
						case CSSQueryTokenizer::TOK_COMPARE_EQUALS:
						case CSSQueryTokenizer::TOK_COMPARE_NOT_EQUAL:
						case CSSQueryTokenizer::TOK_COMPARE_REGEX:
						case CSSQueryTokenizer::TOK_COMPARE_STARTS:
						case CSSQueryTokenizer::TOK_COMPARE_BIGGER_THAN:
						case CSSQueryTokenizer::TOK_COMPARE_SMALLER_THAN:
							$operator_value = $p->getTokenString(($tok === CSSQueryTokenizer::TOK_COMPARE_EQUALS) ? 0 : -1);
							$p->next_no_whitespace();

							if (($val = $this->parse_getIdentifier()) === false) {
								return false;
							}

							$tok = $p->next_no_whitespace();
							break;
					}

					if ($operator_value && $val) {
						$conditions['attributes'][] = array(
							'attribute' => $attribute,
							'operator_value' => $operator_value,
							'value' => $val,
							'match' => $match,
							'operator_result' => $last_mode,
							'compare' => $compare
						);
					} else {
						$conditions['attributes'][] = array(
							'attribute' => $attribute,
							'value' => $match,
							'operator_result' => $last_mode,
							'compare' => $compare
						);
					}

					switch($tok) {
						case CSSQueryTokenizer::TOK_COMMA:
							$tok = $p->next_no_whitespace();
							$last_mode = 'or';
							continue 2;
						case CSSQueryTokenizer::TOK_PLUS:
							$tok = $p->next_no_whitespace();
							$last_mode = 'and';
							continue 2;
						case CSSQueryTokenizer::TOK_BRACKET_CLOSE:
							$tok = $p->next();
							break 2;
						default:
							$this->error('Expected closing bracket or comma at pos %pos%!');
							return false;
					}
				}
			}

			if (count($conditions['attributes']) < 1) {
				unset($conditions['attributes']);
			}

			while($tok === CSSQueryTokenizer::TOK_COLON) {
				if (count($conditions) < 1) {
					$conditions['tags'] = array(array(
						'tag' => '',
						'match' => false
					));
				}

				$tok = $p->next();
				if (($filter = $this->parse_getIdentifier()) === false) {
					return false;
				}

				if (($tok = $p->next()) === CSSQueryTokenizer::TOK_BRACE_OPEN) {
					$start = $p->pos;
					$count = 1;
					while ((($tok = $p->next()) !== CSSQueryTokenizer::TOK_NULL) && !(($tok === CSSQueryTokenizer::TOK_BRACE_CLOSE) && (--$count === 0))) {
						if ($tok === CSSQueryTokenizer::TOK_BRACE_OPEN) {
							++$count;
						}
					}


					if ($tok !== CSSQueryTokenizer::TOK_BRACE_CLOSE) {
						$this->error('Expected closing brace at pos %pos%!');
						return false;
					}
					$len = $p->pos - 1 - $start;
					$params = (($len > 0) ? substr($p->doc, $start + 1, $len) : '');
					$tok = $p->next();
				} else {
					$params = '';
				}

				$conditions['filters'][] = array('filter' => $filter, 'params' => $params);
			}
			if (count($conditions) < 1) {
				$this->error('Invalid search pattern(2): No conditions found!');
				return false;
			}
			$conditions_all[] = $conditions;

			if ($tok === CSSQueryTokenizer::TOK_WHITESPACE) {
				$tok = $p->next_no_whitespace();
			}

			if ($tok === CSSQueryTokenizer::TOK_COMMA) {
				$tok = $p->next_no_whitespace();
				continue;
			} else {
				break;
			}
		}

		return $conditions_all;
	}
Get query conditions (tag, attribute and filter conditions)
@return array False on failure
@see DomNode::match()
@access private