/*
 * 
 * The Seasar Software License, Version 1.1
 *
 * Copyright (c) 2003-2004 The Seasar Project. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or 
 * without modification, are permitted provided that the following 
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above 
 *    copyrightnotice, this list of conditions and the following 
 *    disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above 
 *    copyright notice, this list of conditions and the following 
 *    disclaimer in the documentation and/or other materials provided 
 *    with the distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:  
 *    "This product includes software developed by the 
 *    Seasar Project (http://www.seasar.org/)."
 *    Alternately, this acknowledgement may appear in the software
 *    itself, if and wherever such third-party acknowledgements 
 *    normally appear.
 *
 * 4. Neither the names "The Seasar Project" nor@the name of its
 *    contributors ay be used to endour or promote products derived 
 *    from this software without specific prior written permission of 
 *    the Seasar Project.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR 
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIESOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE SEASER@PROJECT 
 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
 * INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING 
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 
package org.seasar.groovy

import groovy.util.GroovyTestCase
import java.math.BigDecimal
import java.sql.Timestamp
import org.seasar.framework.aop.interceptors.TraceInterceptor
import org.seasar.framework.container.S2Container
import org.seasar.framework.container.ContainerConstants

class SeasarBuilderTest extends GroovyTestCase {

    void testArg() {
        container = new SeasarBuilder().container{
        	component(class:String, name:"one"){
        		arg("1")
        	}
            component(class:Integer, name:"integer1") {
                arg(1)
            }
            component(class:Integer, name:"integer2") {
                arg(ref:"one")
            }
            component(class:BigDecimalObject) {
                arg(new BigDecimal('123.5'))
            }
            component(class:TimestampObject) {
                ts = Timestamp.valueOf('2004-03-24 00:00:00.0')
                arg(ts)
            }
            component(class:Boolean, name:"bool"){
                true ? arg(true) : arg(false)
            }
        }

        assert 1 == container.getComponent("integer1")
        assert 1 == container.getComponent("integer2")
        assert 123.5 == container.getComponent(BigDecimalObject).value
        assert '2004-03-24 00:00:00.0' ==
            container.getComponent(TimestampObject).timestamp.toString()
        assert true == container.getComponent('bool')
    }

    void testAspect() {
        container = new SeasarBuilder().container{
            component(class:TraceInterceptor, name:"traceInterceptor")
            component(java.util.Date) {
                arg(0)
                aspect(pointcut:"getTime, hashCode", advice:"traceInterceptor")
            }
            component(java.util.ArrayList) {
                aspect(advice:"traceInterceptor")
            }
            component(AspectTarget){
            	aspect(pointcut:"run", advice: {invocation|
            		println "before run"
            		invocation.proceed()
            		println "after run"
            	})
            }
        }
        date = container.getComponent(java.util.Date)
        date.getTime()
        date.hashCode()
        date.toString()
        list = container.getComponent(java.util.List)
        list.size()
        target = container.getComponent(AspectTarget)
        target.run()
    }

    void testComponent() {
    	decimal = new BigDecimal('1')
    	obj     = new Object()

        container = new SeasarBuilder().container{
        	component(decimal)
        	component(obj:obj, name:"obj")
            component(java.util.ArrayList)
            component(class:java.util.HashMap, name:"aaa")
            component(class:Integer, name:"bbb") {
                arg{
                    component(String) {
                        arg('1')
                    }
                }
            }
            component(class:Integer, name:"ccc", instance:"prototype") {
                arg(1)
            }
            component(class:String, name:"ddd", binding:"none")
        }

        d = container.getComponentDef(container.getComponentDefSize() - 1)
                
        assert container.getComponent(java.util.List) != null
        assert container.getComponent("aaa") != null
        assert 1 == container.getComponent("bbb")
        assert !(container.getComponent("ccc") === container.getComponent("ccc"))
        assert ContainerConstants.AUTO_BINDING_NONE == d.getAutoBindingMode()
        assert decimal === container.getComponent(BigDecimal)
        assert 1 == container.getComponent(BigDecimal)
        assert obj === container.getComponent("obj")

		try{
	       	container = new SeasarBuilder().container { component(obj: null) }
	       	fail "should be trhwon SeasarBuilderException"
	    }catch(SeasarBuilderException e){
	    }
    }

    void testProp() {
        container = new SeasarBuilder().container{
            component(class:Integer, name:"zero") {
                arg(0)
            }
            component(class:java.util.Date, name:"time1") {
                prop(name:"time", value:0)
            }
            component(class:java.util.Date, name:"time2") {
                prop(name:"time", ref:"zero")
            }
        }

        assert new java.util.Date(0) == container.getComponent("time1")
        assert new java.util.Date(0) == container.getComponent("time2")
    }

    void testLifeCycle() {
        container = new SeasarBuilder().container{
            component(LifeCycleBean){
                init("initialize"){ arg("initialize") }
                init(ognl:"#self.prop = 'prop'")
                destroy("destroy"){ arg("destroy") }
            }
            component(DestroyableBean){
                destroy("destroy")
            }
        }
        container.init()
        lifecycle = container.getComponent(LifeCycleBean)
        destroyable = container.getComponent(DestroyableBean)

        assert lifecycle.initialized == "initialize"
        assert lifecycle.prop == "prop"
        assert lifecycle.destroyed == null
        assert destroyable.destroyed == null

        container.destroy()

        assert lifecycle.destroyed == "destroy"
        assert destroyable.destroyed
    }
    
    void testNamespace(){
	    builder = new SeasarBuilder()
	    
	    o1 = new Object()
   	    o2 = new Object()
	    
        root = builder.container(){
        }
        c1 = builder.container("c1"){
        	component(obj:o1, name:"obj")
        }
        c2 = builder.container("c2"){
        	component(obj:o2, name:"obj")
        }
        root.include(c1)
        root.include(c2)

        assert root.componentDefSize == 0
        assert c1.componentDefSize == 1
        assert c2.componentDefSize == 1
        assert o1 === root.getComponent("c1.obj")
        assert o2 === root.getComponent("c2.obj")
    }
    
    void testHello(){
        builder = new SeasarBuilder()
        container = builder.container(){
            component(Hello){
                prop(name: "message", value: "Hello, World.")
            }
        }
        h = container.getComponent(Hello)
        assert "Hello, World." == h.message
    }

    void testBuilder() {
        builder = new SeasarBuilder()
        assert builder.container() instanceof S2Container
        assert builder.components() instanceof S2Container

        try{
            builder.arg()
            fail("should be thrown SeasarBuilderException")
        }catch(SeasarBuilderException e){
        }
        try{
            builder.aspect(pointcut: "dummy")
            fail("should be thrown SeasarBuilderException")
        }catch(SeasarBuilderException e){
        }
        try{
            builder.component(name: "dummy")
            fail("should be thrown SeasarBuilderException")
        }catch(SeasarBuilderException e){
        }
        try{
            builder.init("dummy")
            fail("should be thrown SeasarBuilderException")
        }catch(SeasarBuilderException e){
        }
        try{
            builder.destroy("dummy")
            fail("should be thrown SeasarBuilderException")
        }catch(SeasarBuilderException e){
        }
        try{
            builder.include("app.dicon")
            fail("should be thrown SeasarBuilderException")
        }catch(SeasarBuilderException e){
        }
    }
    
    void testInclude(){
    	builder = new SeasarBuilder().components {
    		include('app.dicon')
    	}
    	assert builder.getComponent("app.object") != null
    }
}

class Hello{
	property String message = "Hello, good-bye."
	public String sayHello(){
		return message
	}
}

class AspectTarget {
	public run(){
	    println "running run"
	}
}

class LifeCycleBean {
    String initialized
    String prop
    String destroyed
    public initialize(String init){
        initialized = init
    }
    public destroy(String destroy){
        destroyed = destroy
    }
}

class DestroyableBean {
    Boolean destroyed
    public destroy() {
        this.destroyed = true
    }
}

class BigDecimalObject {
	BigDecimal value
	public BigDecimalObject(BigDecimal value){
		this.value = value
	}
}

class TimestampObject {
    Timestamp timestamp
    public TimestampObject(Timestamp ts){
        timestamp = ts
    }
}
