/*-------------------------------------------------------------------------------
Copyright (c)2000 TogetherSoft Corporation. Patents pending. All rights reserved.
-------------------------------------------------------------------------------*/

package com.togethersoft.modules.showdependencies;

import com.togethersoft.openapi.rwi.*;
import com.togethersoft.openapi.sci.*;
import com.togethersoft.openapi.sci.enum.*;
import com.togethersoft.openapi.ide.message.IdeMessageManagerAccess;
import com.togethersoft.openapi.ide.message.IdeMessageManager;
import com.togethersoft.openapi.ide.message.IdeMessagePage;
import com.togethersoft.openapi.ide.message.IdeMessageView;
import com.togethersoft.openapi.ide.message.IdeMessageType;
import com.togethersoft.openapi.ide.diagram.IdeDiagramManager;
import com.togethersoft.openapi.ide.diagram.IdeDiagramManagerAccess;
import com.togethersoft.openapi.ide.diagram.IdeDiagram;
import com.togethersoft.openapi.ide.progress.IdeProgressIndicatorAccess;
import com.togethersoft.openapi.ide.progress.IdeProgressIndicator;
import com.togethersoft.openapi.ide.progress.IdeProgress;

import java.util.Vector;

/**
 * Analyzes a dependency between two packages
 *
 * @author TogetherSoft
 */
class PackagesAnalyzer
{
     /**
      * Returns a Vector containing Dependency objects.
      *
      * @param sourceDiagram the RwiDiagram - source of the dependency link
      * @param destDiagram the RwiDiagram - destination of the dependency link
      */
    public Vector analyze(RwiDiagram sourceDiagram, RwiDiagram destDiagram, boolean inDeclarationsOnly)
    {
        // in RWI a package is represented by RwiDiagram in class diagrams
        RwiPackage rwiSourcePackage = sourceDiagram.getContainingPackage();
        RwiPackage rwiDestPackage = destDiagram.getContainingPackage();

        // getting SciPackages, we will use them to work with the source code
        SciPackage sourcePackage = (SciPackage)rwiSourcePackage.getCodeElement();
        SciPackage destPackage = (SciPackage)rwiDestPackage.getCodeElement();

        Vector result = new Vector();

        // the dependent classes/interfaces, they are in the sourcePackage
        Vector victimClasses = new Vector();

        // printing information message
        IdeMessageManagerAccess.printMessage
            (IdeMessageType.INFORMATION, "DependencyExplorer module: collecting classes in the " +
            sourcePackage.getQualifiedName() + " ...");

        // collecting all dependent classes/interfaces
        getAllClasses(sourcePackage, victimClasses);

        // classes/interfaces causing the dependency
        Vector causeClasses = new Vector();

        // printing information message
        IdeMessageManagerAccess.printMessage
            (IdeMessageType.INFORMATION, "DependencyExplorer module: collecting classes in the " +
            destPackage.getQualifiedName() + " ...");

        getAllClasses(destPackage, causeClasses);

        // analyzes two SciClasses
        ClassesAnalyzer ca = new ClassesAnalyzer();
        int victims = victimClasses.size();
        int causes = causeClasses.size();

        // creating the progress indicator, see ScriptTutorial for an example
        IdeProgressIndicator progressIndicator = IdeProgressIndicatorAccess.getProgressIndicator();
        IdeProgress progress = progressIndicator.start("myID", true, victims * causes,
            "{3, number, percent} completed. Analyzing {2}");
        for (int i = 0; i < victims; i++)
        {
            for (int j = 0; j < causes; j++)
            {
                progress.setCount(i * causes + j);
                if ( SciLanguage.JAVA.equals(((SciClass)causeClasses.elementAt(j)).getLanguage()) &&
                      !(((SciClass)causeClasses.elementAt(j)).hasProperty(SciProperty.PUBLIC))) {
                    continue; //in Java, if we work with different packages, then parent class must be public
                }
                //we are working with dependency between packages
                progress.setStep(((SciClass)victimClasses.elementAt(i)).getQualifiedName() + " and " +
                    ((SciClass)causeClasses.elementAt(j)).getQualifiedName());
                if (progress.isCancelRequested())
                {
                    break;
                }
                //everything is okay, find and collect the Dependency objects into the vector
                Vector dependenciesBetweenTwoClasses =
                    ca.analyze((SciClass)victimClasses.elementAt(i), (SciClass)causeClasses.elementAt(j),
                    inDeclarationsOnly);
                // add to the previously collected objects    
                ca.joinVectors(result, dependenciesBetweenTwoClasses);
            }
        }
        progress.stop();
        return result;
    }

    /**
      * Populates the specified vector with all the clases from the specified package
      * @param p the SciPackage to work with
      * @param classes Vector where to add found SciClasses
      */
    private void getAllClasses(SciPackage pack, Vector classes)
    {
        SciClassEnumeration enum = pack.classes();
        while (enum.hasMoreElements())
        {
            SciClass nextSciClass = enum.nextSciClass();
            // adding inner classes
            SciClassEnumeration innerClasses = nextSciClass.innerClasses();
            while (innerClasses.hasMoreElements())
            {
                SciClass nextInnerClass = innerClasses.nextSciClass();
                if (nextInnerClass.hasProperty(SciProperty.PRIVATE))
                {
                    continue;
                }
                classes.addElement(nextInnerClass);
            }
            classes.addElement(nextSciClass);
        }
        SciPackageEnumeration subpackages = pack.subpackages();
        while (subpackages.hasMoreElements())
        {
            SciPackage nextSciPackage = subpackages.nextSciPackage();
            getAllClasses(nextSciPackage, classes);
        }
    }
}


