//   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 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.HierarchicalEventTargetModel;
import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTarget;
import de.ugoe.cs.autoquest.eventcore.IHierarchicalEventTargetModel;
import de.ugoe.cs.util.console.Console;

import org.eclipse.swt.widgets.Label;

public class ShowGuiModelDialog<T extends IHierarchicalEventTarget> extends Dialog {

    protected Shell shell;
    private Tree targetTree;

    protected IHierarchicalEventTargetModel<T> model;

    public ShowGuiModelDialog(Shell parent, int style, IHierarchicalEventTargetModel<T> 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));

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

        buildTargetTree();

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

        Button btnCollapseAll = new Button(shell, SWT.NONE);
        btnCollapseAll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                expandAll(targetTree, false);
            }
        });
        btnCollapseAll.setText("Collapse all");
        
        if (model instanceof HierarchicalEventTargetModel) {
            Button btnCondense = new Button(shell, SWT.NONE);
            btnCondense.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    ((HierarchicalEventTargetModel<?>) model).condenseModel();
                    targetTree.removeAll();
                    buildTargetTree();
                }
            });
            btnCondense.setText("Condense");

            Button btnMerge = new Button(shell, SWT.NONE);
            btnMerge.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    mergeSelectedNode(targetTree);
                }
            });
            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 buildTargetTree() {
        IHierarchicalEventTargetModel.Traverser<T> traverser =  model.getTraverser();
        
        IHierarchicalEventTarget root = traverser.firstChild();
        
        while (root != null) {
            TreeItem child = new TreeItem(targetTree, SWT.NULL);
            child.setText(root.toString());
            child.setData(root);
            buildTargetTree(child, traverser);
            root = traverser.nextSibling();
        }
    }

    private void buildTargetTree(TreeItem                                   currentParent,
                                 IHierarchicalEventTargetModel.Traverser<T> traverser)
    {
        if (traverser.hasFirstChild()) {
            T childElement = traverser.firstChild();
        
            while (childElement != null) {
                TreeItem child = new TreeItem(currentParent, SWT.NULL);
                child.setText(childElement.toString());
                child.setData(childElement);
                buildTargetTree(child, traverser);
                childElement = traverser.nextSibling();
            }
        
            traverser.parent();
        }
    }

    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);
        }
    }
    
    @SuppressWarnings("unchecked")
    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
            T firstElement = (T) selectedNodes[0].getData();
            for( int i=1 ; i<selectedNodes.length ; i++ ) {
                ((HierarchicalEventTargetModel<T>) model).mergeEventTargets
                    (firstElement, (T) selectedNodes[i].getData());
            }
        }
        catch( IllegalArgumentException e) {
            Console.logException(e);
        }
        
        // update visualization of the model
        if (firstParent != null) {
            firstParent.removeAll();
            buildTargetTree(firstParent, model.getTraverser((T) firstParent.getData()));
            firstParent.setExpanded(true);
        }
        else {
            targetTree.removeAll();
            buildTargetTree();
        }
    }

}
