/**
 * Abstract rule condition based on properties
 */
abstract class EcomDev_Rule_Model_Rule_Condition_Abstract extends Mage_Rule_Model_Condition_Abstract
{
    protected $_properties = null;

    /**
     * Should return a label of the current condition
     *
     * @return string
     */
    abstract protected function _getLabel();

    /**
     * Initializes properties of the rule condition
     *
     * @return EcomDev_Rule_Model_Rule_Condition_Abstract
     */
    protected function _initProperties()
    {
        if (is_array($this->_properties)) {
            foreach ($this->_properties as $code => $data) {
                $this->_properties[$code] = new Varien_Object($data);
                $this->_properties[$code]->setCode($code);
            }
        }

        return $this;
    }

    /**
     * Return list of available properties
     *
     * @return array
     */
    public function getProperties()
    {
        if ($this->_properties === null) {
            $this->_initProperties();
        }

        return $this->_properties;
    }

    /**
     * Retrieves property by code
     *
     * @param string $code
     * @return Varien_Object|boolean
     */
    public function getProperty($code = null)
    {
        if ($code === null) {
            $code = $this->getAttribute();
        }

        if ($this->_properties === null) {
            $this->_initProperties();
        }

        if (!isset($this->_properties[$code])) {
            return false;
        }

        return $this->_properties[$code];
    }

    /**
     * Prepare child rules option list
     *
     * @return array
     */
    public function getNewChildSelectOptions()
    {
        $attributes = $this->loadAttributeOptions()->getAttributeOption();
        $conditions = array();
        foreach ($attributes as $code => $label) {
            $conditions[] = array(
                'value' => $this->getType() . '|' . $code,
                'label' => $label
            );
        }

        return array(
            'value' => $conditions,
            'label' => $this->_getLabel()
        );
    }

    /**
     * Retrieve input type
     *
     * @return string
     */
    public function getInputType()
    {
        return ($this->getProperty() ? $this->getProperty()->getType() : 'string');
    }

    /**
     * Retrieve value element type
     *
     * @return string
     */
    public function getValueElementType()
    {
        if ($this->getInputType() === 'string' || $this->getInputType() === 'numeric') {
            return 'text';
        }

        return $this->getInputType();
    }

    /**
     * Validate propertyvalue for condition
     *
     * @param Varien_Object $object
     * @return bool
     */
    public function validate(Varien_Object $object)
    {
        if (!$this->getProperty()) {
            return false;
        }

        $valueToValidate = $object->getData($this->getProperty()->getDataPath());
        return $this->validateAttribute($valueToValidate);
    }

    /**
     * Load attribute options
     *
     * @return Mage_CatalogRule_Model_Rule_Condition_Product
     */
    public function loadAttributeOptions()
    {
        $options = array();

        foreach ($this->getProperties() as $property => $data) {
            $options[$property] = $data['label'];
        }

        $this->setAttributeOption($options);

        return $this;
    }

    /**
     * Prepares values options to be used as select options or hashed array
     * Result is stored in following keys:
     *  'value_select_options' - normal select array: array(array('value' => $value, 'label' => $label), ...)
     *  'value_option' - hashed array: array($value => $label, ...),
     *
     * @return EcomDev_Rule_Model_Rule_Condition_Abstract
     */
    protected function _prepareValueOptions()
    {
        // Check that both keys exist. Maybe somehow only one was set not in this routine, but externally.
        $selectReady = $this->getData('value_select_options');
        $hashedReady = $this->getData('value_option');
        if ($selectReady && $hashedReady) {
            return $this;
        }

        // Get array of select options. It will be used as source for hashed options
        $selectOptions = null;
        $hashedOptions = null;
        if ($this->getProperty() && is_array($this->getProperty()->getOptions())) {
            $hashedOptions = $this->getProperty()->getOptions();
            $optionGroups =  $this->getProperty()->getOptionGroups();
            $selectOptions = array();
            $selectOptionGroups = array();
            foreach ($hashedOptions as $value => $label) {
                if ($optionGroups) {
                    if (!isset($selectOptionGroups[$optionGroups[$value]])) {
                        $selectOptions[] = array(
                            'label' => $optionGroups[$value],
                            'value' => array()
                        );
                        $selectOptionGroups[$optionGroups[$value]] = &$selectOptions[count($selectOptions) - 1];
                    }

                    $selectOptionGroups[$optionGroups[$value]]['value'][] = array(
                        'label' => $label,
                        'value' => $value
                    );
                } else {
                    $selectOptions[] = array(
                        'label' => $label,
                        'value' => $value
                    );
                }
            }

            $this->setData('value_select_options', $selectOptions);
            $this->setData('value_option', $hashedOptions);
        }

        return $this;
    }

    /**
     * Retrieve value by option
     *
     * @param mixed $option
     * @return string
     */
    public function getValueOption($option=null)
    {
        $this->_prepareValueOptions();
        return $this->getData('value_option'.(!is_null($option) ? '/'.$option : ''));
    }

    /**
     * Retrieve select option values
     *
     * @return array
     */
    public function getValueSelectOptions()
    {
        $this->_prepareValueOptions();
        return $this->getData('value_select_options');
    }

    /**
     * Retrieve attribute element
     *
     * @return Varien_Form_Element_Abstract
     */
    public function getAttributeElement()
    {
        $element = parent::getAttributeElement();
        $element->setShowAsText(true);
        return $element;
    }
}