/*
 * 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.application;

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

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.WizardPage;
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.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;

import org.maskat.ui.ISharedImages;
import org.maskat.ui.MaskatNature;
import org.maskat.ui.MaskatUIPlugin;
import org.maskat.ui.Messages;

public class NewMaskatApplicationWizardPage extends WizardPage {

	public static final String DEFAULT_APPLICATION_NAME
		= ""; //$NON-NLS-1$
	public static final String DEFAULT_HTML_TITLE_NAME
		= "New Maskat Application"; //$NON-NLS-1$
	
	private Text directory;
	
	private Text applicationName;
	
	private Text htmlTitle;

	private ISelection selection;
	
	private CheckboxTableViewer viewer;

	public NewMaskatApplicationWizardPage(String pageName, ISelection selection) {
		super(pageName);
		this.selection = selection;
	}

	public void createControl(Composite parent) {
		Composite composite = new Composite(parent, SWT.NULL);
		composite.setLayout(new GridLayout(3, false));
		
		Label dirLabel = new Label(composite, SWT.NULL);
		dirLabel.setText(Messages.getString("wizard.application.label.dir")); //$NON-NLS-1$

		directory = new Text(composite, SWT.BORDER);
		directory.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
		directory.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				setPageComplete(validatePage());
			}
		});
		
		Button button = new Button(composite, SWT.PUSH);
		button.setText(Messages.getString("wizard.application.button.browse")); //$NON-NLS-1$
		button.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				handleBrowse();
			}
		});	
		Label appLabel = new Label(composite, SWT.NULL);
		appLabel.setText(Messages.getString("wizard.application.label.appname")); //$NON-NLS-1$
		
		applicationName = new Text(composite, SWT.BORDER);
		GridData appGridData = new GridData(GridData.FILL_HORIZONTAL);
		appGridData.horizontalSpan = 2;
		applicationName.setLayoutData(appGridData);
		applicationName.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				setPageComplete(validatePage());
			}
		});

		Label htmlLabel = new Label(composite, SWT.NULL);
		htmlLabel.setText(Messages.getString("wizard.application.label.title")); //$NON-NLS-1$	
		htmlTitle = new Text(composite, SWT.BORDER);
		GridData htmlGridData = new GridData(GridData.FILL_HORIZONTAL);
		htmlGridData.horizontalSpan = 2;		
		htmlTitle.setLayoutData(htmlGridData);		
		htmlTitle.addModifyListener(new ModifyListener() {
			public void modifyText(ModifyEvent e) {
				setPageComplete(validatePage());
			}
		});
		
		Label createLabel = new Label(composite, SWT.NULL);
		GridData crGridData = new GridData(GridData.VERTICAL_ALIGN_BEGINNING);
		crGridData.horizontalSpan = 3;
		applicationName.setLayoutData(appGridData);	
		createLabel.setText(Messages.getString(
				"wizard.application.label.createfile")); //$NON-NLS-1$		
		viewer = CheckboxTableViewer.newCheckList(composite, SWT.FULL_SELECTION | SWT.BORDER);

		Table table = viewer.getTable();
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.horizontalSpan = 3;
		table.setLayoutData(gridData);		
		table.setHeaderVisible(true);
		table.setLinesVisible(true);

	    TableColumn typeColumn = new TableColumn(table,SWT.CENTER);
	    typeColumn.setText(Messages.getString(
	    		"wizard.application.label.type")); //$NON-NLS-1$
	    typeColumn.setWidth(180);	
	    TableColumn nameColumn = new TableColumn(table,SWT.LEFT );
	    nameColumn.setText(Messages.getString(
	    		"wizard.application.label.filename")); //$NON-NLS-1$
	    nameColumn.setWidth(120);
	    TableColumn discColumn = new TableColumn(table,SWT.LEFT);
	    discColumn.setText(Messages.getString(
	    		"wizard.application.label.description")); //$NON-NLS-1$
	    discColumn.setWidth(200);	    
	    
		viewer.setContentProvider(new ArrayContentProvider());
		viewer.setLabelProvider(new CreateFileListLabelProvider());
		viewer.setInput(createTableObjects());
		viewer.setAllChecked(true);
		
	    viewer.setCellEditors(new CellEditor[] {
	    		null, new TextCellEditor(table), null});
	    
	    viewer.setColumnProperties(new String[] {
	    		"summary", "fileName", "description"}); //$NON-NLS-1$
	    
	    viewer.setCellModifier(new CreateFileCellModifier(viewer));
	    
		setControl(composite);
		initialize();
		
        setPageComplete(validatePage());
        setErrorMessage(null);
        setMessage(null);
		
	}

	private void initialize() {
		if (selection != null && selection.isEmpty() == false
				&& selection instanceof IStructuredSelection) {
			IStructuredSelection ssel = (IStructuredSelection) selection;
			if (ssel.size() > 1) {
				return;
			}
			Object obj = ssel.getFirstElement();
			if (obj instanceof IResource) {
				IContainer container;
				if (obj instanceof IContainer) {
					container = (IContainer) obj;
				} else {
					container = ((IResource) obj).getParent();
				}
				directory.setText(container.getFullPath().toString());
			}
		}
		applicationName.setText(DEFAULT_APPLICATION_NAME);
		htmlTitle.setText(DEFAULT_HTML_TITLE_NAME);
	}	
	
	private Object createTableObjects() {
		return new CreateFileData[] {
				new CreateFileData("container",
					Messages.getString("wizard.application.container.filename"), //$NON-NLS-1$
					"index.html", null, //$NON-NLS-1$
					Messages.getString("wizard.application.container.description")), //$NON-NLS-1$
				new CreateFileData("transition", //$NON-NLS-1$
					Messages.getString("wizard.application.transition.filename"), //$NON-NLS-1$
					"transition.xml", "xml", //$NON-NLS-1$
					Messages.getString("wizard.application.transition.description")), //$NON-NLS-1$
				new CreateFileData("layout", //$NON-NLS-1$
					Messages.getString("wizard.application.layout.filename"), //$NON-NLS-1$
					"layout.xml", "xml", //$NON-NLS-1$
					Messages.getString("wizard.application.layout.description")), //$NON-NLS-1$
				new CreateFileData("event", //$NON-NLS-1$
					Messages.getString("wizard.application.event.filename"), //$NON-NLS-1$
					"layout_e.xml", "xml",//$NON-NLS-1$
					Messages.getString("wizard.application.event.description")) //$NON-NLS-1$
		};
	}
	
	private void handleBrowse() {
		ContainerSelectionDialog dialog = new ContainerSelectionDialog(getShell(),
				ResourcesPlugin.getWorkspace().getRoot(), true,
				Messages.getString("wizard.application.browse.title")); //$NON-NLS-1$
		if (dialog.open() == Window.OK) {
			Object[] result = dialog.getResult();
			if (result.length == 1) {
				directory.setText(((Path) result[0]).toString());
			}
		}
	}	

	public void dispose() {
		super.dispose();
	}
	
	private boolean validatePage() {
		String dirPath = directory.getText();
		if (dirPath == null || dirPath.length() == 0) {
			setErrorMessage(Messages.getString(
					"wizard.application.msg.error.notdir")); //$NON-NLS-1$
			directory.setFocus();
			directory.selectAll();
			return false;
		}
		IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
		IResource dir = root.findMember(new Path(dirPath));
		if (dir == null || !dir.exists()) {
			setErrorMessage(directory.getText() + Messages.getString(
					"wizard.application.msg.error.notexistdir")); //$NON-NLS-1$
			directory.setFocus();
			return false;
		}
		IProject project = dir.getProject();
		if (project == null || MaskatNature.getNature(project) == null) {
			setErrorMessage(directory.getText() + Messages.getString(
					"wizard.application.msg.error.invalidproject")); //$NON-NLS-1$
			directory.setFocus();
			return false;			
		}
		String appName = applicationName.getText();
		if (appName == null || appName.length() == 0) {
			setErrorMessage(Messages.getString(
					"wizard.application.msg.error.notapp")); //$NON-NLS-1$
			applicationName.setFocus();
			return false;
		}
		IWorkspace workspace = IDEWorkbenchPlugin.getPluginWorkspace();
        IStatus nameStatus = workspace.validateName(appName, IResource.FOLDER);
        if (!nameStatus.isOK()) {
        	setErrorMessage(nameStatus.getMessage());
			applicationName.setFocus();
			return false;
		}
		StringBuffer sb = new StringBuffer(dirPath);
		sb.append(File.separator).append(appName);
		IResource app = root.findMember(new Path(sb.toString()));
		if (app != null && app.exists()) {		
			setErrorMessage(Messages.getString(
					"wizard.application.msg.error.alreadyexists.app")); //$NON-NLS-1$
			applicationName.setFocus();
			return false;
		}
		String title = htmlTitle.getText();
		if (title == null || title.length() == 0) {
			setErrorMessage(Messages.getString(
					"wizard.application.msg.error.nothtml")); //$NON-NLS-1$
			htmlTitle.setFocus();
			return false;
		}
		ArrayList nameList = new ArrayList();
		CreateFileData[] datas = (CreateFileData[]) viewer.getInput();
		for (int i = 0; i < datas.length; i++) {
			String name = datas[i].fileName;
			if (name == null || name.length() == 0) {
				setErrorMessage(Messages.getString(
						"wizard.application.msg.error.notfilename")); //$NON-NLS-1$
				viewer.getTable().setFocus();
				return false;
			}
	        IStatus status = workspace.validateName(name, IResource.FILE);
	        if (!status.isOK()) {
	        	setErrorMessage(status.getMessage());
				viewer.getTable().setFocus();
				return false;
			}
			int dotLoc = name.lastIndexOf('.'); //$NON-NLS-1$
			if (dotLoc != -1) {
				String ext = name.substring(dotLoc + 1);
				if (datas[i].extension != null) {
					if (ext.equalsIgnoreCase(datas[i].extension) == false) {
						setErrorMessage(Messages.getString(
							"wizard.application.msg.error.filename.invalidextension")); //$NON-NLS-1$
						viewer.getTable().setFocus();
						return false;
					}
				}
			} else if (datas[i].extension != null) {
				setErrorMessage(Messages.getString(
					"wizard.application.msg.error.filename.invalidextension")); //$NON-NLS-1$
				viewer.getTable().setFocus();
				return false;
			}
			if (nameList.contains(name)) {
				setErrorMessage(Messages.getString(
						"wizard.application.msg.error.filename.samename")); //$NON-NLS-1$
				viewer.getTable().setFocus();
				return false;	
			}
			nameList.add(name);
		}
		setErrorMessage(null);
		return true;
	}	
	
	private class CreateFileData {
		public String propertyName;
		public String summary;
		public String fileName;
		public String extension;
		public String description;
	
		public CreateFileData(String p, String s, String f,  String e, String d) {
			propertyName = p;
			summary = s;
			fileName = f;
			extension = e;
			description = d;
		}
	}
	
	public class CreateFileListLabelProvider extends LabelProvider
		implements ITableLabelProvider {

		private Image maskatImage =
				MaskatUIPlugin.getImage(ISharedImages.IMG_WIZBAN_MASKATFILE);
		private Image htmlImage =
				MaskatUIPlugin.getImage(ISharedImages.IMG_WIZBAN_HTMLFILE);
		
		public Image getColumnImage(Object element, int columnIndex) {
			Image img = null;
			if (columnIndex == 0) {
				CreateFileData data = (CreateFileData) element;
				if ("container".equals(data.propertyName)) {
					img = htmlImage;
				} else {
					img = maskatImage;
				}
			}
			return img;
		}

		public String getColumnText(Object element, int columnIndex) {
			CreateFileData data = (CreateFileData) element;
			switch (columnIndex) {
			case 0:
				return data.summary;
			case 1:
				return data.fileName;				
			case 2:
				return data.description;				
			}
			return null;			
		}
	}
	
	public class CreateFileCellModifier implements ICellModifier {
		private TableViewer viewer;
		
		public CreateFileCellModifier(TableViewer viewer) {
			this.viewer = viewer;
		}
		
		public boolean canModify(Object element, String property) {
			if ("fileName".equals(property)) { //$NON-NLS-1$
				CreateFileData data = (CreateFileData) element;
				if ("event".equals(data.propertyName)) { //$NON-NLS-1$
					return false;
				}
				return true;
			}
			return false;
		}
		
		public Object getValue(Object element, String property) {
			CreateFileData data = (CreateFileData) element;
			if ("summary".equals(property)) { //$NON-NLS-1$
				return data.summary;
			} else if ("fileName".equals(property)) { //$NON-NLS-1$
				return data.fileName;				
			} else if ("description".equals(property)) { //$NON-NLS-1$
				return data.description;				
			}
			return null;
		}
		
		public void modify(Object element, String property, Object value) {
			if ("fileName".equals(property)) { //$NON-NLS-1$
			    if (element instanceof Item) {
			        element = ((Item) element).getData();
			    }
			    CreateFileData data = (CreateFileData) element;
			    data.fileName = (String) value;
				viewer.update(element, null);
				
				if ("layout".equals(data.propertyName)) { //$NON-NLS-1$
					CreateFileData d = getCreateFileData("event"); //$NON-NLS-1$
					d.fileName = getEventFileName(data.fileName);
					viewer.update(d, null);
				}
			    setPageComplete(validatePage());
			}
		}
	}

	public String getDirectory() {
		return directory.getText();
	}
	
	public String getApplicationName() {
		return applicationName.getText();
	}
	
	public String getHtmlTitle() {
		return htmlTitle.getText();
	}
	
	public String getContainerFileName() {
		return getCreateFileData("container").fileName; //$NON-NLS-1$
	}
	
	public String getTransitionFileName() {
		return getCreateFileData("transition").fileName; //$NON-NLS-1$
	}

	public String getLayoutFileName() {
		return getCreateFileData("layout").fileName; //$NON-NLS-1$
	}

	public String getEventFileName() {
		return getCreateFileData("event").fileName; //$NON-NLS-1$
	}
	
	public boolean isSelectedContainerFile() {
		return getSelectedFileName("container"); //$NON-NLS-1$
	}

	public boolean isSelectedTransitionFile() {
		return getSelectedFileName("transition"); //$NON-NLS-1$
	}
	
	public boolean isSelectedLayoutFile() {
		return getSelectedFileName("layout"); //$NON-NLS-1$
	}
	
	public boolean isSelectedEventFile() {
		return getSelectedFileName("event"); //$NON-NLS-1$
	}
	
	private boolean getSelectedFileName(String key) {
		Object[] select = viewer.getCheckedElements();
		if (select != null) {
			for (int i = 0; i < select.length; i++) {
				if (key.equals(((CreateFileData) select[i]).propertyName)) {
					return true;
				}
			}
		}
		return false;
	}
	
	private CreateFileData getCreateFileData(String key) {
		CreateFileData[] data = (CreateFileData[]) viewer.getInput();
		for (int i = 0; i < data.length; i++) {
			if (key.equals(data[i].propertyName)) {		
				return data[i];
			}
		}
		return null;
	}

	private String getEventFileName(String layoutName) {
		String[] v = layoutName.split("\\."); //$NON-NLS-1$
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < v.length; i++) {
			if (i == v.length - 1) {
				sb.append("_e."); //$NON-NLS-1$
			}
			sb.append(v[i]);
		}
		return sb.toString();
	}
}
