<?php

namespace apexl\Io\modules\display\includes;

use apexl\Io\modules\component\entities\componentEntity;
use apexl\Io\modules\display\components\RowWrapper;
use apexl\Utils\Arrays\Merge;

/**
 * Class region. This is a container wrapper for a general component - makes adhoc component grouping and injection much easier.
 * Base region class to allow others to extend. Provides generic page structures to allow for easy page building.
 * @package apexl\Io\modules\display\includes
 */
abstract class region
{
    protected $name;
    /** @var componentEntity */
    protected $regionComponent;
    protected $regions;
    protected $components;

    /**
     * region constructor.
     */
    public function __construct(array $components = [])
    {
        $this->setRegionWrapper();
        //check if we're adding a region or a component
        foreach ($components as $component) {
            if (method_exists($component, 'getWrapperType')) {
                if ($component->getWrapperType() == 'region') {
                    $this->addRegion($component);
                } else {
                    $this->addComponent($component);
                }
            } else {
                $this->addComponent($component);
            }
        }
    }

    public function getRegion($region)
    {
        return $this->regions[$region] ?? false;
    }

    public function getWrapperType()
    {
        return "region";
    }

    /**
     * Overload this method to change the wrapper.
     */
    public function setRegionWrapper()
    {
        $this->regionComponent = new RowWrapper();
    }

    public function addWrapperClass($class)
    {
        $this->regionComponent->addClass($class);
        return $this;
    }

    public function addSecondaryComponent(componentEntity $component)
    {
        $this->regionComponent->addSupportComponent($component);
        return $this;
    }

    public function clearWrapperClasses()
    {
        $this->regionComponent->resetClasses();
        $this->regionComponent->resetColumns();
        return $this;
    }

    /**
     * Add a component. Allow the specification of a sub region and the auto inclusion if it doesnt currently exist
     * @param $component
     * @param null $region
     * @param int $weight
     * @return $this
     */
    public function addComponent(componentEntity $component, $region = null, $weight = null)
    {
        if ($region) {
            $region = new $region();
            if (!isset($this->regions[$region->getRegionName()])) {
                $this->regions[$region->getRegionName()] = $region;
            }
            $this->regions[$region->getRegionName()]->addComponent($component, $weight);
        } elseif ($weight && isset($this->components[$weight])) {
            //check the weight and insert accordingly. if the key position exists already, insert after and increment everything else.
            Merge::arrayByWeight($weight, $component, $this->components);
        } else {
            $this->components[] = $component;
        }
        return $this;
    }

    /**
     * Add a subregion.
     * @param region $region
     * @return $this
     */
    public function addRegion(region $region)
    {
        if (!isset($this->regions[$region->getRegionName()])) {
            $this->regions[$region->getRegionName()] = $region;
        }
        return $this;
    }

    /**
     * Allows us to add multiple regions at once to construct basic "pages"
     * @param array $regions
     * @return $this
     */
    public function addRegions(array $regions)
    {
        foreach ($regions as $region) {
            $this->addRegion($region);
        }
        return $this;
    }

    /**
     * Easy get name of region method.
     * @return string
     */
    public function getRegionName()
    {
        return (new \ReflectionClass($this))->getShortName();
    }

    /**
     * Build the region as components for output to the API.
     */
    public function buildRegions()
    {
        //loop over all sub regions, components etc and run the builder methods.
        //we have to assume that regions are rendered before components.
        if ($this->regions) {
            foreach ($this->regions as $region) {
                $this->regionComponent->addComponent($region->buildRegions());
            }
        }
        if ($this->components) {
            foreach ($this->components as $component) {
                $this->regionComponent->addComponent($component);
            }
        }
        return $this->regionComponent;
    }
}
