//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   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 de.ugoe.cs.autoquest.eventcore.guimodel;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * convenience methods for working with GUI elements. E.g. to determine, if two GUI elements have a
 * common parent on their parent hierarchies.
 * </p>
 * 
 * @author Patrick Harms, Ralph Krimmel
 */
public class GUIModelHelpers {

    /**
     * <p>
     * return a common denominator for the provided list of GUI elements, i.e. a GUI element, that
     * is part of the parent GUI hiearchy of all GUI elements in the list. If there is no common
     * denominator, the method returns null.
     * </p>
     * 
     * @param guiElements the GUI elements to get the common denominator of
     */
    public static IGUIElement getCommonDenominator(IGUIElement... guiElements) {
        IGUIElement commonDenominator = null;

        if (guiElements.length > 0) {
            List<IGUIElement> commonDenominatorPath = new ArrayList<IGUIElement>();

            // create a reference list using the first GUI element
            IGUIElement guiElement = guiElements[0];
            while (guiElement != null) {
                commonDenominatorPath.add(0, guiElement);
                guiElement = guiElement.getParent();
            }

            if (commonDenominatorPath.size() == 0) {
                return null;
            }

            // for each other GUI element, check the reference list for the first element in the
            // path, that is not common to the current one, and delete it as well as it subsequent
            // siblings
            List<IGUIElement> currentPath = new ArrayList<IGUIElement>();
            for (int i = 1; i < guiElements.length; i++) {
                currentPath.clear();
                guiElement = guiElements[i];
                while (guiElement != null) {
                    currentPath.add(0, guiElement);
                    guiElement = guiElement.getParent();
                }

                // determine the index of the first unequal path element
                int index = 0;
                while ((index < commonDenominatorPath.size()) && (index < currentPath.size()) &&
                        commonDenominatorPath.get(index).equals(currentPath.get(index)))
                {
                    index++;
                }

                // remove all elements from the common denonimator path, that do
                // not match
                while (index < commonDenominatorPath.size()) {
                    commonDenominatorPath.remove(index);
                }
            }

            if (commonDenominatorPath.size() > 0) {
                commonDenominator = commonDenominatorPath.get(commonDenominatorPath.size() - 1);
            }
        }
        
        return commonDenominator;
    }

    /**
     * <p>
     * determines the number of hops through the GUI element hierarchy to get from one GUI element
     * to another.
     * </p>
     *
     * @param first  the first GUI element, i.e., the start in the hierarchy
     * @param second the second GUI element, i.e., the end in the hierarchy
     * 
     * @return the number of required hops to get from the first GUI element to the second,
     *         INTEGER.MAX_INT if the GUI elements do not share a common parent
     */
    public static int getDistance(IGUIElement first, IGUIElement second) {
        int hopcount = 0;
        
        IGUIElement commonDenominator = getCommonDenominator(first, second);

        while (!(first.equals(commonDenominator))) {
            first = first.getParent();
            hopcount++;
        }

        while (!(second.equals(commonDenominator))) {
            second = second.getParent();
            hopcount++;
        }

        return hopcount;
    }

}
