<?php
class Core_Doctrine_Record_Attribute extends Doctrine_Record_Generator
{
    protected $_options = array(
        'className'         => '%CLASS%Attribute',
        'tableName'         => '%TABLE%_attributes',
        'attributeName'     => 'Attribute',
        'attributeValueName'=> 'AttributeValue',
        'table'             => false,
        'pluginTable'       => false,
        'generateFiles'     => true,
        'children'          => array(),
        'cascadeDelete'     => true,
        'generateFiles'     => false,
        'appLevelDelete'    => false
    );

    /**
     * Accepts array of options to configure the AuditLog
     *
     * @param   array $options An array of options
     * @return  void
     */
    public function __construct(array $options = array())
    {
        $this->_options = Doctrine_Lib::arrayDeepMerge($this->_options, $options);
    }

    public function setUp()
    {
        // Will write Base_%CLASS%Attribute class and %CLASS%Attribute
        $this->_options['generatePath']     = APPLICATION_ROOT .'/shared/models';
        $this->_options['builderOptions']   = array(
            'pearStyle'             => true,
            //'generateTableClasses'  => 'Core_Doctrine_Record',
            'baseClassName'         => 'Core_Doctrine_Record',
            'baseClassPrefix'       => 'Base_',
            'baseClassesDirectory'  => null
        );
        $this->initialize($this->_table);
    }

    public function buildRelation()
    {
        $this->buildForeignRelation('Attributes');
        $this->buildLocalRelation();

        // Add relations with Attribute and AttributeValue
        $this->getTable()->hasOne($this->_options['attributeName'], array(
            'local'     => 'attribute_id',
            'foreign'   => 'attribute_id',
            'onUpdate'  => 'CASCADE',
            'onDelete'  => 'CASCADE'
        ));

        $this->getTable()->hasOne($this->_options['attributeValueName'], array(
            'local'     => 'attribute_value_id',
            'foreign'   => 'attribute_value_id',
            'onUpdate'  => 'CASCADE',
            'onDelete'  => 'CASCADE'
        ));

    }

    /**
     * Set the table definition for the attribute lookup table
     *
     * @return  void
     */
    public function setTableDefinition()
    {
        $name = $this->_options['table']->getComponentName();

        // Building columns
        $columns = $this->_options['table']->getColumns();

        // get all primary fields, remove all sequence and autoincrement definitions and add to the behavior model
        foreach ($columns as $column => $definition) {
            if (!isset($definition['primary']) || $definition['primary'] != true) {
                continue;
            }

            unset($definition['autoincrement']);
            unset($definition['sequence']);

            $fieldName = $this->_options['table']->getFieldName($column);
            if ($fieldName != $column) {
                $name = $column . ' as ' . $fieldName;
            } else {
                $name = $fieldName;
            }

            $this->hasColumn($name, $definition['type'], $definition['length'], $definition);
        }

        $this->hasColumn('attribute_id', 'integer', 8, array(
            'unsigned'  => 1,
            'primary'   => 1
        ));

        $this->hasColumn('attribute_value_id', 'integer', 8, array(
            'unsigned'  => 1,
            'primary'   => 1
        ));
    }

    /**
     * Add attribute to record
     *
     * @param Doctrine_Record $record
     * @param Attribute $attribute
     * @param AttributeValue $attributeValue
     *
     * @return Doctrine_Record
     */
    public function addAttribute(Doctrine_Record $record, Attribute $attribute, AttributeValue $attributeValue)
    {
        $className = $this->_options['className'];

        $relatedAttribute = $this->_getRelatedAttribute($record, $attribute, $attributeValue);

        if ($relatedAttribute !== false) {
            // We already have this attribute
            return $record;
        }

        $relatedAttribute = new $className;

        $relatedAttribute->attribute_id = $attribute->id;
        $relatedAttribute->attribute_value_id = $attributeValue->id;

        $record->Attributes[] = $relatedAttribute;
        $record->save();

        return $record;
    }

    /**
     * Remove attribute and its value
     *
     * @param Doctrine_Record $record
     * @param Attribute $attribute
     * @param AttributeValue $attributeValue
     *
     * @return \Doctrine_Record
     */
    public function removeAttribute(Doctrine_Record $record, Attribute $attribute, AttributeValue $attributeValue)
    {
        $relatedAttribute = $this->_getRelatedAttribute($record, $attribute, $attributeValue);

        if ($relatedAttribute) {
            $relatedAttribute->delete();
        }

        return $record;
    }

    /**
     * Get related attribute
     *
     * @param Doctrine_Record $record
     * @param Attribute $attribute
     * @param AttributeValue $attributeValue
     *
     * @return Doctrine_Record
     */
    protected function _getRelatedAttribute(Doctrine_Record $record, Attribute $attribute, AttributeValue $attributeValue)
    {
        $className = $this->_options['className'];

        $values = array();
        foreach ((array) $this->_options['table']->getIdentifier() as $id) {
            $conditions[]   = $className . '.' . $id . ' = ?';
            $values[]       = $record->get($id);
        }

        $q = Doctrine_Core::getTable($className)
            ->createQuery()
            ->andWhere(implode(' AND ', $conditions))
            ->andWhere('attribute_id = ?')
            ->andWhere('attribute_value_id = ?')
        ;

        $values[] = $attribute->id;
        $values[] = $attributeValue->id;

        return $q->fetchOne($values);
    }
}
