<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonPickwareMobile\Components;

use Enlight_Event_EventManager;
use Doctrine\Common\Collections\ArrayCollection;
use \ViisonPickwareMobile_Interfaces_ShippingProvider_ShippingProvider as ShippingProviderInterface;

class ShippingProviderRepositoryService
{
    /**
     * The name of the event, which is fired to collect all shipping providers.
     */
    const EVENT_COLLECT_SHIPPING_PROVIDERS = 'Shopware_Plugins_ViisonPickwareMobile_CollectShippingProviders';

    /**
     * @var Enlight_Event_EventManager $eventManager
     */
    private $eventManager;

    /**
     * @var array $providers
     */
    private $providers;

    /**
     * @param Enlight_Event_EventManager $eventManager
     */
    public function __construct(Enlight_Event_EventManager $eventManager)
    {
        $this->eventManager = $eventManager;
    }

    /**
     * Checks whether the providers have already been collected and, if not, collects instances
     * of all available shipping providers. Finally the providers are returned.
     *
     * @return array
     */
    public function getProviders()
    {
        if ($this->providers) {
            return $this->providers;
        }

        // Collect providers
        $this->providers = $this->eventManager->collect(
            static::EVENT_COLLECT_SHIPPING_PROVIDERS,
            new ArrayCollection()
        );
        $this->providers = $this->providers->toArray();

        // Make sure all providers implement the ShippingProvider interface
        $this->providers = array_filter($this->providers, function ($provider) {
            return $provider instanceof ShippingProviderInterface;
        });

        return $this->providers;
    }

    /**
     * Returns the first shipping provider instance that matches the given function.
     *
     * @param callable $matchingFunction
     * @return ShippingProviderInterface|null
     */
    public function findProvider($matchingFunction)
    {
        $matchingProviders = array_filter($this->getProviders(), $matchingFunction);

        return (count($matchingProviders) > 0) ? array_values($matchingProviders)[0] : null;
    }

    /**
     * @param int $orderId
     * @return \Shopware\Plugins\ViisonPickwareMobile\Interfaces\ShippingProvider\ShippingProvider|null
     */
    public function findProviderForOrderWithId($orderId)
    {
        return $this->findProvider(function ($provider) use ($orderId) {
            return $provider->isShippingSupported($orderId);
        });
    }

    /**
     * @param int $dispatchMethodId
     * @return \Shopware\Plugins\ViisonPickwareMobile\Interfaces\ShippingProvider\ShippingProvider|null
     */
    public function findProviderForDispatchMethodWithId($dispatchMethodId)
    {
        return $this->findProvider(function ($provider) use ($dispatchMethodId) {
            return in_array($dispatchMethodId, $provider->validDispatchIds());
        });
    }

    /**
     * @param string $identifier
     * @return \Shopware\Plugins\ViisonPickwareMobile\Interfaces\ShippingProvider\ShippingProvider|null
     */
    public function findProviderForDocumentIdentifier($identifier)
    {
        return $this->findProvider(function ($provider) use ($identifier) {
            return $provider->hasCreatedDocumentWithIdentifier($identifier);
        });
    }

    /**
     * @param string $trackingCode
     * @return \Shopware\Plugins\ViisonPickwareMobile\Interfaces\ShippingProvider\ShippingProvider|null
     */
    public function findProviderForTrackingCode($trackingCode)
    {
        return $this->findProvider(function ($provider) use ($trackingCode) {
            return $provider->hasCreatedTrackingCode($trackingCode);
        });
    }
}
