//   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.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
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.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstanceList;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IUserSession;

import org.eclipse.swt.widgets.Label;

/**
 * <p>
 * TODO comment
 * </p>
 * 
 * @author Patrick Harms
 */
public class ShowTaskTreeDialog extends Dialog {

    /** */
    protected Shell shell;
    
    /** */
    private Tree instanceTree;
    
    /** */
    private Tree modelTree;

    /** */
    protected ITaskModel taskModel;

    /**
     * 
     */
    public ShowTaskTreeDialog(Shell parent, int style, ITaskModel taskModel, String taskTreeName) {
        super(parent, style);
        setText("Task Model " + taskTreeName);
        this.taskModel = taskModel;
    }

    /**
     * 
     */
    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(750, 800);
        shell.setText(getText());

        shell.setLayout(new GridLayout(4, false));
        
        SashForm sashForm = new SashForm(shell, SWT.HORIZONTAL);
        sashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 4, 1));
        
        instanceTree = new Tree(sashForm, SWT.BORDER | SWT.MULTI);
        instanceTree.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                modelTree.removeAll();
                TreeItem[] selectedItems = instanceTree.getSelection();
                if (selectedItems.length == 1) {
                    if (selectedItems[0].getData() instanceof ITaskInstance) {
                        buildModelTree((ITaskInstance) selectedItems[0].getData());
                    }
                    else if (selectedItems[0].getData() instanceof ITaskModel) {
                        buildModelTree((ITaskModel) selectedItems[0].getData());
                    }
                }
            }
        });

        buildInstanceTree();

        modelTree = new Tree(sashForm, SWT.BORDER | SWT.MULTI);
        buildModelTree(taskModel);

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

        Button btnCollapseAll = new Button(shell, SWT.NONE);
        btnCollapseAll.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                expandAll(instanceTree, false);
            }
        });
        btnCollapseAll.setText("Collapse all");
        
        //new Label(shell, SWT.NONE);
        new Label(shell, SWT.NONE);
        new Label(shell, SWT.NONE);
        new Label(shell, SWT.NONE);

    }

    /**
     * 
     */
    private void buildInstanceTree() {
        List<IUserSession> sessions = taskModel.getUserSessions();
        
        TreeItem root = new TreeItem(instanceTree, SWT.NULL);
        root.setText(sessions.size() + " sessions");
        root.setData(taskModel);
        
        for (IUserSession session : sessions) {
            buildInstanceTree(root, session);
        }
    }

    /**
     * 
     */
    private void buildInstanceTree(TreeItem currentParent, ITaskInstanceList taskInstanceList) {
        TreeItem child = new TreeItem(currentParent, SWT.NULL);
        child.setText(taskInstanceList.toString());
        child.setData(taskInstanceList);
        
        for (ITaskInstanceList childTask : taskInstanceList) {
            buildInstanceTree(child, childTask);
        }
    }

    /**
     * 
     */
    private void buildModelTree(ITaskModel taskModel) {
        modelTree.removeAll();
        
        // load the correct children on expansion
        if (modelTree.getListeners(SWT.Expand).length == 0) {
           modelTree.addListener(SWT.Expand, new Listener() {
               public void handleEvent(final Event event) {
                   ensureChildren((TreeItem) event.item);
                   ((TreeItem) event.item).setExpanded(true);
               }
           });
        }
        
        Collection<ITask> tasks = taskModel.getTasks();
        
        TreeItem root = new TreeItem(modelTree, SWT.NULL);
        root.setText(tasks.size() + " tasks in model");
        root.setData(taskModel);

        tasks = determineRootTasks(tasks);
        
        for (ITask task : tasks) {
            createTreeItemFor(task, root);
        }
        
        root.setExpanded(true);
    }

    /**
     * 
     */
    private void buildModelTree(ITaskInstance taskInstance) {
        modelTree.removeAll();
        TreeItem root = new TreeItem(modelTree, SWT.NULL);
        root.setText("model of instance " + taskInstance);
        root.setData(taskInstance);

        createTreeItemFor(taskInstance.getTask(), root);
        
        expandAll(root, true, 20);
    }

    /**
     *
     */
    private Collection<ITask> determineRootTasks(Collection<ITask> tasks) {
        Set<ITask> result = new HashSet<ITask>(tasks);
        
        for (ITask task : tasks) {
            removeChildren(task, result);
        }
        
        return result;
    }

    /**
     *
     */
    private void removeChildren(ITask task, Set<ITask> result) {
        if (task instanceof IStructuringTemporalRelationship) {
            for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) {
                result.remove(child);
            }
        }
        else if (task instanceof IMarkingTemporalRelationship) {
            result.remove(((IMarkingTemporalRelationship) task).getMarkedTask());
        }
    }

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

    /**
     * 
     */
    private void expandAll(TreeItem item, boolean expanded, int maxChildrenToExpand) {
        if (expanded) {
            ensureChildren(item);
        }
        
        if (item.getItems().length < maxChildrenToExpand) {
            item.setExpanded(expanded);

            for (TreeItem childItem : item.getItems()) {
                expandAll(childItem, expanded, maxChildrenToExpand);
            }
        }
    }
    
    /**
     * 
     */
    private void ensureChildren(TreeItem parent) {
        if (parent.getData() instanceof ITask) {
            TreeItem[] items = parent.getItems();
            if ((items == null) || (items.length == 0) || (items[0].getData() == null)) {
                for (int i = 0; i < items.length; i++) {
                    items[i].dispose();
                }

                ITask task = (ITask) parent.getData();

                if (task instanceof IStructuringTemporalRelationship) {
                    for (ITask subTask : ((IStructuringTemporalRelationship) task).getChildren()) {
                        createTreeItemFor(subTask, parent);
                    }
                }
                else if (task instanceof IMarkingTemporalRelationship) {
                    createTreeItemFor
                        (((IMarkingTemporalRelationship) task).getMarkedTask(), parent);
                }
            }
        }
    }

    /**
     *
     */
    private void createTreeItemFor(ITask task, TreeItem parent) {
        TreeItem item = new TreeItem(parent, SWT.NULL);
        item.setText(task.toString());
        item.setData(task);
        
        // simulate a child
        if ((task instanceof IStructuringTemporalRelationship) ||
            (task instanceof IMarkingTemporalRelationship))
        {
            new TreeItem(item, SWT.NULL);
        }
    }

}
