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

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.ArrayList;

import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

import com.onpositive.richtexteditor.viewer.RichTextViewer;

import de.ugoe.cs.swe.memos.SettingsManager;
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.datamodel.File;
import de.ugoe.cs.swe.memos.datamodel.Memo;
import de.ugoe.cs.swe.memos.datamodel.Tag;
import de.ugoe.cs.swe.memos.search.CategoryCompletionText;
import de.ugoe.cs.swe.memos.search.TagCompletionText;

public class ArticleComposite extends Composite {
	private Text titleField;
	private RichTextViewer richTextViewer;
	// contentViewer is used for the read-only mode
	private Browser contentViewer;
	private TagCompletionText tagsField;
	private CategoryCompletionText categoryField;
	private Label authorLabel;
	private Button okButton, cancelButton, editButton, addButton, delButton,
			saveButton;
	private Memo currentMemo;
	private Composite confirmComposite, fileComposite;
	private List fileList;

	DropTarget fileListDropTarget;
	final FileTransfer fileTransfer = FileTransfer.getInstance();
	private ArrayList<File> shadowFileList = new ArrayList<File>();
	boolean editable;
	private Composite editorComposite;

	public enum MODE {
		READ, WRITE
	}

	private void refreshGUI() {
		layout();
		fileComposite.layout();
	}

	public ArticleComposite(final Composite parent, int style, Memo memo,
			final CategoryBrowser cbrowser, MODE mode) {
		super(parent, style);
		this.currentMemo = memo;

		createGUI(mode);
		addListeners(parent);

		if (currentMemo == null) {
			currentMemo = new Memo("", true);
			currentMemo.setAuthor(SettingsManager.getInstance().getUsername());
			currentMemo.setLock(SettingsManager.getInstance().getUsername());
			DBUtility.getInstance().insertMemo(currentMemo);
		}

		// categoryField.setEditable(false);
		// Category cat = cbrowser.getSelectedCategory();
		// if (cat != null)
		// categoryField.setText(cbrowser.getSelectedCategory().getName());
		fillGUI(currentMemo);

		// javax.swing.Timer t = new javax.swing.Timer(5000, new
		// ActionListener(){
		// Category c = (Category) categoryField.getTextField().getData();

		//
		// @Override
		// public void actionPerformed(ActionEvent e) {
		// System.out.println("Hallo");
		// while(true)
		// {}
		//				
		// }});
		//		
		// t.start();

	}

	public void closeMemo() {
		if (currentMemo.getLock() != null
				&& currentMemo.getLock() == SettingsManager.getInstance()
						.getUsername()) {
			MessageBox messageBox = new MessageBox(new Shell(),
					SWT.ICON_WARNING | SWT.YES | SWT.NO | SWT.NO_FOCUS);
			messageBox.setText("Inhalt verwerfen?");
			messageBox.setMessage("Wollen Sie die Änderungen wirklich"
					+ "verwerfen?");
			if (messageBox.open() == SWT.YES) {

				if (currentMemo.isDraft()) {
					try {
						DBUtility.getInstance().deleteMemo(currentMemo);
					} catch (DatabaseException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				} else {
					try {
						DBUtility.getInstance().unlockMemo(currentMemo);
					} catch (DatabaseException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				}
				closeTab();
			}

		} else
			closeTab();
	}

	private void addListeners(final Composite parent) {
		editButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event e) {
				try {
					DBUtility.getInstance().updateMemoFromDB(currentMemo);
					//DBUtility.getInstance().updateMemoInDatabase(currentMemo);
					fillGUI(currentMemo);

					if (DBUtility.getInstance().lockMemo(currentMemo)) {
						contentViewer.dispose();
						richTextViewer = new RichTextViewer(editorComposite,
								SWT.BORDER);
						richTextViewer.getTextWidget().setLayout(
								Utils.createGridLayout(1, 0, 0, 0));
						richTextViewer.getTextWidget().setLayoutData(
								new GridData(SWT.LEFT, SWT.FILL, true, true, 1,
										1));
						// refreshes the composite's content :)
						editorComposite.layout();
						fillGUI(currentMemo);

					}
				} catch (DatabaseException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
		});

		cancelButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event e) {
				closeMemo();
			}
		});

		okButton.addListener(SWT.Selection, new Listener() {
			public void handleEvent(Event e) {
				// TODO: IMPORTANT! Change this when category field related
				// stuff is complete
				Category c = (Category) categoryField.getTextField().getData();
				if (c == null)
					c = Category.byPath(categoryField.getTextField().getText());
				if (c == null) {
					Utils.showError("Bitte eine Kategorie auswählen");
					return;
				}
				currentMemo.setDraft(false);
				try {
					DBUtility.getInstance().updateLockDataInMemo(currentMemo);
					if (currentMemo.getLock() == SettingsManager.getInstance()
							.getUsername()) {
						// We still have the lock
						updateMemo();
						DBUtility.getInstance().unlockMemo(currentMemo);
						closeTab();
					} else {
						// Lock was stealed
						if (DBUtility.getInstance().lockMemo(currentMemo)) {
							// Lock was regained
							updateMemo();
							DBUtility.getInstance().unlockMemo(currentMemo);
							closeTab();
						}
					}
				} catch (Exception e1) {
					// TODO: Better exception handling
					e1.printStackTrace();
				}
			}

		});

		fileListDropTarget.addDropListener(new DropTargetListener() {

			@Override
			public void dragEnter(DropTargetEvent event) {
				if (!editable) {
					event.detail = DND.DROP_NONE;
					return;
				}
				if (event.detail == DND.DROP_DEFAULT) {
					if ((event.operations & DND.DROP_COPY) != 0) {
						event.detail = DND.DROP_COPY;
					} else {
						event.detail = DND.DROP_NONE;
					}
				}

				for (int i = 0; i < event.dataTypes.length; i++) {
					if (fileTransfer.isSupportedType(event.dataTypes[i])) {
						event.currentDataType = event.dataTypes[i];
						// files should only be copied
						if (event.detail != DND.DROP_COPY) {
							event.detail = DND.DROP_NONE;
						}
						break;
					}
				}

			}

			@Override
			public void dragLeave(DropTargetEvent event) {
			}

			@Override
			public void dragOperationChanged(DropTargetEvent event) {
				if (!editable) {
					event.detail = DND.DROP_NONE;
					return;
				}
				if (event.detail == DND.DROP_DEFAULT) {
					if ((event.operations & DND.DROP_COPY) != 0) {
						event.detail = DND.DROP_COPY;
					} else {
						event.detail = DND.DROP_NONE;
					}
				}
				// allow text to be moved but files should only be copied
				if (fileTransfer.isSupportedType(event.currentDataType)) {
					if (event.detail != DND.DROP_COPY) {
						event.detail = DND.DROP_NONE;
					}
				}

			}

			@Override
			public void dragOver(DropTargetEvent event) {
			}

			@Override
			public void drop(DropTargetEvent event) {
				if (!editable) {
					event.detail = DND.DROP_NONE;
					return;
				}
				if (fileTransfer.isSupportedType(event.currentDataType)) {
					String[] files = (String[]) event.data;
					for (int i = 0; i < files.length; i++) {
						addFile(files[i]);
						// fileList.add(files[i]);
						// TableItem item = new TableItem(dropTable, SWT.NONE);
						// item.setText(files[i]);
					}
					refreshGUI();
				}

			}

			@Override
			public void dropAccept(DropTargetEvent event) {
			}

		});

		addButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				FileDialog fd = new FileDialog(fileComposite.getShell(),
						SWT.OPEN);
				fd.setText("Datei hinzufügen");
				// fd.setFilterExtensions(new String[] {"*.*"});
				String fileName = fd.open();

				if (fileName != null) {
					addFile(fileName);
				}
			}
		});

		delButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (fileList.getSelectionCount() == 1) {
					int index = fileList.getSelectionIndex();
					if (DBUtility.getInstance().deleteFileByFileID(
							shadowFileList.get(index).id)) {
						shadowFileList.remove(index);
						fileList.remove(index);
					}
				}

			}
		});

		saveButton.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				if (fileList.getSelectionCount() == 1) {
					int index = fileList.getSelectionIndex();
					FileDialog fd = new FileDialog(fileComposite.getShell(),
							SWT.SAVE);
					fd.setText("Datei speichern unter");
					fd.setFileName(fileList.getItem(index));
					// fd.setFilterExtensions(new String[] {"*.*"});
					String fileName = fd.open();

					if (fileName != null) {
						try {
							FileOutputStream o = new FileOutputStream(fileName);
							DBUtility.getInstance().getFileContent(
									shadowFileList.get(index), o);
							o.close();
						} catch (Exception e1) {
							// TODO Auto-generated catch block
							e1.printStackTrace();
						}
					}
				}
			}
		});

	}

	private void setEditable(boolean editable) {
		if (this.richTextViewer != null) {
			this.richTextViewer.setEditable(editable);
		}
		// else
		// this.contentViewer.setEnabled(editable);
	}

	public String getHTMLContent() {
		return (this.richTextViewer != null) ? this.richTextViewer
				.getLayerManager().getSerializedString() : this.contentViewer
				.getText();
	}

	public void setContent(String content) {
		if (this.richTextViewer != null) {
			this.richTextViewer.getTextWidget().setText("");
			this.richTextViewer.getLayerManager().pasteHTML(content, 0);
		} else
			this.contentViewer.setText(content);
	}

	public Memo getMemo() {
		return currentMemo;
	}

	private void createGUI(MODE mode) {
		Composite metaDataComposite = new Composite(this, SWT.NONE);
		metaDataComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER,
				false, false, 1, 1));
		metaDataComposite.setLayout(Utils.createGridLayout(7));
		this.setLayout(Utils.createGridLayout(1));

		Label titleLabel = new Label(metaDataComposite, SWT.NONE);
		titleLabel.setText("Überschrift");
		titleLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 1, 1));

		titleField = new Text(metaDataComposite, SWT.BORDER);
		titleField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true,
				false, 5, 1));

		authorLabel = new Label(metaDataComposite, SWT.NONE);
		authorLabel.setText("Author dummy");
		authorLabel.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false,
				false, 1, 1));

		Label categoryLabel = new Label(metaDataComposite, SWT.NONE);
		categoryLabel.setText("Kategorie");
		categoryLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false,
				false, 1, 1));

		categoryField = new CategoryCompletionText(metaDataComposite,
				SWT.BORDER, false, true);
		categoryField.getTextField().setLayoutData(
				new GridData(SWT.FILL, SWT.CENTER, true, false, 6, 1));

		Label tagLabel = new Label(metaDataComposite, SWT.NONE);
		tagLabel.setText("Tags");
		tagLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false,
				1, 1));

		tagsField = new TagCompletionText(metaDataComposite, SWT.BORDER, true,
				false);
		tagsField.getTextField().setLayoutData(
				new GridData(SWT.FILL, SWT.CENTER, true, false, 6, 1));

		editorComposite = new Composite(this, SWT.BORDER);
		editorComposite.setLayout(new FillLayout(SWT.HORIZONTAL));
		editorComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
				true, 1, 1));

		if (mode == MODE.WRITE) {
			richTextViewer = new RichTextViewer(editorComposite, SWT.BORDER);

			richTextViewer.getTextWidget().setLayout(
					Utils.createGridLayout(1, 0, 0, 0));
			richTextViewer.getTextWidget().setLayoutData(
					new GridData(SWT.LEFT, SWT.FILL, true, true, 1, 1));
			// TODO: Add a border to the richTExtViewer's textWidget
			// richTextViewer.getTextWidget().setStyle
		} else
			contentViewer = new Browser(editorComposite, SWT.BORDER);

		Composite lowerComposite = new Composite(this, SWT.NONE);
		GridData d2 = new GridData(SWT.FILL, SWT.BOTTOM, true, false, 1, 1);
		d2.heightHint = 88;
		lowerComposite.setLayoutData(d2);
		lowerComposite.setLayout(Utils.createGridLayout(2, 0, 0, 0));

		fileComposite = new Composite(lowerComposite, SWT.NONE);
		GridData d = new GridData(SWT.LEFT, SWT.BOTTOM, true, false, 1, 1);

		fileComposite.setLayoutData(d);
		fileComposite.setLayout(Utils.createGridLayout(2, 0, 0, 0));

		fileList = new List(fileComposite, SWT.BORDER | SWT.V_SCROLL);
		d = new GridData(SWT.LEFT, SWT.FILL, true, true, 1, 3);
		d.minimumWidth = 250;
		d.heightHint = 80;

		fileList.setLayoutData(d);
		int operations = DND.DROP_MOVE | DND.DROP_COPY | DND.DROP_DEFAULT;
		fileListDropTarget = new DropTarget(fileList, operations);
		Transfer[] types = new Transfer[] { fileTransfer };
		fileListDropTarget.setTransfer(types);

		addButton = new Button(fileComposite, SWT.NONE);
		addButton.setText("Datei hinzufügen");
		addButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1,
				1));

		delButton = new Button(fileComposite, SWT.NONE);
		delButton.setText("Datei löschen");
		delButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1,
				1));

		saveButton = new Button(fileComposite, SWT.NONE);
		saveButton.setText("Datei speichern unter");
		saveButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false,
				1, 1));

		confirmComposite = new Composite(lowerComposite, SWT.NONE);
		confirmComposite.setLayoutData(new GridData(SWT.RIGHT, SWT.BOTTOM,
				true, false, 1, 1));
		confirmComposite.setLayout(Utils.createGridLayout(1, 0, 0, 0));

		editButton = new Button(confirmComposite, SWT.None);
		editButton.setText("Editieren");
		editButton.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true,
				false, 1, 1));

		okButton = new Button(confirmComposite, SWT.NONE);
		okButton.setText("Speichern und Schließen");
		okButton.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false,
				1, 1));

		cancelButton = new Button(confirmComposite, SWT.NONE);
		cancelButton.setText("Schließen");
		cancelButton.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true,
				false, 1, 1));
	}

	private void addFile(String filename) {
		File f = new File();
		String fName = filename.substring(filename
				.lastIndexOf(java.io.File.separatorChar) + 1);
		f.name = fName;
		f.memo = currentMemo;
		try {
			DBUtility.getInstance().insertSingleFile(f,
					new FileInputStream(filename),
					(new java.io.File(filename)).length());
			shadowFileList.add(f);
			fileList.add(fName);
		} catch (FileNotFoundException e) {
			Utils.showError("Fehler beim Einfügen der Datei in die Datenbank: Datei wurde nicht gefunden");
		}
		
	}

	private void closeTab() {
		Utils.getMainView().closeActiveTabItem();
	}

	private void updateMemo() {
		System.out.println(getHTMLContent());

		currentMemo.setTitle(titleField.getText());
		currentMemo.setContent(getHTMLContent());

		String[] tags = tagsField.getTextField().getText().split("\\s");
		for (String tag : tags) {
			if (tag.equals(""))
				continue;
			if (!tagExists(tag)) {
				Tag t = new Tag(tag);
				t.setMemo(currentMemo);
				currentMemo.getTags().add(t);
			}
		}

		Category c = (Category) categoryField.getTextField().getData();
		if (c == null)
			c = Category.byPath(categoryField.getTextField().getText());

		currentMemo.setCategory(c);
		currentMemo.setCategoryID(c.getiD());

		DBUtility.getInstance().updateMemoInDatabase(currentMemo);

	}

	private boolean tagExists(String tag) {
		for (Tag t : currentMemo.getTags()) {
			if (t.getName().toLowerCase().equals(tag.toLowerCase()))
				return true;
		}
		return false;
	}

	public Text getCategoryField() {
		return categoryField.getTextField();
	}

	private void fillGUI(Memo memo) {
		if (memo == null)
			return;
		titleField.setText(memo.getTitle());
		if (memo.getCategory() != null) {
			categoryField.getTextField().setText(memo.getCategory().getName());
			categoryField.getTextField().setData(memo.getCategory());
		}

		if (memo.getContent() != null)
			this.setContent((memo.getContent()));

		String tags = "";
		for (Tag tag : memo.getTags())
			tags += tag.getName() + " ";
		if (tags.length() != 0) {
			tags = tags.substring(0, tags.length() - 1);
			tagsField.getTextField().setText(tags);
		} else
			tagsField.getTextField().setText("");

		authorLabel.setText("Autor: " + memo.getAuthor());

		fileList.removeAll();
		shadowFileList.clear();
		memo.loadFiles();
		for (File f : memo.getFiles()) {
			shadowFileList.add(f);
			fileList.add(f.name);
		}

		editable = (SettingsManager.getInstance().getUsername().equals(memo
				.getLock()));

		titleField.setEditable(editable);
		tagsField.getTextField().setEditable(editable);
		this.setEditable(editable);
		editButton.setEnabled(!editable);
		okButton.setEnabled(editable);
		addButton.setEnabled(editable);
		delButton.setEnabled(editable);
	}

}
