//   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.ui.swt;

import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import de.ugoe.cs.autoquest.eventcore.guimodel.GUIModel;
import de.ugoe.cs.autoquest.eventcore.guimodel.IGUIElement;
import de.ugoe.cs.util.console.Console;

import org.eclipse.swt.widgets.Label;

public class ShowGuiModelDialog extends Dialog {

    protected Shell shell;
    private Tree guiTree;

    protected GUIModel model;

    public ShowGuiModelDialog(Shell parent, int style, GUIModel model, String modelName) {
        super(parent, style);
        setText("GUI Model " + modelName);
        this.model = model;
    }

    public void open() {
        createContents();
        shell.open();
        shell.layout();
        Display display = getParent().getDisplay();
        while (!shell.isDisposed()) {
            if (!display.readAndDispatch()) {
                display.sleep();
            }
        }
    }

    private void createContents() {
        shell = new Shell(getParent(), SWT.SHELL_TRIM | SWT.BORDER | SWT.APPLICATION_MODAL);
        shell.setSize(450, 300);
        shell.setText(getText());

        shell.setLayout(new GridLayout(4, false));

        guiTree = new Tree(shell, SWT.BORDER | SWT.MULTI);
        guiTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));

        buildGuiTree();

        Button btnExpandAll = new Button(shell, SWT.NONE);
        btnExpandAll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                expandAll(guiTree, true);
            }
        });
        btnExpandAll.setText("Expand all");

        Button btnCollapseAll = new Button(shell, SWT.NONE);
        btnCollapseAll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                expandAll(guiTree, false);
            }
        });
        btnCollapseAll.setText("Collapse all");
        
        Button btnCondense = new Button(shell, SWT.NONE);
        btnCondense.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                model.condenseModel();
                guiTree.removeAll();
                buildGuiTree();
            }
        });
        btnCondense.setText("Condense");
        
        Button btnMerge = new Button(shell, SWT.NONE);
        btnMerge.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                mergeSelectedNode(guiTree);
            }
        });
        btnMerge.setText("Merge nodes");
        
        //new Label(shell, SWT.NONE);
        new Label(shell, SWT.NONE);
        new Label(shell, SWT.NONE);
        new Label(shell, SWT.NONE);

    }

    private void buildGuiTree() {
        GUIModel.Traverser traverser = model.getTraverser();
        
        IGUIElement root = traverser.firstChild();
        
        while (root != null) {
            TreeItem child = new TreeItem(guiTree, SWT.NULL);
            child.setText(root.toString());
            child.setData(root);
            buildGuiTree(child, traverser);
            root = traverser.nextSibling();
        }
    }

    private void buildGuiTree(TreeItem currentParent, GUIModel.Traverser traverser) {
        if (traverser.hasFirstChild()) {
            IGUIElement childElement = traverser.firstChild();
        
            while (childElement != null) {
                TreeItem child = new TreeItem(currentParent, SWT.NULL);
                child.setText(childElement.toString());
                child.setData(childElement);
                buildGuiTree(child, traverser);
                childElement = traverser.nextSibling();
            }
        
            traverser.parent();
        }
    }

    private void buildGuiTree(TreeItem currentParent, List<IGUIElement> elements) {
        for (IGUIElement element : elements) {
            TreeItem child = new TreeItem(currentParent, SWT.NULL);
            child.setText(element.toString());
            child.setData(element);
            buildGuiTree(child, model.getChildren(element));
        }
    }

    private void expandAll(Tree tree, boolean expanded) {
        for (TreeItem item : tree.getItems()) {
            expandAll(item, expanded);
        }
    }

    private void expandAll(TreeItem item, boolean expanded) {
        item.setExpanded(expanded);
        for (TreeItem childItem : item.getItems()) {
            expandAll(childItem, expanded);
        }
    }
    
    private void mergeSelectedNode(Tree tree) {
        TreeItem[] selectedNodes = tree.getSelection();
        if( selectedNodes.length<2 ) {
            MessageBox messageBox = new MessageBox(shell, SWT.ERROR);
            messageBox.setMessage("Must select at least two nodes to merge!");
            messageBox.setText("Error");
            messageBox.open();
            return;
        }
        
        TreeItem firstParent = selectedNodes[0].getParentItem();
        for( int i=1 ; i<selectedNodes.length ; i++ ) {
            if( firstParent!=selectedNodes[i].getParentItem() ) {
                MessageBox messageBox = new MessageBox(shell, SWT.ERROR);
                messageBox.setMessage("All selected nodes must have the same parent!");
                messageBox.setText("Error");
                messageBox.open();
                return;
            }
        }
        
        try {
            // try to merge the elements
            IGUIElement firstElement = (IGUIElement) selectedNodes[0].getData();
            for( int i=1 ; i<selectedNodes.length ; i++ ) {
                model.mergeGUIElements(firstElement, (IGUIElement) selectedNodes[i].getData());
            }
        } catch( IllegalArgumentException e) {
            Console.logException(e);
        }
        
        // update visualization of the model
        firstParent.removeAll();
        buildGuiTree(firstParent, model.getChildren((IGUIElement) firstParent.getData()));
        firstParent.setExpanded(true);
    }

}
