<?php

namespace ModulesGarden\OpenXchangeAddon\Core\DependencyInjection;

use Illuminate\Contracts\Container\Container as ContainerContract;
use ModulesGarden\OpenXchangeAddon\Core\Helper\WhmcsVersionComparator;

class Container extends \Illuminate\Container\Container
{
    protected static $instance = null;

    public static function getInstance()
    {
        if (is_null(self::$instance))
        {
            self::$instance = new static;
        }

        return static::$instance;
    }

    public static function setInstance(?ContainerContract $container = null)
    {
        self::$instance = $container;
    }

    /**
     * @param $parameters
     * @param array $primitives
     * @return array
     */
    protected function getDependencies($parameters, array $primitives = array())
    {
        $dependencies = array();
        foreach ($parameters as $parameter)
        {
            if($parameter->isOptional())
            {
                break;
            }

            $dependency = $parameter->getClass();
            // If the class is null, it means the dependency is a string or some other
            // primitive type which we can not resolve since it is not a class and
            // we will just bomb out with an error since we have no-where to go.
            if (array_key_exists($parameter->name, $primitives))
            {
                $dependencies[] = $primitives[$parameter->name];
            }
            elseif (is_null($dependency))
            {
                $dependencies[] = $this->resolveNonClass($parameter);
            }
            else
            {
                $dependencies[] = $this->resolveClass($parameter);
            }
        }

        return (array) $dependencies;
    }

    /**
     * Set null value as default parameter when cannot find default value
     * @param ReflectionParameter $parameter
     * @return null
     */
    protected function resolveNonClass(\ReflectionParameter $parameter)
    {
        if ($parameter->isDefaultValueAvailable())
        {
            return $parameter->getDefaultValue();
        }

        return null;
    }

        /**
     * Resolve the given type from the container.
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     *
     * @throws \Illuminate\Contracts\Container\BindingResolutionException
     */
    public function make($abstract, array $parameters = [])
    {
        /* If $abstract contains namespace without slash at the begging, we need to add it */
        $explodedAbstract = explode('\\', $abstract);
        if($explodedAbstract[0] == 'ModulesGarden' && count($explodedAbstract) > 1)
        {
            $abstract = '\\'.$abstract;
        }

        /* This function executes a different code, depending on the version of the container - WHMCS 8 has a much newer version */
        $version8OrHigher = (new WhmcsVersionComparator)->isWVersionHigherOrEqual('8.0.0');
        if($version8OrHigher)
        {
            return $this->resolve($abstract, $parameters);
        }

        $abstract = $this->getAlias($this->normalize($abstract));
        if (isset($this->instances[$abstract])) {
            return $this->instances[$abstract];
        }

        $concrete = $this->getConcrete($abstract);
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete, $parameters);
        } else {
            $object = $this->make($concrete, $parameters);
        }

        foreach ($this->getExtenders($abstract) as $extender) {
            $object = $extender($object, $this);
        }

        if ($this->isShared($abstract)) {
            $this->instances[$abstract] = $object;
        }

        $this->fireResolvingCallbacks($abstract, $object);
        $this->resolved[$abstract] = true;

        return $object;
    }

}
