<?php

namespace ActivityPhpTest\Type;

use ActivityPhp\Type;
use ActivityPhp\Type\Dialect;
use Exception;
use PHPUnit\Framework\TestCase;

class DialectTest extends TestCase
{
	/**
	 * Test basic getters
	 */
	public function testBasicGetters()
	{
		Dialect::clear();

		// test with empty stacks
		$this->assertEquals([], Dialect::getLoadedDialects());
		$this->assertEquals([], Dialect::getDialects());
		$this->assertEquals([], Dialect::getDefinitions());

		$dialect = [
		    // Add fields to one type
		    'Person' => [
		        'myDialectField'
		    ],
		];

		// Simply add this dialect
		Dialect::add('mydialect', $dialect, false);

		// test with a little stack stacks
		$this->assertEquals([], Dialect::getLoadedDialects());
		$this->assertEquals(['mydialect'], Dialect::getDialects());
		$this->assertEquals([
		    'Person' => [
		        'myDialectField' => [
		            'defaultValue' => '',
		            'validator'    => '',
		            'dialects'     => [
		                'mydialect',
		            ]
		        ]
		    ]
		], Dialect::getDefinitions());

		// Load this dialect
		Dialect::load('mydialect');

		$this->assertEquals(['mydialect'], Dialect::getLoadedDialects());
		$this->assertEquals(['mydialect'], Dialect::getDialects());
	}


	/**
	 * Extend one type with one property
	 */
	public function testExtendOneTypeWithOneProperty()
	{
		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person' => [
		        'myDialectField'
		    ],
		];

		// Add and load this dialect
		Dialect::add('mydialect', $dialect);

		// Set this dialect property for one type
		$type = Type::create('Person', ['myDialectField' => 1]);

		$this->assertEquals(
		    1,
		    $type->myDialectField
		);
	}


	/**
	 * Define and load a property for 2 dialect
	 */
	public function testExtendWithTwoDialects()
	{
		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person' => [
		        'myDialectField'
		    ],
		];

		// Add and load these dialect
		Dialect::add('myDialect', $dialect);
		Dialect::add('mySecondDialect', $dialect);

		// Set this dialect property for one type
		$type = Type::create('Person', ['myDialectField' => 1]);

		$this->assertEquals(
		    1,
		    $type->myDialectField
		);
	}


	/**
	 * Extend 2 types type with one property
	 */
	public function testExtendTwoTypeWithOneProperty()
	{
		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person|Application' => [
		        'myDialectField'
		    ],
		];

		// Add and load this dialect
		Dialect::add('mydialect', $dialect);

		// Set this dialect property for one type
		$person = Type::create('Person', ['myDialectField' => 1]);
		$application = Type::create('Application', ['myDialectField' => 2]);

		$this->assertEquals(
		    1,
		    $person->myDialectField
		);
		$this->assertEquals(
		    2,
		    $application->myDialectField
		);
	}


	/**
	 * Add and load a dialect in 2 steps
	 */
	public function testAddThenLoadDialect()
	{
		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person|Application' => [
		        'myDialectField'
		    ],
		];

		// Simply add this dialect
		Dialect::add('mydialect', $dialect, false);

		// Load it
		Dialect::load('mydialect');

		// Set this dialect property for one type
		$person = Type::create('Person', ['myDialectField' => 1]);

		$this->assertEquals(
		    1,
		    $person->myDialectField
		);
	}


	/**
	 * Add and load all dialects in 2 steps
	 */
	public function testAddThenLoadAllDialect()
	{
		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person|Application' => [
		        'myDialectField'
		    ],
		];

		// Simply add this dialect
		Dialect::add('mydialect', $dialect, false);

		// Load it
		Dialect::load('*');

		// Set this dialect property for one type
		$person = Type::create('Person', ['myDialectField' => 1]);

		$this->assertEquals(
		    1,
		    $person->myDialectField
		);
	}


	/**
	 * Should throw an Exception when using a dialect that has
	 * been defined and loaded, then unloaded
	 */
	public function testAddLoadUnloadDialect()
	{
		$this->expectException(Exception::class);

		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person|Application' => [
		        'myDialectField'
		    ],
		];

		// Add and load this dialect
		Dialect::add('mydialect', $dialect);
		Dialect::unload('mydialect');

		// Set this dialect property for one type
		$person = Type::create('Person', ['myDialectField' => 1]);
	}


	/**
	 * Should throw an Exception when using a dialect that has
	 * been defined and loaded, then unloaded with *
	 */
	public function testAddLoadUnloadAllDialects()
	{
		$this->expectException(Exception::class);

		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person|Application' => [
		        'myDialectField'
		    ],
		];

		// Add and load this dialect
		Dialect::add('mydialect', $dialect);
		Dialect::unload('*');

		// Set this dialect property for one type
		$person = Type::create('Person', ['myDialectField' => 1]);
	}


	/**
	 * Should throw an Exception when a property has a wrong definition
	 */
	public function testWrongPropertyDefinition()
	{
		$this->expectException(Exception::class);

		Dialect::clear();

		$dialect = [
		    // Add a wrong definition (properties must be an array
		    'Person|Application' =>
		        'myDialectField'
		    ,
		];

		// Add and load this dialect
		Dialect::add('mydialect', $dialect);
	}


	/**
	 * Should throw an Exception when using a define dialect that has
	 * not been loaded
	 */
	public function testUsingNotLoadedDialect()
	{
		$this->expectException(Exception::class);

		Dialect::clear();

		$dialect = [
		    // Add fields to one type
		    'Person|Application' => [
		        'myDialectField'
		    ],
		];

		// Simply add this dialect
		Dialect::add('mydialect', $dialect, false);

		// Set this dialect property for one type
		$person = Type::create('Person', ['myDialectField' => 1]);
	}


	/**
	 * Should throw an Exception when trying to load an undefined
	 * dialect
	 */
	public function testLoadingUndefinedDialect()
	{
		$this->expectException(Exception::class);

		Dialect::clear();

		Dialect::load('mydialect');
	}


	/**
	 * Throw an Exception when trying to use a type that has been
	 * unloaded
	 */
	public function testUsingAnUnloadedType()
	{
		$this->expectException(Exception::class);

		Dialect::clear();

		$dialect = [
		    // A new type
		    'MyDialectType' => [
		        'myDialectField'
		    ],
		];

		// Add and load
		Dialect::add('mydialect', $dialect);
		Dialect::unload('mydialect');
		Type::create('MyDialectType');
	}


	/**
	 * Create a new callable type with dialect
	 */
	public function testCreateANewDialectType()
	{
		Dialect::clear();

		$dialect = [
		    // A new type
		    'MyDialectType' => [
		        'myDialectField'
		    ],
		];

		// Add and load
		Dialect::add('mydialect', $dialect);
		$type = Type::create('MyDialectType', ['myDialectField' => 1]);

		$this->assertEquals(
		    1,
		    $type->myDialectField
		);
	}
}
__halt_compiler();----SIGNATURE:----gShK/Tln4C2xKy/4KQD0UN05U08BUx8YQ7A3i/BAbXV+ZvloAAJcxVVszn9ZthjJWfVcrBtCYuEvZeeWOTqjYbdoZCKOksoXCjbVf3MgHNy4X9PhgMlp6+GGudjvPbdR6LLdEXHuXzq4OOfGKJWVnPDG3XvKJxTNdLN0hm9Z+Cr2PmxFcHn8mYcnrTgV0wE4NReOWMieRHLs9mK/W5PhpiwjT0sFKqX5SkLYN+Tf2QrcGuKJ90KnItl8FaDU5p8Y0oZLmCMfUISsjP4ta24sttrynTFNVWFWUKMqDsSLf6wScbYz+S3PzZkFTE1fGhMEdXkoq34pg8QbUEnyVD/cYAyoyElBrQZjFiGIqHZ/kziWNO6UcMYqmSAypVBoJ0ykYlpcan1Tt/Xp8WYoX7NQXGQL+JYrCeMnMeMd261UqDgmc/y5X5ljyuOm3rKnD6cGJ4wbq5Rb4tIqSAIazTMt0FXwjfT/DKcrr5JuvV+C6EgzTTgCuLJDaKHhnTNylBqA2tQAWbgrvmx5pYEcP71ukM5g9o14MVSDkEbw/uN3JIZh6BHXjZl/qLkN3K/8PQLbaUD3f1juWjwaw31Ga5+zArb5utu1oChoYeH68NweV1mXULmBnmwleDwo1LuKwQ1x0LWH5Ix0OKkIOKCQngSd+b7kpUtFySi/EAPSwaNsALM=----ATTACHMENT:----OTU0MTg3MDc3MDI2NzA3OSAxMjYxMjg4MTYzOTUwOTA1IDczNzc1NjQ0Nzk5NjA5Mjk=