package de.ugoe.cs.swe.memos.gui.mainview;

import java.util.Vector;

import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import de.ugoe.cs.swe.memos.Utils;
import de.ugoe.cs.swe.memos.database.DBUtility;
import de.ugoe.cs.swe.memos.database.DatabaseException;
import de.ugoe.cs.swe.memos.datamodel.Category;
import de.ugoe.cs.swe.memos.gui.menu.deleteCHandler;
import de.ugoe.cs.swe.memos.gui.menu.editCHandler;

public class CategoryBrowser {
	private Tree categoryTree;
	private DBUtility connect = DBUtility.getInstance();
	private CatExpandListener expandHandler = new CatExpandListener();
	private TreeMouseListener treeMouseListener = new TreeMouseListener(this);

	public CategoryBrowser(Composite parent) {
		Group categoryBrowser = new Group(parent, SWT.RESIZE);
		categoryBrowser.setText("Kategorien Baum");

		categoryBrowser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false,
				true, 1, 1));
		categoryBrowser.setLayout(createGridLayout(3));
		
		categoryTree = new Tree(categoryBrowser, SWT.BORDER);
		categoryTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				true, 3, 1));
		Button addButton = new Button(categoryBrowser, SWT.NONE);
		addButton.setText("+");
		addButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				false, 1, 1));
		addButton
				.setToolTipText("Eine Kategorie an den aktuell selektierten Knoten / Wurzel anfügen");
		addButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				addCategoryButtonPressed();

			}
		});
		Button delButton = new Button(categoryBrowser, SWT.NONE);
		delButton.setText(" - ");
		delButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				false, 1, 1));
		delButton.setToolTipText("die aktuell selektierte Kategorie löschen");
		delButton.addListener(SWT.Selection, new deleteCHandler());
		Button refreshButton = new Button(categoryBrowser, SWT.NONE);
		refreshButton.setText("refresh");
		GridData gd1=new GridData(SWT.FILL, SWT.FILL, false,
				false, 1, 1);
		//gd1.minimumWidth=180;
		gd1.widthHint=100;
		refreshButton.setLayoutData(gd1);
		refreshButton
				.setToolTipText("Einen manuellen Refresh der Kategorien durchführen!");
		refreshButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				refreshCatTree();
			}
		});
		createRightClickMenu();
		categoryTree.addMouseListener(this.treeMouseListener);
		categoryTree.addTreeListener(expandHandler);
		categoryTree.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent event) {
				if (event.keyCode == SWT.F2
						&& categoryTree.getSelectionCount() == 1) {
					addCategoryButtonPressed();
				}
			}
		});
		categoryTree.addFocusListener(new FocusListener() {

			@Override
			public void focusGained(FocusEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void focusLost(FocusEvent e) {
				if (categoryTree.getSelectionCount() < 1) {
					deleteCHandler.setEnabled(false);
					editCHandler.setEnabled(false);
				}
			}

		});
		fillTree();
	}

	public TreeMouseListener getTreeMouseListener() {
		return this.treeMouseListener;
	}

	private void createRightClickMenu() {
		Menu menu = new Menu(categoryTree);
		categoryTree.setMenu(menu);

		final MenuItem addCategory = new MenuItem(menu, SWT.NONE);
		addCategory.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event event) {
				addCategoryButtonPressed();
			}
		});
		addCategory.setText("Kategorie hinzufügen");
		final MenuItem delCategory = new MenuItem(menu, SWT.NONE);
		delCategory.addListener(SWT.Selection, new deleteCHandler());
		delCategory.setText("Kategorie entfernen");
		final MenuItem modifyCategory = new MenuItem(menu, SWT.NONE);
		modifyCategory.addListener(SWT.Selection, new editCHandler());
		modifyCategory.setText("Kategorie editieren");
	}

	public void addCategoryButtonPressed() {
		final TreeItem newEntryItem;
		try {
			if (categoryTree.getSelection().length <= 0) {
				Category root = new Category("root");
				Category newCategory = new Category("neueRootKategorie");
				connect.addChildrenToCategory(root);
				newEntryItem = new TreeItem(categoryTree, 0);
				newEntryItem.setData(newCategory);
				showNewCatEditField(newEntryItem, newCategory, root);
			} else {
				TreeItem selectedItem = categoryTree.getSelection()[0];
				Category selectedCategory = (Category) selectedItem.getData();

				CatExpandListener.expandHandler(selectedItem);

				Category newCategory = new Category("neueKategorie");
				newEntryItem = new TreeItem(selectedItem, 0);
				newEntryItem.setData(newCategory);
				selectedItem.setExpanded(true);
				showNewCatEditField(newEntryItem, newCategory, selectedCategory);
			}
		} catch (DatabaseException e) {
			Utils
					.showError("Fehler mit der Datenbank, bitte starte die Anwendung neu");
		}
	}

	public boolean isValidCategoryName(String name,
			Vector<Category> activeCategories) {
		for (Category child : activeCategories) {
			if (child.getName().equals(name)) {
				MessageBox mb = new MessageBox(new Shell(), SWT.OK
						| SWT.ICON_WARNING);
				mb.setText("Doppelte Kategorie");
				mb.setMessage("Keine Unterkategorien mit identischem Namen möglich.");
				mb.open();
				//refreshCatTree();
				return false;
			}
		}
		return true;
	}
	
	private boolean doNotLoseFocus=false;

	private void showNewCatEditField(final TreeItem newEntryItem,
			final Category newCategory, final Category parent) {
		final TreeEditor editor = new TreeEditor(categoryTree);
		final Text itemTextEditor = new Text(categoryTree, SWT.NONE);

		editor.horizontalAlignment = SWT.LEFT;
		editor.grabHorizontal = true;

		itemTextEditor.setText("Kategoriename");
		itemTextEditor.selectAll();
		itemTextEditor.setFocus();
		itemTextEditor.addFocusListener(new FocusAdapter() {
			public void focusLost(FocusEvent event) {
				if (!doNotLoseFocus && isValidCategoryName(itemTextEditor.getText(), parent
						.getChildCategories())) {
					newCategory.setName(itemTextEditor.getText());
					newEntryItem.setText(newCategory.getName());
					parent.addChild(newCategory);
					connect.insertSingleCategory(newCategory);
					refreshCatTree();
					itemTextEditor.dispose();
				}
				else
				{
				newEntryItem.dispose();
				itemTextEditor.dispose();
				}
			}
		});

		itemTextEditor.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent event) {
				doNotLoseFocus=true;
				switch (event.keyCode) {
				case SWT.CR:
					if (isValidCategoryName(itemTextEditor.getText(), parent
							.getChildCategories())) 
					{
						newCategory.setName(itemTextEditor.getText());
						newEntryItem.setText(newCategory.getName());
						parent.addChild(newCategory);
						connect.insertSingleCategory(newCategory);
						refreshCatTree();
						itemTextEditor.dispose();
					}
					else
					{
						newEntryItem.dispose();
						itemTextEditor.dispose();
					}
					break;

				case SWT.ESC:
					itemTextEditor.dispose();
					refreshCatTree();
					// event.doit = false;
					break;
				}
				doNotLoseFocus=false;
			}
		});
		editor.setEditor(itemTextEditor, newEntryItem);
	}

	private void fillTree() {

		Category root = new Category("root");
		root.setiD(0L);
		root.loadChildrenFromDB();

		for (Category c : root.getChildCategories()) {
			TreeItem iItem = new TreeItem(categoryTree, 0);
			iItem.setText(c.getName());
			iItem.setData(c);

			TreeItem newSubTI = new TreeItem(iItem, SWT.NONE);
			newSubTI.setText("...");
		}
	}

	private GridLayout createGridLayout(int numColumns) {
		GridLayout gridLayout = new GridLayout();
		gridLayout.numColumns = numColumns;
		return gridLayout;
	}

	public Tree getCategoryTree() {
		return this.categoryTree;
	}

	public Category getSelectedCategory() {
		if (categoryTree.getSelectionCount() != 0) {
			TreeItem selectedItem = categoryTree.getSelection()[0];
			return (Category) selectedItem.getData();
		}
		return null;
	}

	public void refreshCatTree() {
		Category selectedCategory = getSelectedCategory();
		Vector<Long> expandedTreeItems = new Vector<Long>();
		for (TreeItem ti : categoryTree.getItems())
			if (ti.getExpanded()) {
				expandedTreeItems.add(((Category) ti.getData()).getiD());
				fillExpandedItems(ti, expandedTreeItems);
			}

		categoryTree.removeAll();
		this.fillTree();

		for (TreeItem ti : categoryTree.getItems()) {

			if (ti.getData() != null
					&& expandedTreeItems.contains(((Category) ti.getData())
							.getiD())) {
				CatExpandListener.expandHandler(ti);
				ti.setExpanded(true);
				iterateTree(ti, selectedCategory, expandedTreeItems);
			}

			if (ti.getData() != null
					&& selectedCategory != null
					&& ((Category) ti.getData()).getiD().equals(
							selectedCategory.getiD())) {
				categoryTree.select(ti);
			}
		}
	}

	private void fillExpandedItems(TreeItem pi, Vector<Long> expanded) {

		for (TreeItem ti : pi.getItems()) {
			if (ti.getExpanded()) {
				expanded.add(((Category) ti.getData()).getiD());
				fillExpandedItems(ti, expanded);
			}
		}
	}

	private void iterateTree(TreeItem pi, Category selectedCategory,
			Vector<Long> expandedTreeItems) {
		for (TreeItem ti : pi.getItems()) {
			if (ti.getData() != null
					&& expandedTreeItems.contains(((Category) ti.getData())
							.getiD())) {
				CatExpandListener.expandHandler(ti);
				ti.setExpanded(true);
				iterateTree(ti, selectedCategory, expandedTreeItems);
			}

			if (ti.getData() != null
					&& ((Category) ti.getData()).getiD().equals(
							selectedCategory.getiD())) {
				categoryTree.select(ti);
			}
		}
	}
}