<?php
/**
 * This file is part of the DATAtourisme project.
 *
 *  @author Conjecto <contact@conjecto.com>
 *
 * For the full copyright and license information, please view the LICENSE file that was distributed with this source code.
 */

namespace Datatourisme\Api\Processor;

use Datatourisme\Api\Exception\RuntimeException;
use Datatourisme\Api\Resolver\ResolverInterface;
use Datatourisme\Api\Schema\Compiler\SchemaCompiler;
use Datatourisme\Api\Schema\SchemaLoader;

class ProcessorBuilder
{
    /**
     * @var string
     */
    protected $schemaFile;

    /**
     * @var bool
     */
    protected $debug;

    /**
     * @var SchemaCompiler
     */
    protected $compiler;

    /**
     * @var SchemaLoader
     */
    protected $loader;

    /**
     * @var ResolverInterface
     */
    protected $resolver;

    /**
     * @var array
     */
    protected $entryPoints = array();

    /**
     * @var array
     */
    protected $typesMap = array();

    /**
     * ProcessorBuilder constructor.
     *
     * @param ResolverInterface $resolver
     * @param string            $schemaFile
     */
    public function __construct(ResolverInterface $resolver, string $schemaFile)
    {
        $this->resolver = $resolver;
        $this->schemaFile = $schemaFile;
    }

    /**
     * @param $compiler
     *
     * @return $this
     */
    public function setCompiler($compiler)
    {
        $this->compiler = $compiler;

        return $this;
    }

    /**
     * @return SchemaCompiler
     */
    public function getCompiler()
    {
        if (!$this->compiler) {
            $this->compiler = new SchemaCompiler();
        }

        return $this->compiler;
    }

    /**
     * @param mixed $loader
     *
     * @return $this
     */
    public function setLoader($loader)
    {
        $this->loader = $loader;

        return $this;
    }

    /**
     * @return SchemaLoader
     *
     * @throws \Exception
     */
    public function getLoader()
    {
        if (!$this->loader) {
            $this->loader = new SchemaLoader($this->getCompiler());
        }

        return $this->loader;
    }

    /**
     * @return ResolverInterface
     */
    public function getResolver()
    {
        return $this->resolver;
    }

    /**
     * @param ResolverInterface $resolver
     *
     * @return $this
     */
    public function setResolver($resolver)
    {
        $this->resolver = $resolver;

        return $this;
    }

    /**
     * @param bool $debug
     *
     * @return $this
     */
    public function setDebug($debug)
    {
        $this->debug = $debug;

        return $this;
    }

    /**
     * @param string $name
     * @param string $type
     *
     * @return ProcessorBuilder
     */
    public function addEntrypoint(string $name, string $type): ProcessorBuilder
    {
        $this->entryPoints[$name] = $type;

        return $this;
    }

    /**
     * @param string $name
     * @param string $className
     *
     * @return $this
     */
    public function addTypeMap(string $name, string $className)
    {
        $this->typesMap[$name] = $className;

        return $this;
    }

    /**
     * @return Processor
     *
     * @throws RuntimeException
     * @throws \Exception
     */
    public function getProcessor(): Processor
    {
        $this->getCompiler()->setTypesMap($this->typesMap);
        $schema = $this->getLoader()->load($this->schemaFile);

        // add entry points
        foreach ($this->entryPoints as $name => $entrypoint) {
            $schema->addEntryPoint($name, $entrypoint, $this->resolver);
        }

        // instanciate processor
        return new Processor($schema);
    }
}
