/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.myfaces.orchestra.conversation;

import org.apache.myfaces.orchestra.conversation.basic.LogConversationMessager;
import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
import org.apache.myfaces.orchestra.frameworkAdapter.local.LocalFrameworkAdapter;
import org.springframework.aop.scope.ScopedObject;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;

/**
 * Test various aspects of the conversation handling
 */
public class TestConversation extends AbstractDependencyInjectionSpringContextTests implements ConversationBindingListener
{
    protected String[] getConfigLocations()
    {
        return new String[]
            {
                "classpath:testApplicationContext.xml"
            };
    }


    private int valueBoundCount = 0;
    private int valueUnboundCount = 0;

    protected void onSetUp() throws Exception
    {
        super.onSetUp();

        LocalFrameworkAdapter frameworkAdapter = new LocalFrameworkAdapter();
        frameworkAdapter.setApplicationContext(applicationContext);
        frameworkAdapter.setConversationMessager(new LogConversationMessager());
        FrameworkAdapter.setCurrentInstance(frameworkAdapter);
    }

    public void testConversation() throws Exception
    {
        DummyBean.callback=this;
        final String BEAN_NAME = "dummyBean";

        // The Spring configuration for dummyBean does not explicitly set a conversation name,
        // so conversation-name = bean-name
        final String CONVERSATION_NAME = BEAN_NAME;

        valueBoundCount = 0;
        valueUnboundCount = 0;

        /* simple create test */
        DummyBean bean = (DummyBean) applicationContext.getBean(BEAN_NAME);

        assertTrue("should be a scoped object", bean instanceof ScopedObject);

        assertFalse("conversation should not have been started yet", ConversationManager.getInstance().hasConversation(CONVERSATION_NAME));
        assertEquals("value bound", 0, valueBoundCount);
        assertEquals("value unbound", 0, valueUnboundCount);
        bean.touch();
        assertEquals("value bound", 1, valueBoundCount);
        assertEquals("value unbound", 0, valueUnboundCount);
        assertTrue("conversation should have been started", ConversationManager.getInstance().hasConversation(CONVERSATION_NAME));

        /* check if correct conversation has been started */
        Conversation conversationHolder = bean.checkCurrentConversation();
        assertNotNull("current conversation", conversationHolder);
        assertEquals("conversation name", CONVERSATION_NAME, conversationHolder.getName());

        /* invalidate conversation */
        bean.invalidateSelf();

        assertFalse("conversation should not be running", ConversationManager.getInstance().hasConversation(CONVERSATION_NAME));
        assertTrue("conversation should be marked invalid", conversationHolder.isInvalid());
        assertEquals("value bound", 1, valueBoundCount);
        assertEquals("value unbound", 1, valueUnboundCount);

        bean.touch();
        assertTrue("conversation should have been started", ConversationManager.getInstance().hasConversation(CONVERSATION_NAME));
        assertEquals("value bound", 2, valueBoundCount);


        /* check if a new conversation bean has been created */
        bean.setData("check");

        bean.invalidateAndRestartSelf();

        assertEquals("value bound", 2, valueBoundCount);
        assertEquals("value unbound", 2, valueUnboundCount);

        assertTrue("conversation should still be running", ConversationManager.getInstance().hasConversation(CONVERSATION_NAME));

        DummyBean beanNew = (DummyBean) applicationContext.getBean(BEAN_NAME);

        assertNotNull("should have got a new conversation", beanNew);
        assertNull("the conversation is not new", bean.getData());

        beanNew.touch();

        assertEquals("value bound", 3, valueBoundCount);

        /* clear the whole conversation context */

        ConversationManager.getInstance().clearCurrentConversationContext();

        assertEquals("value unbound", 3, valueUnboundCount);
        assertFalse("conversation should not be running", ConversationManager.getInstance().hasConversation(CONVERSATION_NAME));
    }

    public void valueBound(ConversationBindingEvent event)
    {
        valueBoundCount++;
    }

    public void valueUnbound(ConversationBindingEvent event)
    {
        valueUnboundCount++;
    }
}
