<?php

class WactConfigRegistryTestBasicComponent {
}

class WactConfigRegistryTestCompoundComponent {

    public $param;
    
    function __construct(WactConfigRegistryTestBasicComponent $param) {
        $this->param = $param;
    }
    
}

class WactConfigRegistryTestMixedRequiredAndOptionalParameters {

    public $param1;
    public $param2;
    
    function __construct(WactConfigRegistryTestBasicComponent $param1, $param2 = "default") {
        $this->param1 = $param1;
        $this->param2 = $param2;
    }
    
}

class WactConfigRegistryTestNoConstructor {
}

class WactConfigRegistryTestConstructorDocBlock {
    
    public $param;

    /**
     * @param WactConfigRegistryTestBasicComponent $param The thing to inject
     */
    function __construct($param) {
        $this->param = $param;
    }
    
}


class WactConfigRegistryTestConstructorDocBlockMultipleTypes {
    
    public $param;

    /**
     * @param database_password | string $param The password to use for something or other
     */
    function __construct($param) {
        $this->param = $param;
    }
    
}

class WactConfigRegistryTestConstructorDocBlockOrder {
    
    public $param;

    /**
     * @param ThisTypeIsSelectedFirst $param
     */
    function __construct(WactConfigRegistryTestBasicComponent $param) {
        $this->param = $param;
    }
    
}

class WactConfigRegistryTestRegistryInjection {

    public $param;
    
    function __construct(Wact_Config_Registry $param) {
        $this->param = $param;
    }
    
}

class WactConfigRegistryTestExtension extends Wact_Config_Registry {

    function createFoo() {
        return 'bar';
    }
    
}


class WactConfigRegistryTestCase extends Wact_Test_Case {

    protected $registry;

    function setUp() {
        $this->registry = new Wact_Config_Registry();
    }
    
    function testCreatingClassWithNoConstructor() {
        $obj = $this->registry->createWactConfigRegistryTestNoConstructor();
        
        $this->assertIsa($obj, "WactConfigRegistryTestNoConstructor");
    }

    function testCreatingClassWithOneParameter() {
        $data = new WactConfigRegistryTestBasicComponent();
        $obj = $this->registry->createWactConfigRegistryTestCompoundComponent($data);
        
        $this->assertIsA($obj, "WactConfigRegistryTestCompoundComponent");
        $this->assertIdentical($obj->param, $data);
    }

    function testCreatingClassWithInjectingParameter() {
        $obj = $this->registry->createWactConfigRegistryTestCompoundComponent();
        
        $this->assertIsA($obj, "WactConfigRegistryTestCompoundComponent");
        $this->assertIsA($obj->param, "WactConfigRegistryTestBasicComponent");
    }

    function testCreatingUnProvidableClass() {
        $this->expectException('Wact_Config_Exception');

        $obj = $this->registry->createWactConfigRegistryTestUnProvidableClass();
    }

    function testCreatingClassWithMixedRequiredAndOptionalParameters() {
        $obj = $this->registry->createWactConfigRegistryTestMixedRequiredAndOptionalParameters();
        
        $this->assertIsA($obj, "WactConfigRegistryTestMixedRequiredAndOptionalParameters");
        $this->assertIsA($obj->param1, "WactConfigRegistryTestBasicComponent");
        $this->assertEqual($obj->param2, "default");
    }
    
    function testFetchingNewSingleton() {
        $obj1 = $this->registry->WactConfigRegistryTestCompoundComponent;
        $obj2 = $this->registry->WactConfigRegistryTestCompoundComponent;

        $this->assertIsA($obj1, "WactConfigRegistryTestCompoundComponent");
        $this->assertIsA($obj2, "WactConfigRegistryTestCompoundComponent");

        $this->assertIdentical($obj1, $obj2);
    }
    
    function testSettingAndFetchingSingleton() {
        $obj = new WactConfigRegistryTestBasicComponent();
        $this->registry->foo = $obj;
        
        $this->assertIdentical($this->registry->foo, $obj);
    }
    
    function testInjectedParametersPreferSingletons() {
        $data = new WactConfigRegistryTestBasicComponent();
        $this->registry->WactConfigRegistryTestBasicComponent = $data;
        $obj = $this->registry->createWactConfigRegistryTestCompoundComponent();
        
        $this->assertIsA($obj, "WactConfigRegistryTestCompoundComponent");
        $this->assertIdentical($obj->param, $data);
    }

    function testCreatingClassWithInjectingParameterSpecifiedByDocComments() {
        $obj = $this->registry->createWactConfigRegistryTestConstructorDocBlock();
        
        $this->assertIsA($obj, "WactConfigRegistryTestConstructorDocBlock");
        $this->assertIsA($obj->param, "WactConfigRegistryTestBasicComponent");
    }

    function testCreatingClassWithInjectingParameterSpecifiedByDocComments2() {
        $this->registry->database_password = "secret";
        $obj = $this->registry->createWactConfigRegistryTestConstructorDocBlockMultipleTypes();

        $this->assertEqual($obj->param, "secret");
    }

    function testCreatingClassWithInjectingParameterSpecifiedByDocCommentsOverridingTypehint() {
        $specialObj = new WactConfigRegistryTestBasicComponent();
        $this->registry->ThisTypeIsSelectedFirst = $specialObj;
        $obj = $this->registry->createWactConfigRegistryTestConstructorDocBlockOrder();

        $this->assertIdentical($obj->param, $specialObj);
    }

    function testCreatingDefinedClass() {
        $this->registry->define('WactConfigRegistryTestNoConstructor')
            ->asClass('WactConfigRegistryTestNoConstructor');
        $obj = $this->registry->WactConfigRegistryTestNoConstructor;
        
        $this->assertIsa($obj, "WactConfigRegistryTestNoConstructor");
    }

    function testFactoryExistsReturnsFalseWhenNothingIsThere() {
        $this->assertFalse($this->registry->factoryExists('SingletonDoesNotExist'));
    }

    function testFactoryExistsReturnsTrueWhenFactoryIsDefined() {
        $this->registry->define('foo');
        $this->assertTrue($this->registry->factoryExists('foo'));
    }
    
    function testSingletonExistsReturnsFalseWhenNothingIsThere() {
        $this->assertFalse($this->registry->singletonExists('SingletonDoesNotExist'));
    }
    
    function testSingletonExistsReturnsTrueWhenSingletonIsSet() {
        $this->registry->key = 'test';
        $this->assertTrue($this->registry->singletonExists('key'));
    }

    function testIsDefinedReturnsFalseWhenNothingIsThere() {
        $this->assertFalse($this->registry->isDefined('SingletonDoesNotExist'));
    }

    function testIsDefinedReturnsTrueWhenFactoryIsDefined() {
        $this->registry->define('foo');
        $this->assertTrue($this->registry->isDefined('foo'));
    }
    
    function testIsDefinedReturnsTrueWhenSingletonIsSet() {
        $this->registry->key = 'test';
        $this->assertTrue($this->registry->isDefined('key'));
    }
    
    function testUnsetIsNotAllowed() {
        $this->expectException('Wact_Config_Exception');

        $this->registry->key = 'test';
        unset($this->registry->key);
    }

    function testSingletonReplacementNotAllowed() {
        $this->expectException('Wact_Config_Exception');
        
        $this->registry->key = 'test';
        $this->registry->key = 'somethingelse';
    }
    
    function testInjectingRegistryAsParameter() {
        $obj = $this->registry->createWactConfigRegistryTestRegistryInjection();
        $this->assertIdentical($obj->param, $this->registry);
    }
    
    function testIfSetOrFindsExistingSingleton() {
        $this->registry->key = 'test';
        $this->assertEqual($this->registry->ifsetor('key', FALSE), 'test');
    }

    function testIfSetOrReturnsDefaultWhenNotFound() {
        $this->assertEqual($this->registry->ifsetor('key', 'bar'), 'bar');
    }
    
}

class WactConfigRegistryFallbackTestCase extends WactConfigRegistryTestCase {

    protected $fallback;

    function setUp() {
        $this->fallback = new Wact_Config_Registry();
        $this->registry = new Wact_Config_Registry($this->fallback);
    }
    
    function testFetchingFallbackSingleton() {
        $this->fallback->key = 'test';
        $this->assertEqual($this->registry->key, 'test');
    }
    
    function testFetchingOverridenSingleton() {
        $this->fallback->key = 'fallback-test';
        $this->registry->key = 'test';
        $this->assertEqual($this->registry->key, 'test');
    }
    
    function testSingletonExistsWorksWithFallback() {
        $this->fallback->key = 'test';
        $this->assertTrue($this->registry->singletonExists('key'));
    }
    
    function testSingletonCreationOccursInContext() {
        $obj1 = $this->registry->WactConfigRegistryTestCompoundComponent;
        $this->assertNotNull($obj1);
        $this->assertFalse($this->fallback->singletonExists('WactConfigRegistryTestCompoundComponent'));
    }
    
    function testFactoryDefinedOnParentInjectsFromCorrectContext() {
        $regobj = new WactConfigRegistryTestBasicComponent();
        $fallbackobj = new WactConfigRegistryTestBasicComponent();
        $this->fallback->define('WactConfigRegistryTestCompoundComponent')
            ->asClass('WactConfigRegistryTestCompoundComponent');
        $this->fallback->WactConfigRegistryTestBasicComponent = $fallbackobj;
        $this->registry->WactConfigRegistryTestBasicComponent = $regobj;
        $obj = $this->registry->createWactConfigRegistryTestCompoundComponent();
        $this->assertIdentical($obj->param, $regobj);
    }
}

class WactConfigRegistryExtensionTestCase extends Wact_Test_Case {

    protected $registry;

    function setUp() {
        $this->registry = new WactConfigRegistryTestExtension();
    }
    
    function testConcreteFactoryMethodIsCalled() {
        $this->assertEqual($this->registry->create('Foo'), 'bar');
    }
}

?>