//   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 static org.junit.Assert.*;

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

import org.junit.Test;

/**
 *
 * @author Patrick Harms
 */
public class GUIModelTest {
    
    /**
     * 
     */
    private IGUIElementFactory guiElementFactory = new TestGUIElementFactory();

    /**
     * 
     */
    @Test
    public void test_PathIntegration_01() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        
        IGUIElement element = model.integratePath(guiElementPath, guiElementFactory);
        
        assertTrue(element instanceof TestGUIElement);
        assertEquals(guiElementPath.get(0), element.getSpecification());
        assertNull(element.getParent());
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        assertEquals(element, model.getRootElements().get(0));
        
        assertNotNull(model.getChildren(element));
        assertTrue(model.getChildren(element).isEmpty());
        
        assertNull(model.getParent(element));
    }

    /**
     * 
     */
    @Test
    public void test_PathIntegration_02() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        for (int i = 0; i < 5; i++) {
            guiElementPath.add(new TestGUIElementSpec("guiElem" + i));
        }
        
        IGUIElement element = model.integratePath(guiElementPath, guiElementFactory);
        
        for (int i = 4; i >= 0; i--) {
            assertTrue(element instanceof TestGUIElement);
            assertEquals(guiElementPath.get(i), element.getSpecification());
            
            assertNotNull(model.getChildren(element));
            
            if (i == 4) {
                assertTrue(model.getChildren(element).isEmpty());
            }
            else {
                assertEquals(1, model.getChildren(element).size());
                assertEquals(guiElementPath.get(i + 1),
                             model.getChildren(element).get(0).getSpecification());
            }
            
            element = element.getParent();
        }
        
        assertNull(element);

        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        assertNotNull(model.getRootElements().get(0));
        assertEquals(guiElementPath.get(0), model.getRootElements().get(0).getSpecification());
    }

    /**
     * 
     */
    @Test
    public void test_PathIntegration_03() throws Exception {
        GUIModel model = new GUIModel();
        
        for (int i = 0; i < 20; i++) {
            List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
            
            for (int j = 0; j < 5; j++) {
                guiElementPath.add(new TestGUIElementSpec("guiElem_" + i + "_" + j));
            }
            
            IGUIElement element = model.integratePath(guiElementPath, guiElementFactory);
            
            for (int j = 4; j >= 0; j--) {
                assertTrue(element instanceof TestGUIElement);
                assertEquals(guiElementPath.get(j), element.getSpecification());
                
                assertNotNull(model.getChildren(element));
                
                if (j == 4) {
                    assertTrue(model.getChildren(element).isEmpty());
                }
                else {
                    assertEquals(1, model.getChildren(element).size());
                    assertEquals(guiElementPath.get(j + 1),
                                 model.getChildren(element).get(0).getSpecification());
                }
                
                element = element.getParent();
            }
            
            assertNull(element);

        }
        
        assertNotNull(model.getRootElements());
        assertEquals(20, model.getRootElements().size());
    }

    /**
     * 
     */
    @Test
    public void test_PathIntegration_04() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        
        IGUIElement element1 = model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        
        IGUIElement element2 = model.integratePath(guiElementPath, guiElementFactory);
        
        assertSame(element1, element2);
    }

    /**
     * 
     */
    @Test
    public void test_PathIntegration_05() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        for (int i = 0; i < 5; i++) {
            guiElementPath.add(new TestGUIElementSpec("guiElem" + i));
        }
        
        IGUIElement element1 = model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath = new ArrayList<IGUIElementSpec>();
        for (int i = 0; i < 5; i++) {
            guiElementPath.add(new TestGUIElementSpec("guiElem" + i));
        }
        
        IGUIElement element2 = model.integratePath(guiElementPath, guiElementFactory);
        
        assertSame(element1, element2);
    }

    /**
     * 
     */
    @Test
    public void test_PathIntegration_06() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        IGUIElement element1 = model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        IGUIElement element2 = model.integratePath(guiElementPath, guiElementFactory);
        
        assertFalse(element1.equals(element2));
        
        element1 = element1.getParent();
        assertFalse(element1.equals(element2));
        
        element2 = element2.getParent();
        assertFalse(element1.equals(element2));
        
        element1 = element1.getParent();
        assertFalse(element1.equals(element2));
        
        element2 = element2.getParent();
        assertSame(element1, element2);
    }

    /**
     * 
     */
    @Test
    public void test_CondenseModel_01() throws Exception {
        GUIModel model = new GUIModel();
        
        for (int i = 0; i < 20; i++) {
            List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
            
            for (int j = 0; j < 5; j++) {
                guiElementPath.add(new TestGUIElementSpec("guiElem_" + i + "_" + j, "spec_" + j));
            }
            
            model.integratePath(guiElementPath, guiElementFactory);
        }
        
        assertNotNull(model.getRootElements());
        assertEquals(20, model.getRootElements().size());
        
        model.condenseModel();
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        IGUIElement element = model.getRootElements().get(0);
        
        for (int i = 0; i < 5; i++) {
            assertNotNull(element);
            assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
            assertTrue(((TestGUIElementSpec) element.getSpecification()).id.endsWith("_" + i));

            if (i < 4) {
                assertNotNull(model.getChildren(element));
                assertEquals(1, model.getChildren(element).size());
                element = model.getChildren(element).get(0);
            }
            else {
                assertNotNull(model.getChildren(element));
                assertEquals(0, model.getChildren(element).size());
            }
        }
    }

    /**
     * 
     */
    @Test
    public void test_CondenseModel_02() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        for (int j = 0; j < 3; j++) {
            guiElementPath.add(new TestGUIElementSpec("guiElem_" + j));
        }
        
        for (int i = 0; i < 20; i++) {
            for (int j = 3; j < 5; j++) {
                guiElementPath.add(new TestGUIElementSpec("guiElem_" + i + "_" + j, "spec_" + j));
            }
            
            model.integratePath(guiElementPath, guiElementFactory);
            
            for (int j = 3; j < 5; j++) {
                guiElementPath.remove(3);
            }
        }
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        IGUIElement element = model.getRootElements().get(0);
        
        for (int i = 0; i < 3; i++) {
            assertNotNull(element);
            assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
            assertEquals("guiElem_" + i, ((TestGUIElementSpec) element.getSpecification()).id);

            if (i < 2) {
                assertNotNull(model.getChildren(element));
                assertEquals(1, model.getChildren(element).size());
                element = model.getChildren(element).get(0);
            }
            else {
                assertNotNull(model.getChildren(element));
                assertEquals(20, model.getChildren(element).size());
            }
        }

        model.condenseModel();
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        element = model.getRootElements().get(0);
        
        for (int i = 0; i < 5; i++) {
            assertNotNull(element);
            assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
            assertTrue(((TestGUIElementSpec) element.getSpecification()).id.endsWith("_" + i));

            if (i < 4) {
                assertNotNull(model.getChildren(element));
                assertEquals(1, model.getChildren(element).size());
                element = model.getChildren(element).get(0);
            }
            else {
                assertNotNull(model.getChildren(element));
                assertEquals(0, model.getChildren(element).size());
            }
        }
    }

    /**
     * 
     */
    @Test
    public void test_GroupGUIElements_01() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(3);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem7"));
        guiElementPath.add(new TestGUIElementSpec("guiElem8"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem9"));
        guiElementPath.add(new TestGUIElementSpec("guiElem10"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        // the model created is
        // guiElem1
        //   |-- guiElem2
        //   |     |-- guiElem3
        //   |     |     \-- guiElem4
        //   |     |
        //   |     \-- guiElem5
        //   |           |-- guiElem6
        //   |           \-- guiElem7
        //   |                 \-- guiElem8
        //   \-- guiElem9
        //         \-- guiElem10
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        IGUIElement guiElem1 = model.getRootElements().get(0);
        
        assertEquals(2, model.getChildren(guiElem1).size());
        IGUIElement guiElem2 = model.getChildren(guiElem1).get(0);
        IGUIElement guiElem9 = model.getChildren(guiElem1).get(1);
        
        model.groupGUIElements(Arrays.asList(guiElem2, guiElem9), "newGroup");
        
        assertEquals(1, model.getChildren(guiElem1).size());
        IGUIElement group = model.getChildren(guiElem1).get(0);
        
        assertEquals(2, model.getChildren(group).size());
        assertEquals(guiElem2, model.getChildren(group).get(0));
        assertEquals(guiElem9, model.getChildren(group).get(1));
        
        assertEquals(group, guiElem2.getParent());
        assertEquals(group, guiElem9.getParent());
    }

    /**
     * 
     */
    @Test
    public void test_GroupGUIElements_02() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(3);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem7"));
        guiElementPath.add(new TestGUIElementSpec("guiElem8"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem9"));
        guiElementPath.add(new TestGUIElementSpec("guiElem10"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        // the model created is
        // guiElem1
        //   |-- guiElem2
        //   |     |-- guiElem3
        //   |     |     \-- guiElem4
        //   |     |
        //   |     \-- guiElem5
        //   |           |-- guiElem6
        //   |           \-- guiElem7
        //   |                 \-- guiElem8
        //   \-- guiElem9
        //         \-- guiElem10
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        IGUIElement guiElem1 = model.getRootElements().get(0);
        IGUIElement guiElem2 = model.getChildren(guiElem1).get(0);
        
        assertEquals(2, model.getChildren(guiElem2).size());
        IGUIElement guiElem3 = model.getChildren(guiElem2).get(0);
        IGUIElement guiElem5 = model.getChildren(guiElem2).get(1);
        
        model.groupGUIElements(Arrays.asList(guiElem3, guiElem5), "newGroup");
        
        assertEquals(1, model.getChildren(guiElem2).size());
        IGUIElement group = model.getChildren(guiElem2).get(0);
        
        assertEquals(2, model.getChildren(group).size());
        assertEquals(guiElem3, model.getChildren(group).get(0));
        assertEquals(guiElem5, model.getChildren(group).get(1));
        
        assertEquals(group, guiElem3.getParent());
        assertEquals(group, guiElem5.getParent());
    }

    /**
     * 
     */
    @Test
    public void test_GroupGUIElements_03() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(3);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem7"));
        guiElementPath.add(new TestGUIElementSpec("guiElem8"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem9"));
        guiElementPath.add(new TestGUIElementSpec("guiElem10"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        // the model created is
        // guiElem1
        //   |-- guiElem2
        //   |     |-- guiElem3
        //   |     |     \-- guiElem4
        //   |     |
        //   |     \-- guiElem5
        //   |           |-- guiElem6
        //   |           \-- guiElem7
        //   |                 \-- guiElem8
        //   \-- guiElem9
        //         \-- guiElem10
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        IGUIElement guiElem1 = model.getRootElements().get(0);
        IGUIElement guiElem2 = model.getChildren(guiElem1).get(0);
        IGUIElement guiElem3 = model.getChildren(guiElem2).get(0);
        
        assertEquals(1, model.getChildren(guiElem3).size());
        IGUIElement guiElem4 = model.getChildren(guiElem3).get(0);
        
        model.groupGUIElements(Arrays.asList(guiElem4), "newGroup");
        
        assertEquals(1, model.getChildren(guiElem3).size());
        IGUIElement group = model.getChildren(guiElem3).get(0);
        
        assertEquals(1, model.getChildren(group).size());
        assertEquals(guiElem4, model.getChildren(group).get(0));
        
        assertEquals(group, guiElem4.getParent());
    }

    /**
     * 
     */
    @Test(expected = java.lang.IllegalArgumentException.class)
    public void test_GroupGUIElements_04() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(3);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem7"));
        guiElementPath.add(new TestGUIElementSpec("guiElem8"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem9"));
        guiElementPath.add(new TestGUIElementSpec("guiElem10"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        // the model created is
        // guiElem1
        //   |-- guiElem2
        //   |     |-- guiElem3
        //   |     |     \-- guiElem4
        //   |     |
        //   |     \-- guiElem5
        //   |           |-- guiElem6
        //   |           \-- guiElem7
        //   |                 \-- guiElem8
        //   \-- guiElem9
        //         \-- guiElem10
        
        assertNotNull(model.getRootElements());
        assertEquals(1, model.getRootElements().size());
        
        IGUIElement guiElem1 = model.getRootElements().get(0);
        IGUIElement guiElem2 = model.getChildren(guiElem1).get(0);
        IGUIElement guiElem3 = model.getChildren(guiElem2).get(0);
        IGUIElement guiElem5 = model.getChildren(guiElem2).get(1);
        
        assertEquals(1, model.getChildren(guiElem3).size());
        IGUIElement guiElem4 = model.getChildren(guiElem3).get(0);
        
        assertEquals(2, model.getChildren(guiElem5).size());
        IGUIElement guiElem6 = model.getChildren(guiElem5).get(0);

        model.groupGUIElements(Arrays.asList(guiElem4, guiElem6), "newGroup");
    }

    /**
     * 
     */
    @Test
    public void test_Traverser_01() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(3);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem7"));
        guiElementPath.add(new TestGUIElementSpec("guiElem8"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem9"));
        guiElementPath.add(new TestGUIElementSpec("guiElem10"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        // the model created is
        // guiElem1
        //   |-- guiElem2
        //   |     |-- guiElem3
        //   |     |     \-- guiElem4
        //   |     |
        //   |     \-- guiElem5
        //   |           |-- guiElem6
        //   |           \-- guiElem7
        //   |                 \-- guiElem8
        //   \-- guiElem9
        //         \-- guiElem10
        
        GUIModel.Traverser traverser = model.getTraverser();
        assertNotNull(traverser);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.parent());
        
        // guiElem1
        IGUIElement element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem1", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem2
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem2", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem3
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem3", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem4
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem4", ((TestGUIElementSpec) element.getSpecification()).id);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());

        // guiElem3
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem3", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem5
        element = traverser.nextSibling();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem5", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem6
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem6", ((TestGUIElementSpec) element.getSpecification()).id);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem7
        element = traverser.nextSibling();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem7", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem8
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem8", ((TestGUIElementSpec) element.getSpecification()).id);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem7
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem7", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem5
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem5", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem2
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem2", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem9
        element = traverser.nextSibling();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem9", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem10
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem10", ((TestGUIElementSpec) element.getSpecification()).id);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem9
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem9", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem1
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem1", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        assertNull(traverser.parent());
    }

    /**
     * 
     */
    @Test
    public void test_Traverser_02() throws Exception {
        GUIModel model = new GUIModel();
        
        List<IGUIElementSpec> guiElementPath = new ArrayList<IGUIElementSpec>();
        guiElementPath.add(new TestGUIElementSpec("guiElem1"));
        guiElementPath.add(new TestGUIElementSpec("guiElem2"));
        guiElementPath.add(new TestGUIElementSpec("guiElem3"));
        guiElementPath.add(new TestGUIElementSpec("guiElem4"));
        
        model.integratePath(guiElementPath, guiElementFactory);

        guiElementPath.remove(2);
        guiElementPath.remove(2);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem5"));
        guiElementPath.add(new TestGUIElementSpec("guiElem6"));

        IGUIElement target = model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(3);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem7"));
        guiElementPath.add(new TestGUIElementSpec("guiElem8"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        guiElementPath.remove(1);
        
        guiElementPath.add(new TestGUIElementSpec("guiElem9"));
        guiElementPath.add(new TestGUIElementSpec("guiElem10"));

        model.integratePath(guiElementPath, guiElementFactory);
        
        // the model created is
        // guiElem1
        //   |-- guiElem2
        //   |     |-- guiElem3
        //   |     |     \-- guiElem4
        //   |     |
        //   |     \-- guiElem5
        //   |           |-- guiElem6
        //   |           \-- guiElem7
        //   |                 \-- guiElem8
        //   \-- guiElem9
        //         \-- guiElem10
        
        GUIModel.Traverser traverser = model.getTraverser(target);
        assertNotNull(traverser);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem7
        IGUIElement element = traverser.nextSibling();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem7", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem8
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem8", ((TestGUIElementSpec) element.getSpecification()).id);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem7
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem7", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem5
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem5", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem2
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem2", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertTrue(traverser.hasNextSibling());
        
        // guiElem9
        element = traverser.nextSibling();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem9", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem10
        element = traverser.firstChild();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem10", ((TestGUIElementSpec) element.getSpecification()).id);
        assertFalse(traverser.hasFirstChild());
        assertNull(traverser.firstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem9
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem9", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        // guiElem1
        element = traverser.parent();
        assertNotNull(element);
        assertTrue(element.getSpecification() instanceof TestGUIElementSpec);
        assertEquals("guiElem1", ((TestGUIElementSpec) element.getSpecification()).id);
        assertTrue(traverser.hasFirstChild());
        assertFalse(traverser.hasNextSibling());
        assertNull(traverser.nextSibling());
        
        assertNull(traverser.parent());
    }

    /**
     *
     * @author Patrick Harms
     */
    private class TestGUIElementFactory implements IGUIElementFactory {

        /* (non-Javadoc)
         * @see IGUIElementFactory#instantiateGUIElement(IGUIElementSpec, IGUIElement)
         */
        @Override
        public IGUIElement instantiateGUIElement(IGUIElementSpec specification, IGUIElement parent)
            throws GUIModelConfigurationException
        {
            assertTrue(specification instanceof TestGUIElementSpec);
            
            return new TestGUIElement((TestGUIElementSpec) specification, parent);
        }

    }

    /**
     *
     * @author Patrick Harms
     */
    private class TestGUIElementSpec implements IGUIElementSpec {

        /**  */
        private static final long serialVersionUID = 1L;
        
        /** */
        private String id;

        /** */
        private String similarityId;

        /**
         *
         */
        public TestGUIElementSpec(String id) {
            this(id, "");
        }

        /**
         *
         */
        public TestGUIElementSpec(String id, String similarityId) {
            this.id = id;
            this.similarityId = similarityId;
            assertNotNull(id);
            assertNotNull(similarityId);
        }

        /* (non-Javadoc)
         * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getType()
         */
        @Override
        public String getType() {
            return "TestGUIElement";
        }

        /* (non-Javadoc)
         * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec#getTypeHierarchy()
         */
        @Override
        public String[] getTypeHierarchy() {
            return new String[] { "TestGUIElement" };
        }

        /* (non-Javadoc)
         * @see IGUIElementSpec#getSimilarity(IGUIElementSpec)
         */
        @Override
        public boolean getSimilarity(IGUIElementSpec other) {
            return (other instanceof TestGUIElementSpec ?
                ((TestGUIElementSpec) other).similarityId.equals(similarityId) : false);
        }

        /* (non-Javadoc)
         * @see java.lang.Object#equals(java.lang.Object)
         */
        @Override
        public boolean equals(Object other) {
            return (other instanceof TestGUIElementSpec ?
                ((TestGUIElementSpec) other).id.equals(id) : false);
        }

    }

    /**
     *
     * @author Patrick Harms
     */
    public class TestGUIElement extends AbstractDefaultGUIElement implements IGUIElement {

        /**  */
        private static final long serialVersionUID = 1L;

        /**
         *
         */
        public TestGUIElement(TestGUIElementSpec specification, IGUIElement parent) {
            super(specification, parent);
        }

        /* (non-Javadoc)
         * @see de.ugoe.cs.autoquest.eventcore.IEventTarget#getPlatform()
         */
        @Override
        public String getPlatform() {
            return "TEST";
        }

        /* (non-Javadoc)
         * @see de.ugoe.cs.autoquest.eventcore.IEventTarget#getStringIdentifier()
         */
        @Override
        public String getStringIdentifier() {
            return ((TestGUIElementSpec) super.getSpecification()).id;
        }

        /* (non-Javadoc)
         * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#updateSpecification(de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElementSpec)
         */
        @Override
        public void updateSpecification(IGUIElementSpec furtherSpec) {
            // do nothing
        }

        /* (non-Javadoc)
         * @see de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement#getDistanceTo(IGUIElement)
         */
        @Override
        public double getDistanceTo(IGUIElement otherElement) {
            if (this == otherElement) {
                return 0.0;
            }
            else {
                return 1.0;
            }
        }

    }

}
