package org.codehaus.plexus.component.composition;

/*
 * Copyright 2001-2006 Codehaus Foundation.
 *
 * Licensed 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.
 */

import junit.framework.TestCase;
import org.codehaus.plexus.component.repository.ComponentDescriptor;
import org.codehaus.plexus.component.repository.io.PlexusTools;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;

import java.util.List;

/**
 *
 *
 * @author Jason van Zyl
 *
 * @version $Id: AbstractCompositionResolverTest.java 8155 2009-04-26 01:22:53Z jvanzyl $
 */
public abstract class AbstractCompositionResolverTest
    extends TestCase           
{

    /**
     *
     * @return
     */
    protected abstract CompositionResolver getCompositionResolver();


    // ------------------------------------------------------------------------
    //
    //     +-------+           +-------+
    //     |  c1   | --------> |  c2   |
    //     +-------+           +-------+
    //         |
    //         |
    //         V
    //     +-------+
    //     |  c3   |
    //     +-------+
    //
    // ------------------------------------------------------------------------
    public void testSimpleComponentResolution()
        throws Exception
    {
        String cc1 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c1</role>" +
            "  <requirements>" +
            "    <requirement>" +
            "      <role>c2</role>" +
            "   </requirement>" +
            "    <requirement>" +
            "      <role>c3</role>" +
            "   </requirement>" +
            "  </requirements>" +
            "</component>";

        String cc2 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c2</role>" +
            "</component>";

        String cc3 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c3</role>" +
            "</component>";

        ClassWorld classWorld = new ClassWorld( "test", Thread.currentThread().getContextClassLoader() );
        ClassRealm realm = classWorld.getRealm( "test" );

        CompositionResolver compositionResolver = getCompositionResolver();

        ComponentDescriptor<?> c1 = PlexusTools.buildComponentDescriptor( cc1, realm );

        ComponentDescriptor<?> c2 = PlexusTools.buildComponentDescriptor( cc2, realm );

        ComponentDescriptor<?> c3 = PlexusTools.buildComponentDescriptor( cc3, realm );

        compositionResolver.addComponentDescriptor( c1 );

        compositionResolver.addComponentDescriptor( c2 );

        compositionResolver.addComponentDescriptor( c3 );

        List dependencies = compositionResolver.getRequirements( c1.getRole(), c1.getRoleHint() );

        assertEquals( 2, dependencies.size() );

        assertTrue( dependencies.contains( c2.getRole() + CompositionResolver.SEPARATOR_CHAR + c2.getRoleHint() ) );

        assertTrue( dependencies.contains( c3.getRole() + CompositionResolver.SEPARATOR_CHAR + c2.getRoleHint() ) );

        assertEquals( 2, dependencies.size() );
    }

    // ------------------------------------------------------------------------
    //
    //     +-------+           +-------+
    //     |  c1   | --------> |  c2   |
    //     +-------+           +-------+
    //         |
    //         |
    //         V
    //     +-------+           +-------+
    //     |  c3   | --------> |  c4   |
    //     +-------+           +-------+
    //         |
    //         |
    //         V
    //     +-------+
    //     |  c5   |
    //     +-------+
    //
    // ------------------------------------------------------------------------
    public void testComplexComponentResolution()
        throws Exception
    {
        String cc1 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c1</role>" +
            "  <requirements>" +
            "    <requirement>" +
            "      <role>c2</role>" +
            "   </requirement>" +
            "   <requirement>" +
            "      <role>c3</role>" +
            "   </requirement>" +
            "  </requirements>" +
            "</component>";

        String cc2 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c2</role>" +
            "</component>";

        String cc3 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c3</role>" +
            "  <requirements>" +
            "    <requirement>" +
            "      <role>c4</role>" +
            "   </requirement>" +
            "    <requirement>" +
            "      <role>c5</role>" +
            "   </requirement>" +
            "  </requirements>" +
            "</component>";

        String cc4 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c4</role>" +
            "</component>";

        String cc5 =
            "<component>" +
            "  <implementation>java.lang.String</implementation>" +
            "  <role>c5</role>" +
            "</component>";

        ClassWorld classWorld = new ClassWorld( "test", Thread.currentThread().getContextClassLoader() );
        ClassRealm realm = classWorld.getRealm( "test" );

        CompositionResolver compositionResolver = getCompositionResolver();

        ComponentDescriptor<?> c1 = PlexusTools.buildComponentDescriptor( cc1, realm );

        ComponentDescriptor<?> c2 = PlexusTools.buildComponentDescriptor( cc2, realm );

        ComponentDescriptor<?> c3 = PlexusTools.buildComponentDescriptor( cc3, realm );

        ComponentDescriptor<?> c4 = PlexusTools.buildComponentDescriptor( cc4, realm );

        ComponentDescriptor<?> c5 = PlexusTools.buildComponentDescriptor( cc5, realm );

        compositionResolver.addComponentDescriptor( c1 );

        compositionResolver.addComponentDescriptor( c2 );

        compositionResolver.addComponentDescriptor( c3 );

        compositionResolver.addComponentDescriptor( c4 );

        compositionResolver.addComponentDescriptor( c5 );

        List dependencies = compositionResolver.getRequirements( c1.getRole(), c1.getRoleHint() );

        assertEquals( 2, dependencies.size() );

        // I just leave this at the moment as I am just 99% sure that this is not needed and not
        // correct. compositionResolver.getComponentDependencies() should return only direct dependencies
        //
        // I will need to add a method like getSortedComponents()
        // which will do topological sort of DAG and return list of ordered component which can be used
        // by ComponentComposer.
        // Possibility of checking if there are cycles probably also must be exposed in API (DAG has it alredy)
        // and it should be used
        // I can implement cycle detecting from single node (source) as after adding new component
        // we don't have to probably check entire graph but we will probably have to check
        // if there are cycles.

        /**
        // c5 must come before c3
        assertTrue( dependencies.indexOf( "c5" ) < dependencies.indexOf( "c3" ) );

        // c4 must come before c3
        assertTrue( dependencies.indexOf( "c4" ) < dependencies.indexOf( "c3" ) );
        */
    }
}
