/**
 * File:    ViewEditor.java
 * Created: 13.03.2009
 *
/*******************************************************************************
 * Copyright (c) 2005-2011
 * University of Augsburg, Germany, http://www.ds-lab.org/
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    Melanie Hesselbart, Programming distributed Systems Lab, University of Augsburg 
 *    	- initial API and implementation
 *******************************************************************************/

package org.eclipse.jwt.we_view_editor.editors;

import java.io.File;
import java.net.URL;
import java.util.List;

import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.ui.URIEditorInput;
import org.eclipse.emf.common.util.URI;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jwt.we.Plugin;
import org.eclipse.jwt.we.editors.actions.managed.recentfiles.RecentFilesListManager;
import org.eclipse.jwt.we.misc.util.FontUtil;
import org.eclipse.jwt.we.misc.views.ViewEcoreManager;
import org.eclipse.jwt.we.misc.views.ViewItemWrapper;
import org.eclipse.jwt.we_view_editor.PluginProperties;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
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.FileDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IEditorSite;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.ide.FileStoreEditorInput;
import org.eclipse.ui.part.FileEditorInput;
import org.eclipse.ui.part.MultiPageEditorPart;
import org.osgi.framework.Bundle;

public class ViewEditor extends MultiPageEditorPart {

	/**
	 * Name of the composite that the editor-page will be added to.
	 */
	private Composite composite;

	/**
	 * The table where the E-Classes are listed.
	 */
	private Table table;

	/**
	 * List of the E-Classes.
	 */
	private List<ViewItemWrapper> itemtabledata = null;

	/**
	 * The list of attributes corresponding to the selected E-Class.
	 */
	private List<ViewItemWrapper> attributes = null;

	/**
	 * The current view-File the user has in progress.
	 */
	private File currentfile;

	/**
	 * The extention of every view-File.
	 */
	private String extension = "view"; //$NON-NLS-1$

	/**
	 * The number of the selected row in the table (= selected E-Class),
	 * necessary for loading the details-view with the detail-properties of this
	 * E-Class.
	 */
	private int selectedRow;

	/**
	 * The path to the ecore-File.
	 */
	private URL ecorePath = null;

	/**
	 * List of the E-Classes and their values (true/false).
	 */
	private Object[][] data;

	/**
	 * Switches to true, if file has been edited, otherwise it's false.
	 */
	private boolean dirty = false;

	/**
	 * Textfield, where the view-name is displayed und also may be changed in.
	 */
	private Text viewName;

	/**
	 * The constructor
	 */
	public ViewEditor() {
		super();
	}

	/**
	 * The layout of the editor.
	 */
	protected void createPages() {
		// page for properties
		composite = new Composite(getContainer(), SWT.NONE);
		int index = addPage(composite);
		setPageText(index, PluginProperties.editor_pagetext_properties);

		// get path to editor-input file
		getPathToFile();

		// get path to ecore-file
		getPathToEcoreFile();

		ViewEcoreManager.getInstance().setPath(ecorePath.toString());
		ViewEcoreManager.getInstance().openFile(currentfile);

		// create textfield for the viewname and table for the E-Classes
		createLayout();

		// fill the table
		reloadTables();
		ViewEcoreManager.getInstance().savetoFile(currentfile);
		ViewEcoreManager.getInstance().setPath(ecorePath.getFile());
	}

	/**
	 * Inits the GUI for the E-Classes.
	 */
	private void createLayout() {
		// generall layout for the page
		GridLayout layout = new GridLayout();
		layout.numColumns = 1;
		composite.setLayout(layout);

		// for the view name group
		GridLayout layout2Columns = new GridLayout();
		layout2Columns.numColumns = 2;

		GridData data = new GridData();
		data.verticalAlignment = GridData.BEGINNING;

		// the part to change the viewname
		createLayoutViewname(layout2Columns);

		GridData data1 = new GridData();
		data1.verticalAlignment = GridData.BEGINNING;
		data1.verticalAlignment = GridData.FILL;
		// data1.horizontalAlignment = GridData.FILL;
		data1.grabExcessVerticalSpace = true;
		data1.grabExcessHorizontalSpace = true;

		// the part with the table for the e-classes to switch the properties
		// on/off
		createLayoutTable(layout2Columns, data1);

	}

	/**
	 * Creates the textfield to edit the viewname
	 * 
	 * @param layout
	 */
	private void createLayoutViewname(GridLayout layout) {
		Group grNames = new Group(composite, SWT.NONE);
		grNames.setText(PluginProperties.editor_group_viewname);
		grNames.setFont(FontUtil.getSystemStyle(SWT.BOLD));
		grNames.setLayout(layout);
		GridData data = new GridData();

		grNames.setLayoutData(data);

		Label name = new Label(grNames, 0);
		name.setText(PluginProperties.editor_fieldname_viewname);
		name.setVisible(true);

		viewName = new Text(grNames, SWT.BORDER);
		{
			data.horizontalAlignment = GridData.BEGINNING;
			data.grabExcessHorizontalSpace = true;
			data.horizontalSpan = 1;
			data.widthHint = 335;
			viewName.setLayoutData(data);
		}

		viewName.setSize(285, 15);
		viewName.setText(ViewEcoreManager.getInstance().getName());
		viewName.setVisible(true);

		viewName.addKeyListener(new KeyListener() {

			public void keyPressed(KeyEvent arg0) {
				setDirty(true);
			}

			public void keyReleased(KeyEvent arg0) {
				setDirty(true);
			}

		});

		grNames.setVisible(true);
	}

	/**
	 * Creates the Table for the E-Classes
	 * 
	 * @param layout
	 * @param data
	 */
	private void createLayoutTable(GridLayout layout, GridData data) {
		Group grTables = new Group(composite, SWT.NONE);
		grTables.setText(PluginProperties.editor_group_properties);
		grTables.setFont(FontUtil.getSystemStyle(SWT.BOLD));
		grTables.setLayout(layout);
		grTables.setLayoutData(data);

		table = new Table(grTables, SWT.SINGLE | SWT.BORDER
				| SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL);
		table.setLayoutData(new GridData(SWT.NONE, SWT.FILL, true, true));
		table.setHeaderVisible(true);
		table.setLinesVisible(true);
		table.setSize(300, 800);

		TableColumn columnProp = new TableColumn(table, SWT.NONE, 0);
		columnProp.setText(PluginProperties.editor_properties_tableColumn);// "Properties"
		columnProp.setWidth(250);

		TableColumn columnAct = new TableColumn(table, SWT.NONE, 1);
		columnAct.setWidth(50);

		// selectionListener for the table
		table.addSelectionListener(new SelectionListener() {
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			public void widgetSelected(SelectionEvent e) {
				selectedRow = table.getSelectionIndex();
				ViewItemWrapper obj = itemtabledata.get(selectedRow);
				attributes = ViewEcoreManager.getInstance().getAttributesList(
						obj);
			}
		});

		// notifies all views, that something in editor has changed
		TableViewer tableviewer = new TableViewer(table);
		getSite().setSelectionProvider(tableviewer);
	}

	/**
	 * Reads out the absolute path to the file, depending on the editor-input
	 * type.
	 */
	private void getPathToFile() {
		URI fileName;

		// get the right-editor input of the view-file
		if (getEditorInput() instanceof IFileEditorInput) {
			// open views that are shown after the current view has been closed
			FileEditorInput f = (FileEditorInput) this.getEditorInput();
			currentfile = new File(f.getPath().toFile().getAbsolutePath());
		} else if (getEditorInput() instanceof FileStoreEditorInput) {
			// open views at programm start
			// views opened by select from the file-menu (recently opened files)
			// views opened by file -> new
			fileName = URI
					.createFileURI(((FileStoreEditorInput) getEditorInput())
							.getURI().getPath());
			currentfile = new File(fileName.toFileString());
		}

	}

	/**
	 * Sets the path to the ecore-file.
	 */
	private void getPathToEcoreFile() {
		org.eclipse.jwt.meta.Plugin plugin = org.eclipse.jwt.meta.Plugin
				.getDefault();
		Bundle bundle = plugin.getBundle();
		ecorePath = bundle
				.getResource("/org/eclipse/jwt/meta/ecore/JWTMetaModel.ecore"); //$NON-NLS-1$
	}

	/**
	 * Simply reload the table with the EClasses.
	 * 
	 */
	private void reloadTables() {
		itemtabledata = ViewEcoreManager.getInstance().getItemsList();
		data = new Object[itemtabledata.size()][2];

		for (int i = 0; i < itemtabledata.size(); i++) {
			// name of the property
			data[i][0] = itemtabledata.get(i);
			// value of the property
			data[i][1] = itemtabledata.get(i).getValue();

			final int p = i;
			final Button buttonCheck = new Button(table, SWT.CHECK);

			// selectionListener for the checkbuttons
			buttonCheck.addSelectionListener(new SelectionListener() {
				public void widgetDefaultSelected(SelectionEvent e) {
				}

				public void widgetSelected(SelectionEvent e) {
					setDirty(true);

					ViewItemWrapper viw = (ViewItemWrapper) data[p][0];
					boolean value = buttonCheck.getSelection();
					ViewEcoreManager.getInstance().setDisplay(viw, value);
				}
			});

			// create editor input with property name and value of the checkbox
			// for each item
			TableItem item = new TableItem(table, SWT.NULL);
			TableEditor editor = new TableEditor(table);
			editor.grabHorizontal = true;
			editor.minimumHeight = buttonCheck.getSize().x;
			editor.minimumWidth = buttonCheck.getSize().y;
			editor.setEditor(buttonCheck, item, 1);

			item.setText(0, (data[i][0]).toString());

			if ((data[i][1]).equals(true)) {
				buttonCheck.setSelection(true);
			} else {
				buttonCheck.setSelection(false);
			}

			item.setData(buttonCheck);
		}
	}

	public boolean isDirty() {
		return dirty;
	}

	public void setDirty(boolean dirty) {
		this.dirty = dirty;
		firePropertyChange(PROP_DIRTY);
	}

	/**
	 * Closes the editor
	 */
	public void dispose() {
		super.dispose();
	}

	/**
	 * Saves the editor's document.
	 */
	public void doSave(IProgressMonitor monitor) {
		final IPath path = new Path(currentfile.getAbsolutePath());
		String pathtofile = path.makeAbsolute().toFile().getAbsolutePath();
		pathtofile = pathtofile.replace("\\", "/"); //$NON-NLS-1$//$NON-NLS-2$

		if (viewName.getText().length() == 0) {
			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title,
					PluginProperties.editor_ErrorMissingViewName_message);

			return;

		}

		ViewEcoreManager.getInstance().setName(viewName.getText());
		ViewEcoreManager.getInstance().savetoFile(new File(pathtofile));
		setDirty(false);
	}

	/**
	 * Saves the editor's document as another file. Also updates the text for
	 * page 0's tab, and updates this editor's input to correspond to the nested
	 * editor's.
	 */
	public void doSaveAs() {
		Shell shell = getSite().getWorkbenchWindow().getShell();

		// error-message, if no view name is set in editor
		if (viewName.getText().length() == 0) {
			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title,
					PluginProperties.editor_ErrorMissingViewName_message);

			return;

		}

		FileDialog fd = new FileDialog(shell, SWT.SAVE);
		String selectedfile = null;

		try {
			// set the standard file name
			fd.setFileName(getEditorInput().getName());

			// set the filter extensions
			fd.setFilterExtensions(new String[] { "*." + extension }); //$NON-NLS-1$
			selectedfile = fd.open();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		// return, if the dialog was aborted
		if (selectedfile == null) {
			return;
		}

		// the file
		final IPath path = new Path(selectedfile);
		final File file = path != null ? path.toFile() : null;

		// return, if file could not be created
		if (file == null) {
			MessageDialog.openError(getEditorSite().getShell(),
					PluginProperties.editor_ErrorMessage_title,
					PluginProperties.editor_ErrorSavingFile_message);

			return;
		}
		// return, if destination file is currently open
		IWorkbenchPage workbenchPage = Plugin.getInstance().getWorkbench()
				.getActiveWorkbenchWindow().getActivePage();

		for (IEditorReference editorReference : workbenchPage
				.getEditorReferences()) {
			String openFileName = ""; //$NON-NLS-1$
			try {
				if (editorReference.getEditorInput() instanceof URIEditorInput) {
					openFileName = ((URIEditorInput) editorReference
							.getEditorInput()).getURI().toFileString();
				} else if (editorReference.getEditorInput() instanceof FileStoreEditorInput) {
					openFileName = URI.createFileURI(
							((FileStoreEditorInput) editorReference
									.getEditorInput()).getURI().getPath())
							.toFileString();
				} else {
					openFileName = editorReference.getEditorInput().getName();
				}
			} catch (PartInitException e) {
			}

			if (openFileName.equals(selectedfile)) {
				MessageDialog.openError(getEditorSite().getShell(),
						PluginProperties.editor_ErrorMessage_title,
						PluginProperties.editor_ErrorCurrentlyOpen_message);
				return;
			}
		}

		// return, if the file already exists and should not be overwritten
		if (file.exists()
				&& !MessageDialog.openQuestion(getEditorSite().getShell(),
						PluginProperties.editor_QuestionOverwriteFile_title,
						PluginProperties.editor_QuestionOverwriteFile_message)) {
			return;
		}

		String pathtofile = path.makeAbsolute().toFile().getAbsolutePath();
		pathtofile = pathtofile.replace("\\", "/"); //$NON-NLS-1$//$NON-NLS-2$

		// set new view-name, it may have changed
		ViewEcoreManager.getInstance().setName(viewName.getText());

		ViewEcoreManager.getInstance().savetoFile(new File(pathtofile));
		setDirty(false);

		// *************************
		// TODO this doesn't work :(
		// *************************
		// add to recent files
		if (getEditorInput() instanceof URIEditorInput) {
			if (((URIEditorInput) getEditorInput()).getURI().toFileString() != null) {
				// file string
				RecentFilesListManager.getInstance().setNewFile(
						((URIEditorInput) getEditorInput()).getURI()
								.toFileString());
			} else {
				// url string
				RecentFilesListManager.getInstance()
						.setNewFile(
								((URIEditorInput) getEditorInput()).getURI()
										.toString());
			}
		} else {
			// other
			RecentFilesListManager.getInstance().setNewFile(
					URI.createURI(getEditorInput().getName()).toFileString());
		} // Create a dummy resource for this file.
	}

	/**
	 * Inits the editor-input and sets the PartName.
	 */
	public void init(IEditorSite site, IEditorInput editorInput) {
		try {
			super.init(site, editorInput);
			this.setPartName(editorInput.getName());
		} catch (PartInitException e) {
			e.printStackTrace();
		}
	}

	/**
	 * To get the E-Class selected in table.
	 * 
	 * @param selectedRow
	 * @return selected E-Class
	 */
	public ViewItemWrapper getItemtabledata(int selectedRow) {
		return (ViewItemWrapper) itemtabledata.get(selectedRow);
	}

	/**
	 * To get the list of attributes corresponding to the selected E-Class.
	 * 
	 * @return list of attributes
	 */
	public List<ViewItemWrapper> getListOfAttributes() {
		return attributes;
	}

	/**
	 * Is the selected E-Class enabled or disabled.
	 * 
	 * @return value of checkbox
	 */
	public Object getItemValue() {
		return data[selectedRow][1];
	}

	/**
	 * To get the path to the ecore file.
	 * 
	 * @return ecore-path
	 */
	public URL getEcorePath() {
		return ecorePath;
	}

	public boolean isSaveAsAllowed() {
		return true;
	}

	public void setChangesFromView(Object dataView, boolean value) {
		ViewItemWrapper viw = (ViewItemWrapper) dataView;
		ViewEcoreManager.getInstance().setDisplay(viw, value);
	}
}
