<?php

namespace Opentalent\OtTemplating\ViewHelpers\Members;

use FluidTYPO3\Vhs\Traits\TemplateVariableViewHelperTrait;
use Opentalent\OtTemplating\Domain\Repository\MemberRepository;
use Opentalent\OtTemplating\Exception\ApiRequestException;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;

/**
 *   This view helper give access to an array named according to the 'as' variable
 *   and which contains the members of the structure, eventually grouped by instruments
 *
 *     {namespace ot=Opentalent\OtTemplating\ViewHelpers}
 *
 *     <ot:members.getAll as="members"
 *                        organizationId="{settings.organizationId}">
 *          <f:debug>{members}</f:debug>
 *     </ot:members.getAll>
 *
 * @package Opentalent\OtTemplating\ViewHelpers
 */
class GetAllViewHelper extends AbstractViewHelper {

    use TemplateVariableViewHelperTrait;

    /**
     * >> Required to prevent typo3 to escape the html output
     * @var boolean
     */
    protected $escapeOutput = false;

    /**
     * @var MemberRepository
     *
     */
    protected $memberRepository;

    /**
     * -- This method is expected by Fluid --
     * Declares the viewhelper's parameters
     */
    public function initializeArguments()
    {
        $this->registerArgument(
            'as',
            'string',
            'Name of the returned array',
            true
        );
        $this->registerArgument(
            'organizationId',
            'integer',
            'Id of the current structure',
            true
        );
        $this->registerArgument(
            'groupByInstruments',
            'bool',
            'If true, returns an array of the form [instrument=>[members]], 
                       else the returned array is simply [members]',
            false,
            false
        );
    }

    /**
     * -- This method is expected by Fluid --
     * Renders the content as html
     *
     * @return string
     * @throws ApiRequestException
     */
    public function render()
    {
        // Get current settings
        $as = $this->arguments['as'];
        $organizationId = $this->arguments['organizationId'];
        $groupByInstruments = $this->arguments['groupByInstruments'];

        // Get members of the structure
        $members = $this->memberRepository->findByOrganizationId($organizationId);

        // Sort by instrument (conductor first), then alphabetically by name
        usort($members,
            function($a, $b) {
                if ($a->getInstrument() == 'CONDUCTOR') {
                    return -1;
                } else if ($b->getInstrument() == 'CONDUCTOR') {
                    return 1;
                } else if ($a->getInstrument() != $b->getInstrument()) {
                    return strcmp($a->getInstrument(), $b->getInstrument());
                } else {
                    return strcmp($a->getName(), $b->getName());
                }
            }
        );

        if ($groupByInstruments) {

            // Instruments to display in first place (next will be sorted alphabetically)
            $stack1 = ['CONDUCTOR' => []];

            $stack2 = [];
            foreach ($members as $member) {
                // If that Instrument exist in stack1: put it in this one
                if (array_key_exists($member->getInstrument(), $stack1)) {
                    array_push($stack1[$member->getInstrument()], $member);
                } else {
                    // Create the new array if needed in stack2, then put the member in it
                    if (!array_key_exists($member->getInstrument(), $stack2)) {
                        $stack2[$member->getInstrument()] = [];
                    }
                    array_push($stack2[$member->getInstrument()], $member);
                }
            }

            // remove empty instruments in stack 1
            $stack1 = array_filter($stack1);

            // sort by instrument stack2
            ksort($stack2);

            $members = array_merge($stack1, $stack2);
        }

        $variables = [$as => $members];
        return $this->renderChildrenWithVariables($variables);
    }

    /**
     * @param MemberRepository $memberRepository
     */
    public function injectMemberRepository(MemberRepository $memberRepository)
    {
        $this->memberRepository = $memberRepository;
    }
}
