<?php 
 
/* 
 * This file is part of Sulu. 
 * 
 * (c) Sulu GmbH 
 * 
 * This source file is subject to the MIT license that is bundled 
 * with this source code in the file LICENSE. 
 */ 
 
namespace Sulu\Component\Content\Compat\Block; 
 
use Sulu\Component\Content\Compat\Property; 
use Sulu\Component\Content\Compat\PropertyInterface; 
use Sulu\Component\Content\Document\Structure\PropertyValue; 
 
/** 
 * Representation of a block node in template xml. 
 * 
 * @method BlockPropertyType[] getTypes() 
 * @method addType(BlockPropertyType $type) 
 * @method BlockPropertyType getType(string $name) 
 * @method BlockPropertyType getProperties(int $index) 
 * @method BlockPropertyType initProperties(int $index, string $typeName) 
 */ 
class BlockProperty extends Property implements BlockPropertyInterface 
{ 
    public function __construct( 
        $name, 
        $metadata, 
        $defaultTypeName, 
        $mandatory = false, 
        $multilingual = false, 
        $maxOccurs = 1, 
        $minOccurs = 1, 
        $params = [], 
        $tags = [], 
        $col = null 
    ) { 
        parent::__construct( 
            $name, 
            $metadata, 
            'block', 
            $mandatory, 
            $multilingual, 
            $maxOccurs, 
            $minOccurs, 
            $params, 
            $tags, 
            $col, 
            $defaultTypeName 
        ); 
    } 
 
    public function setValue($value) 
    { 
        $this->doSetValue($value); 
 
        if ($this->propertyValue) { 
            $this->propertyValue->setValue($value); 
        } 
    } 
 
    public function setPropertyValue(PropertyValue $value) 
    { 
        parent::setPropertyValue($value); 
        $this->doSetValue($value); 
    } 
 
    /** 
     * Sub properties need to be referenced to the PropertyValue so 
     * that the "real" property is updated. 
     * 
     * TODO: This is very tedious code. It is important to factor this out. 
     */ 
    public function doSetValue($value) 
    { 
        $items = $value; 
        if ($value instanceof PropertyValue) { 
            $items = $value->getValue(); 
        } 
 
        if (null == $items) { 
            return; 
        } 
 
        // check value for single value 
        if (\array_keys($items) !== \range(0, \count($items) - 1)) { 
            $items = [$items]; 
        } 
 
        $this->properties = []; 
 
        for ($i = 0; $i < \count($items); ++$i) { 
            $item = $items[$i]; 
            $type = $this->initProperties($i, $item['type']); 
            if (isset($item['settings'])) { 
                $type->setSettings($item['settings']); 
            } 
 
            /** @var PropertyInterface $subProperty */ 
            foreach ($type->getChildProperties() as $subProperty) { 
                if (!isset($item[$subProperty->getName()])) { 
                    continue; 
                } 
 
                $subName = $subProperty->getName(); 
                $subValue = $item[$subName]; 
 
                if ($subValue instanceof PropertyValue) { 
                    $subValueProperty = new PropertyValue($subName, $subValue); 
                    $subProperty->setPropertyValue($subValueProperty); 
                    $item[$subName] = $subValueProperty; 
                } else { 
                    $subProperty->setValue($subValue); 
                } 
            } 
 
            $items[$i] = $item; 
        } 
 
        if ($value instanceof PropertyValue) { 
            $value->setValue($items); 
        } 
    } 
 
    /** 
     * get value of sub properties. 
     * 
     * @return array|mixed 
     */ 
    public function getValue() 
    { 
        // if size of children smaller than minimum 
        if (\count($this->properties) < $this->getMinOccurs()) { 
            for ($i = \count($this->properties); $i < $this->getMinOccurs(); ++$i) { 
                $this->initProperties($i, $this->getDefaultTypeName()); 
            } 
        } 
 
        $data = []; 
        foreach ($this->properties as $type) { 
            $result = [ 
                'type' => $type->getName(), 
                'settings' => $type->getSettings(), 
            ]; 
            foreach ($type->getChildProperties() as $property) { 
                $result[$property->getName()] = $property->getValue(); 
            } 
            $data[] = $result; 
        } 
 
        return $data; 
    } 
 
    /** 
     * returns TRUE if property is a block. 
     * 
     * @return bool 
     */ 
    public function getIsBlock() 
    { 
        return true; 
    } 
 
    public function getIsMultiple() 
    { 
        if (\is_null($this->getMinOccurs()) || \is_null($this->getMaxOccurs())) { 
            // in contrast to properties blocks are multiple by default 
            return true; 
        } 
 
        return parent::getIsMultiple(); 
    } 
 
    /** 
     * returns child properties of given Type. 
     * 
     * @param string $typeName 
     * 
     * @return PropertyInterface[] 
     */ 
    public function getChildProperties($typeName) 
    { 
        return $this->getTypeChildProperties($typeName); 
    } 
}