<?
class PersistentOperand
{
    public $criteria;
    public $operand;
    public $type;

    public function __construct($criteria, $operand)
    {
        $this->criteria = $criteria;
        $this->operand = $operand;
    }

    public function getSql()
    {
        return '';
    }

    public function getSqlWhere()
    {
        return $this->getSql();
    }
}

class OperandNull extends PersistentOperand
{
    public function __construct($criteria, $operand)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'null';
    }
}

class OperandValue extends PersistentOperand
{
    public function __construct($criteria, $operand)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'value';
    }

    public function getSql()
    {
        $value = $this->operand; 
        if ($value{0} != '?')
        {
            if ($value{0} == ':')
            {
                $value = substr($value,1);
            }
            elseif (($value === '') || (strtolower($value)=='null') || is_null($value))
            {
                $value = 'null';
            }
            elseif ($value{0} != "'")
            {
                $value = "'".addslashes($value)."'";
            }
        }
        return $value;
    }
}

class OperandAttributeMap extends PersistentOperand
{
    public $attributeMap;
    public $alias = '';

    public function __construct($criteria, $operand, $name)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'attributemap';
        if ($p = strpos($name,'.')) $this->alias = substr($name,0, $p);
        $this->attributeMap = $operand;
    }

    public function getSql()
    {
        return $this->attributeMap->getColumnMap()->getColumnName($this->alias, FALSE,$this->attributeMap->getClassMap());
    }

    public function getSqlName()
    {
        return $this->attributeMap->getColumnMap()->getName();
    }

    public function getSqlOrder()
    {
        return $this->attributeMap->getColumnMap()->getFullyQualifiedName($this->alias);
    }

    public function getSqlWhere()
    {
        return $this->attributeMap->getColumnMap()->getColumnWhereName($this->alias,$this->attributeMap->getClassMap());
    }

    public function getSqlGroup()
    {
        return $this->attributeMap->getColumnMap()->getFullyQualifiedName($this->alias);
    }

}

class OperandArray extends PersistentOperand
{
    public function __construct($criteria, $operand)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'array';
    }

    public function getSql()
    {
        $sql = "(";
        $i = 0; 
        foreach($this->operand as $o)
        {
            $sql .= ($i++ > 0) ? ", " : "";
            $sql .= "'$o'";
        }
        $sql .= ")";
        return $sql;
    }
}

class OperandCriteria extends PersistentOperand
{
    public function __construct($criteria, $operand)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'criteria';
    }

    public function getSql()
    {
        $sql = $this->operand->getSqlStatement();
        $sql->setDb($this->operand->getManager()->getConnection($this->operand->getClassMap()->getDatabase()));
        return "(" . $sql->select() . ")";
    }
}

class OperandObject extends PersistentOperand
{
    public function __construct($criteria, $operand)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'object';
    }

    public function getSql()
    {
        return $this->operand->getSql();
    }
}

class OperandFunction extends PersistentOperand
{
    public $argument;
    public $argOperand;

    public function __construct($criteria, $operand)
    {
        parent::__construct($criteria, $operand);
        $this->type = 'public function';
        $str = $this->argument = $this->operand;
        $separator = "+-/*,()";
        $tok = strtok($str, $separator);
        while ($tok)
        {
            $t[$tok] = $tok;
            $tok = strtok($separator);
        }
        foreach($t as $token)
        {
            $op = $criteria->getOperand($token);
            if (get_class($op) == 'OperandValue')
            {
                $op = $criteria->getOperand(':'.$token);
            }
            $this->argument = str_replace($token,$op->getSql(), $this->argument);
        }
    }

    public function getSql()
    {
        return $this->argument;
    }

    public function getSqlGroup()
    {
        return $this->argument;
    }

    public function getSqlOrder()
    {
        return $this->argument;
    }

}