#!/usr/bin/env php
<?php
declare(strict_types=1);

use Zend\ServiceManager\ServiceManager;
use Zend\ServiceManager\Factory\InvokableFactory;
use Zend\Hydrator\ConfigProvider as HydratorConfigProvider;
use Zend\Cache\ConfigProvider as CacheConfigProvider;
use Swagger\V30\Hydrator;
use Swagger\V30\Hydrator\ReflectionBasedAbstractFactory;
use Zend\ServiceManager\Proxy\LazyServiceFactory;
use Zend\ServiceManager\AbstractFactory\ReflectionBasedAbstractFactory as ZendReflectionFactory;
use Symfony\Component\Console\Application;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Console\Input\InputDefinition;

// Setup/verify autoloading
$cwd = getcwd();
if (is_dir($cwd . '/vendor')) {
    echo "Using project autoloader based on current working directory\n";
    chdir($cwd);
    require 'vendor/autoload.php';
} elseif (file_exists($a = __DIR__ . '/../../../autoload.php')) {
    echo "Using project autoloader\n";
    require $a;
} elseif (file_exists($a = __DIR__ . '/../vendor/autoload.php')) {
    echo "Using project autoloader relative to bin directory\n";
    require $a;
} elseif (file_exists($a = __DIR__ . '/../autoload.php')) {
    echo "Using project autoloader relative to vendor directory\n";
    require $a;
} else {
    fwrite(STDERR, 'Cannot locate autoloader; please run "composer install"' . PHP_EOL);
    exit(1);
}

$application = new Application('swagger-codegen');

$hydratorConfig = new HydratorConfigProvider();
$cacheConfig = new CacheConfigProvider();

$cacheDir = getcwd() . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR . 'swagger';

if (!is_dir($cacheDir)) {
    mkdir($cacheDir, 0755, true);
}

$serviceManager = new ServiceManager(array_replace_recursive(
    $hydratorConfig->getDependencyConfig(),
    $cacheConfig->getDependencyConfig(),
    [
        'factories' => [
            \Swagger\Command\Codegen::class => \Swagger\Command\Service\CodegenFactory::class,
            \Swagger\Template::class => \Swagger\Service\TemplateFactory::class,
            \Swagger\Generator\HandlerGenerator::class => ZendReflectionFactory::class,
            \Swagger\Generator\ModelGenerator::class => ZendReflectionFactory::class,
            \Swagger\Generator\RoutesGenerator::class => ZendReflectionFactory::class,
            \Swagger\Generator\HydratorGenerator::class => ZendReflectionFactory::class,
            \Swagger\Generator\DependenciesGenerator::class => ZendReflectionFactory::class,
            \Swagger\Generator\ApiGenerator::class => ZendReflectionFactory::class,
            \Swagger\Ignore::class => \Swagger\Service\IgnoreFactory::class,
            \Zend\Validator\ValidatorChain::class => \Swagger\Service\ValidatorChainFactory::class,
            EventDispatcher::class => InvokableFactory::class,
            \Swagger\Parser::class => \Swagger\Service\ParserFactory::class,
            \Swagger\Composer::class => InvokableFactory::class,
            InputDefinition::class => InvokableFactory::class
        ],
        'aliases' => [
            'event_dispatcher' => EventDispatcher::class,
            EventDispatcherInterface::class => EventDispatcher::class
        ],
        'shared' => [
            \Zend\Validator\ValidatorChain::class => false,
            InputDefinition::class => false
        ],
        'services' => [
            'config' => [
                'hydrators' => [
                    'factories' => [
                        Hydrator\DocumentHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\InfoHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ServerHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\PathItemHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ContactHydrator::class => InvokableFactory::class,
                        Hydrator\LicenseHydrator::class => InvokableFactory::class,
                        Hydrator\ServerVariableHydrator::class => InvokableFactory::class,
                        Hydrator\OperationHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ParameterHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ReferenceHydrator::class => InvokableFactory::class,
                        Hydrator\ExampleHydrator::class => InvokableFactory::class,
                        Hydrator\MediaTypeHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\EncodingHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\HeaderHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\CallbackHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ExternalDocumentationHydrator::class => InvokableFactory::class,
                        Hydrator\LinkHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\RequestBodyHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ResponseHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ResponsesHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\SecurityRequirementHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\SchemaHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\OAuthFlowHydrator::class => InvokableFactory::class,
                        Hydrator\OAuthFlowsHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\SecuritySchemeHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\ComponentsHydrator::class => ReflectionBasedAbstractFactory::class,
                        Hydrator\TagHydrator::class => ReflectionBasedAbstractFactory::class
                    ],
                    'lazy_services' => [
                        'class_map' => [
                            Hydrator\PathItemHydrator::class => Hydrator\PathItemHydrator::class,
                            Hydrator\OperationHydrator::class => Hydrator\OperationHydrator::class,
                            Hydrator\ParameterHydrator::class => Hydrator\ParameterHydrator::class,
                            Hydrator\CallbackHydrator::class => Hydrator\CallbackHydrator::class,
                            Hydrator\MediaTypeHydrator::class => Hydrator\MediaTypeHydrator::class
                        ]
                    ],
                    'delegators' => [
                        Hydrator\PathItemHydrator::class => [
                            LazyServiceFactory::class
                        ],
                        Hydrator\OperationHydrator::class => [
                            LazyServiceFactory::class
                        ],
                        Hydrator\ParameterHydrator::class => [
                            LazyServiceFactory::class
                        ],
                        Hydrator\CallbackHydrator::class => [
                            LazyServiceFactory::class
                        ],
                        Hydrator\MediaTypeHydrator::class => [
                            LazyServiceFactory::class
                        ]
                    ]
                ],
                'caches' => [
                    'Cache.Swagger.Template' => [
                        'adapter' => [
                            'name'    => 'filesystem',
                            'options' => [
                                'ttl' => 3600,
                                'cache_dir' => $cacheDir
                            ],
                        ]
                    ]
                ]
            ]
        ]
    ]
));

$commandList = [
    $serviceManager->get(\Swagger\Command\Codegen::class)
];

$application->addCommands($commandList);

$application->run();
