/*
 * Copyright (c) 2009, Tony Kohar. All Rights Reserved.
 *
 * 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. 
 */
package org.qi4j.envisage.tree;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.MutableTreeNode;
import org.qi4j.tools.model.descriptor.*;
import org.qi4j.tools.model.util.DescriptorNameComparator;

/**
 * Helper class to build tree model for Qi4J model as Structure Tree
 */
/* package */ final class StructureModelBuilder
{
    private final DescriptorNameComparator<Object> nameComparator = new DescriptorNameComparator<>();
    private final List<Object> tempList = new ArrayList<>();   // used for sorting

    /* package */ static MutableTreeNode build( ApplicationDetailDescriptor descriptor )
    {
        StructureModelBuilder builder = new StructureModelBuilder();
        return builder.buildApplicationNode( descriptor );
    }

    private MutableTreeNode buildApplicationNode( ApplicationDetailDescriptor descriptor )
    {
        DefaultMutableTreeNode node = new DefaultMutableTreeNode( descriptor );
        buildLayersNode( node, descriptor.layers() );
        return node;
    }

    private void buildLayersNode( DefaultMutableTreeNode parent, Iterable<LayerDetailDescriptor> iter )
    {
        for( LayerDetailDescriptor descriptor : iter )
        {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode( descriptor );
            buildModulesNode( node, descriptor.modules() );
            parent.add( node );
        }
    }

    private void buildModulesNode( DefaultMutableTreeNode parent, Iterable<ModuleDetailDescriptor> iter )
    {
        for( ModuleDetailDescriptor descriptor : iter )
        {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode( descriptor );
            buildServicesNode( node, descriptor.services() );
            buildImportedServicesNode( node, descriptor.importedServices() );
            buildEntitiesNode( node, descriptor.entities() );
            buildTransientsNode( node, descriptor.transients() );
            buildValuesNode( node, descriptor.values() );
            buildObjectsNode( node, descriptor.objects() );
            parent.add( node );
        }
    }

    private void addTypeChildren( DefaultMutableTreeNode parent, List<Object> childList )
    {
        Collections.sort( childList, nameComparator );

        for( int i = 0; i < childList.size(); i++ )
        {
            DefaultMutableTreeNode node = new DefaultMutableTreeNode( childList.get( i ) );
            parent.add( node );
        }
    }

    private void buildServicesNode( DefaultMutableTreeNode parent, Iterable<ServiceDetailDescriptor> iter )
    {
        tempList.clear();
        for( ServiceDetailDescriptor descriptor : iter )
        {
            tempList.add( descriptor );
        }

        addTypeChildren( parent, tempList );
    }

    private void buildImportedServicesNode( DefaultMutableTreeNode parent,
                                            Iterable<ImportedServiceDetailDescriptor> iter
    )
    {
        tempList.clear();
        for( ImportedServiceDetailDescriptor descriptor : iter )
        {
            tempList.add( descriptor );
        }

        addTypeChildren( parent, tempList );
    }

    private void buildEntitiesNode( DefaultMutableTreeNode parent, Iterable<EntityDetailDescriptor> iter )
    {
        tempList.clear();
        for( EntityDetailDescriptor descriptor : iter )
        {
            tempList.add( descriptor );
        }

        addTypeChildren( parent, tempList );
    }

    private void buildTransientsNode( DefaultMutableTreeNode parent, Iterable<TransientDetailDescriptor> iter )
    {
        tempList.clear();
        for( TransientDetailDescriptor descriptor : iter )
        {
            tempList.add( descriptor );
        }

        addTypeChildren( parent, tempList );
    }

    private void buildValuesNode( DefaultMutableTreeNode parent, Iterable<ValueDetailDescriptor> iter )
    {
        tempList.clear();
        for( ValueDetailDescriptor descriptor : iter )
        {
            tempList.add( descriptor );
        }

        addTypeChildren( parent, tempList );
    }

    private void buildObjectsNode( DefaultMutableTreeNode parent, Iterable<ObjectDetailDescriptor> iter )
    {
        tempList.clear();
        for( ObjectDetailDescriptor descriptor : iter )
        {
            tempList.add( descriptor );
        }

        addTypeChildren( parent, tempList );
    }
}
