/*
 * Copyright (c) 2006-2008 Maskat Project.
 *
 * 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:
 *     Maskat Project - initial API and implementation
 */
package org.maskat.ui.wizards.export;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
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.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.dialogs.ContainerCheckedTreeViewer;
import org.maskat.core.betwixt.MaskatBeanIO;
import org.maskat.core.event.Component;
import org.maskat.core.event.Event;
import org.maskat.core.event.EventDef;
import org.maskat.core.event.EventElement;
import org.maskat.core.event.EventRef;
import org.maskat.core.event.Param;
import org.maskat.core.event.Result;
import org.maskat.ui.ISharedImages;
import org.maskat.ui.MaskatUIPlugin;
import org.maskat.ui.Messages;

public class ExportMessageSchemaDialogArea extends Composite {

    private Text eventFilePath;
	
    private Text outputFilePath;
    
    private boolean valid;
	
	private String errorMessage;
	
	private IResource initPath;

	private Tree exportEventTree = null;

	private ContainerCheckedTreeViewer exportEventTreeViewer = null;
	
	private HashMap refMap = new HashMap();
	
	public ExportMessageSchemaDialogArea(Composite parent, int style, IResource path) {
		super(parent, style);
		initPath = path;
		createControl();
	}
	
	private void createControl() {
		setLayout(new GridLayout(4, false));
		setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		
		Label dirLabel = new Label(this, SWT.NULL);
		dirLabel.setText(Messages.getString(
			"exportSchemaWizard.label.eventName")); //$NON-NLS-1$				
		
		eventFilePath = new Text(this, SWT.BORDER);
		eventFilePath.setEditable(false);
		GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
		gridData.horizontalSpan = 2;
		eventFilePath.setLayoutData(gridData);
		Button button = new Button(this, SWT.PUSH);
		button.setText(Messages.getString(
			"exportSchemaWizard.button.browse")); //$NON-NLS-1$	
	
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				IResource file = inputHandleBrowse();
				if (file != null) {
					eventFilePath.setText(file.getFullPath().toString());
					createEventTreeView(file);
					setValid(validatePage());
				}
			}
		});	
		if (initPath == null) {
			button.setEnabled(false);
		}
		
		Label selectLabel = new Label(this, SWT.NULL);
		selectLabel.setText(Messages.getString(
			"exportSchemaWizard.label.selectEvent")); //$NON-NLS-1$		

		GridData treeData = new GridData();
		treeData.horizontalAlignment = GridData.FILL;
		treeData.horizontalSpan = 4;
		treeData.grabExcessVerticalSpace = true;
		treeData.grabExcessHorizontalSpace = true;
		treeData.verticalAlignment = GridData.FILL;	
		
		exportEventTree = new Tree(this, SWT.CHECK | SWT.BORDER);
		exportEventTree.setHeaderVisible(false);
		exportEventTree.setLayoutData(treeData);
		exportEventTreeViewer = new ContainerCheckedTreeViewer(exportEventTree);
		exportEventTreeViewer.setContentProvider(new EvnetContentProvider());
		exportEventTreeViewer.setLabelProvider(new EventLabelProvider());

		exportEventTreeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent selectionChangedEvent) {
			}
		});
		Label outDirLabel = new Label(this, SWT.NULL);
		outDirLabel.setText(Messages.getString(
			"exportSchemaWizard.label.outputDirectory")); //$NON-NLS-1$				
		
		outputFilePath = new Text(this, SWT.BORDER);
		GridData outData = new GridData(GridData.FILL_HORIZONTAL);
		outData.horizontalSpan = 2;
		outputFilePath.setLayoutData(outData);
		outputFilePath.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				setValid(validatePage());
			}
		});	
		Button outBrowsen = new Button(this, SWT.PUSH);
		outBrowsen.setText(Messages.getString(
			"exportSchemaWizard.button.browse.output")); //$NON-NLS-1$	
		
		outBrowsen.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				String path = outputHandleBrowse();
				if (path != null) {
					outputFilePath.setText(path);
					setValid(validatePage());
				}
			}
		});
	}
	
	public void initialize() {
		eventFilePath.setText(initPath == null ? "" : initPath.getFullPath().toString());
		outputFilePath.setText("");
		createEventTreeView(initPath);
        setErrorMessage(null);
	}
	
	private void createEventTreeView(IResource resouce) {
		if (resouce != null && resouce.getType() == IResource.FILE) {
			try {
				EventDef eventDef = MaskatBeanIO.readEventDef(
						((IFile) resouce).getLocationURI().getPath());
				if (eventDef == null) {
					exportEventTreeViewer.setInput(null);
				} else {
					setEventRefElements(eventDef);
					exportEventTreeViewer.setInput(eventDef);
					exportEventTreeViewer.expandAll();
					exportEventTreeViewer.setAllChecked(true);
				}
				
			} catch (Exception e) {
				exportEventTreeViewer.setInput(null);
				MaskatUIPlugin.log(new Status(IStatus.ERROR,
						MaskatUIPlugin.PLUGIN_ID, IStatus.ERROR, e
								.getMessage(), e));
			}
		}
	}
	
	private void setEventRefElements(EventDef eventDef) {
		for (Iterator ite = eventDef.getChildren(); ite != null && ite.hasNext();) {
			Object obj = ite.next();
			if (obj instanceof EventRef) {
				EventRef ref = (EventRef) obj;
				refMap.put(ref.getRefid(), ref);
			}
		}
		
	}

	
	private IResource inputHandleBrowse() {
		XMLSchemaSelectionDialog dialog = new XMLSchemaSelectionDialog(getShell(),
				initPath, Messages.getString("exportSchemaWizard.browse.title")); //$NON-NLS-1$
		if (dialog.open() == IDialogConstants.OK_ID) {
			return dialog.getSelectEventXMLFile();
		}
		return null;
	}
	
	private String outputHandleBrowse() {
		String init = (initPath == null) ?
				"" : initPath.getLocation().toString(); //$NON-NLS-1$
		
		DirectoryDialog selectionDialog = new DirectoryDialog(getShell());
		selectionDialog.setFilterPath(init);
		return selectionDialog.open();
	}

	private class EvnetContentProvider implements ITreeContentProvider {

		public Object[] getChildren(Object parentElement) {
			ArrayList list = new ArrayList();
			EventElement element = (EventElement) parentElement;
			if (parentElement != null) { 
				for (Iterator ite = element.getChildren(); ite != null && ite.hasNext();) {
					Object obj = ite.next();
					if ((obj instanceof Component || obj instanceof Event) &&
						!(obj instanceof EventRef)) {
						list.add(obj);
					}
				}
			}
			return list.toArray();
		}

		public Object getParent(Object element) {
			EventElement parentElement = (EventElement) element;
			return parentElement.getParent();
		}

		public boolean hasChildren(Object element) {
			return (element instanceof Component);
		}

		public Object[] getElements(Object inputElement) {
			return getChildren(inputElement);
		}

		public void dispose() {}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
	}

	private class EventLabelProvider extends LabelProvider {
		Image evnetImage = MaskatUIPlugin.getImage(ISharedImages.IMG_COMPONENT_TEXT);
		
		public String getText(Object element) {
			EventElement e = (EventElement) element;
			if (e instanceof Event) {
				return ((Event) e).getId();
			} else if (e instanceof Component) {
				return ((Component) e).getId();
			}
			return null;
		}

		public Image getImage(Object element) {
			return evnetImage;
		}

	}
		
	public boolean isValid() {
		return valid;
	}
	
	public void setValid(boolean valid) {
		this.valid = valid;
	}
	
	public String getErrorMessage() {
		return errorMessage;
	}

	public void setErrorMessage(String newMessage) {
		this.errorMessage = newMessage;
	}
	
	public boolean validatePage() {
		String path = outputFilePath.getText();
		if (path == null || path.length() == 0) {
			setErrorMessage(Messages.getString(
					"exportSchemaWizard.msg.error.notdir")); //$NON-NLS-1$
			outputFilePath.setFocus();
			return false;
		}
		if (!(new File(path)).isDirectory()) {
			setErrorMessage(Messages.getString(
					"exportSchemaWizard.msg.error.invaliddir")); //$NON-NLS-1$
			outputFilePath.setFocus();
			return false;
		}
		if (!isWriteDirectory(new File(path))) {
			setErrorMessage(Messages.getString(
					"exportSchemaWizard.msg.error.nowritedir")); //$NON-NLS-1$
			outputFilePath.setFocus();
			return false;			
		}
		Object[] selected = exportEventTreeViewer.getCheckedElements();
		if (selected.length <= 0) {
			setErrorMessage(Messages.getString(
					"exportSchemaWizard.msg.error.notselected")); //$NON-NLS-1$
			return false;				
		}
        setErrorMessage(null);
		return true;
	}
	
	private boolean isWriteDirectory(File dir) {
		if (!dir.isDirectory()) {
			return false;
		}
		try {
			File tmp = File.createTempFile("_maskat", null, dir); //$NON-NLS-1$
			tmp.delete();
		} catch (Exception e) {
			return false;
		}
		return true;
	}
	
	public void setEventFilePath(String path) {
		eventFilePath.setText(path);
	}
	
	public String getEventFilePath() {
		return eventFilePath.getText();
	}

	public void setOutputFilePath(String path) {
		outputFilePath.setText(path);
	}
	
	public String getOutputFilePath() {
		return outputFilePath.getText();
	}
	
	public ExportMessage[] getSelectedMessages() {
		Object[] selected = exportEventTreeViewer.getCheckedElements();
		ArrayList list = new ArrayList();
		
		for (int i = 0; i < selected.length; i++) {	
			EventElement element = (EventElement) selected[i];
			if (element instanceof Event) {
				Event event = (Event) element;
				String ref = event.getRef();
				if (ref != null) {
					element = (Event) refMap.get(ref);
				}
				for (Iterator ite = element.getChildren(); ite != null && ite.hasNext();) {
					Object obj = ite.next();
					if (obj instanceof Param || obj instanceof Result) {
						list.add(new ExportMessage(event, (EventElement) obj));
					}
				}
			}
		}
		return (ExportMessage[]) list.toArray(new ExportMessage[0]);
	}
}
