package com.xaraya.wizard;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;

import net.sourceforge.phpdt.internal.ui.util.StringUtil;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceStatus;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.ui.actions.WorkspaceModifyOperation;
import org.eclipse.ui.dialogs.ContainerGenerator;
import org.eclipse.ui.help.WorkbenchHelp;
import org.eclipse.ui.internal.IHelpContextIds;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.misc.ResourceAndContainerGroup;

public class XarayaModuleContainerPage extends WizardPage implements Listener {
	private static final int SIZING_CONTAINER_GROUP_HEIGHT = 250;
	private IStructuredSelection currentSelection;
	private IContainer currentParent;
	NewXarayaResourceWizard wizard;
	private IPath newModulePath;
	private IFolder newModule;
	
	// widgets
	private ResourceAndContainerGroup resourceGroup;

public XarayaModuleContainerPage(String pageName, IStructuredSelection selection) {
	super(XarayaModuleMessages.getString("Xaraya.label.container"));
	setTitle(pageName);
	setDescription(XarayaModuleMessages.getString("Xaraya.label.container")); 
	this.currentSelection = selection;
}

public void createControl(Composite parent) {
	initializeDialogUnits(parent);
	// top level group
	Composite composite = new Composite(parent,SWT.NONE);
	composite.setFont(parent.getFont());
	composite.setLayout(new GridLayout());
	composite.setLayoutData(new GridData(
		GridData.VERTICAL_ALIGN_FILL | GridData.HORIZONTAL_ALIGN_FILL));

	WorkbenchHelp.setHelp(composite, IHelpContextIds.NEW_FOLDER_WIZARD_PAGE);

	resourceGroup = new ResourceAndContainerGroup(composite,this,
		XarayaModuleMessages.getString("Xaraya.label.container"),
		XarayaModuleMessages.getString("Xaraya.label.modversionname"),
			false, SIZING_CONTAINER_GROUP_HEIGHT); //$NON-NLS-2$ //$NON-NLS-1$
	resourceGroup.setAllowExistingResources(false);
	initializePage();
	validatePage();
	// Show description on opening
	setErrorMessage(null);
	setMessage(null);
	setControl(composite);
}

protected void createFolder(IFolder folderHandle, IProgressMonitor monitor) throws CoreException {
    try {
        // Create the folder resource in the workspace
        // Update: Recursive to create any folders which do not exist already
        if (!folderHandle.exists()) {
            IContainer parent= folderHandle.getParent();
            if (parent instanceof IFolder && (!((IFolder)parent).exists())) {
                createFolder((IFolder)parent, monitor);
            }
        		folderHandle.create(false, true, monitor);
        }
    }
    catch (CoreException e) {
        // If the folder already existed locally, just refresh to get contents
        if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
            folderHandle.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 500));
        else
            throw e;
    }

    if (monitor.isCanceled())
        throw new OperationCanceledException();
}

protected IFolder createFolderHandle(IPath folderPath) {
	return WorkbenchPlugin.getPluginWorkspace().getRoot().getFolder(folderPath);
}

public IFolder createNewModuleFolder() {
	if (newModule != null)
		return newModule;

	// create the new folder and cache it if successful
	final IPath containerPath = resourceGroup.getContainerFullPath();
	newModulePath = containerPath.append(resourceGroup.getResource());
	final IFolder newModuleHandle = createFolderHandle(newModulePath);

	WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
		public void execute(IProgressMonitor monitor) throws CoreException {
			try {
				monitor.beginTask(WorkbenchMessages.getString("WizardNewFolderCreationPage.progress"), 2000); //$NON-NLS-1$
				ContainerGenerator generator = new ContainerGenerator(containerPath);
				generator.generateContainer(new SubProgressMonitor(monitor, 1000));
				createFolder(newModuleHandle, new SubProgressMonitor(monitor, 1000));
			} finally {
				monitor.done();
			}
		}
	};

	try {
		getContainer().run(true, true, op);
	} catch (Exception e) {
		return null;
	}
	newModule = newModuleHandle;
	return newModule;
}

public boolean createNewGuiFolder() {
	final IPath containerPath = newModulePath;
	IPath newFolderPath = containerPath.append(XarayaModuleMessages.getString("Xaraya.folder.gui"));
	final IFolder newFolderHandle = createFolderHandle(newFolderPath);

	WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
		public void execute(IProgressMonitor monitor) throws CoreException {
			try {
				monitor.beginTask(WorkbenchMessages.getString("WizardNewFolderCreationPage.progress"), 2000); //$NON-NLS-1$
				ContainerGenerator generator = new ContainerGenerator(containerPath);
				generator.generateContainer(new SubProgressMonitor(monitor, 1000));
				createFolder(newFolderHandle, new SubProgressMonitor(monitor, 1000));
			} finally {
				monitor.done();
			}
		}
	};

	try {
		getContainer().run(true, true, op);
	} catch (Exception e) {
		return false;
	} 
	return true;
}

protected void createFile(IFile fileHandle, InputStream contents, IProgressMonitor monitor) throws CoreException {
	if (contents == null)
		contents = new ByteArrayInputStream(new byte[0]);

	try {
			fileHandle.create(contents, false, monitor);
	}
	catch (CoreException e) {
		// If the file already existed locally, just refresh to get contents
		if (e.getStatus().getCode() == IResourceStatus.PATH_OCCUPIED)
			fileHandle.refreshLocal(IResource.DEPTH_ZERO, null);
		else
			throw e;
	}

	if (monitor.isCanceled())
		throw new OperationCanceledException();
}

protected IFile createFileHandle(IPath filePath) {
	return WorkbenchPlugin.getPluginWorkspace().getRoot().getFile(filePath);
}

public Object[] createNewModuleFiles(){
	ArrayList fileAL = new ArrayList();
	boolean isGuiDirCreated = false;
	fileAL.add(createNewFile(XarayaModuleMessages.getString("Xaraya.files.init")));
	fileAL.add(createNewFile(XarayaModuleMessages.getString("Xaraya.files.version")));
	if (XarayaVersionModel.isAdminApi()) fileAL.add(createNewFile(XarayaModuleMessages.getString("Xaraya.files.adminApi"))); 
	if (XarayaVersionModel.isAdminGui()) {
		fileAL.add(createNewFile(XarayaModuleMessages.getString("Xaraya.files.adminGui")));
		isGuiDirCreated=createNewGuiFolder();
	}  
	if (XarayaVersionModel.isUserApi()) fileAL.add(createNewFile(XarayaModuleMessages.getString("Xaraya.files.userApi")));  
	if (XarayaVersionModel.isUserGui()) {
		fileAL.add(createNewFile(XarayaModuleMessages.getString("Xaraya.files.userGui")));
		if (!isGuiDirCreated) isGuiDirCreated=createNewGuiFolder();	
	} 
	return fileAL.toArray();
}

public IFile createNewFile(String fileName) {
	final IPath containerPath = newModulePath;
	IPath newFilePath = containerPath.append(fileName);
	final IFile newFileHandle = createFileHandle(newFilePath);
	final InputStream initialContents = getInitialContents(fileName);
	WorkspaceModifyOperation op = new WorkspaceModifyOperation() {
		protected void execute(IProgressMonitor monitor) throws CoreException,
			InterruptedException
		{
			try {
				monitor.beginTask("Progress", 2000); //$NON-NLS-1$
				ContainerGenerator generator = new ContainerGenerator(containerPath);
				generator.generateContainer(new SubProgressMonitor(monitor, 1000));
				createFile(newFileHandle,initialContents, new SubProgressMonitor(monitor, 1000));
			} finally {
				monitor.done();
			}
		}
	};

	try {
		getContainer().run(true, true, op);
	} catch (Exception e) {
		return null;
	} 
	return newFileHandle;
}

	protected InputStream getInitialContents(String fileName) {
		StringBuffer inputString = new StringBuffer();
		if (fileName.equals(XarayaModuleMessages.getString("Xaraya.files.init"))) 
			inputString=XarayaModuleText.xarinit;
		if (fileName.equals(XarayaModuleMessages.getString("Xaraya.files.adminGui"))) 
			inputString=XarayaModuleText.xaradmin;
		if (fileName.equals(XarayaModuleMessages.getString("Xaraya.files.adminApi"))) 
			inputString=XarayaModuleText.xaradminapi;
		if (fileName.equals(XarayaModuleMessages.getString("Xaraya.files.userGui"))) 
			inputString=XarayaModuleText.xaruser;
		if (fileName.equals(XarayaModuleMessages.getString("Xaraya.files.userApi"))) 
			inputString=XarayaModuleText.xaruserapi;
		if (fileName.equals(XarayaModuleMessages.getString("Xaraya.files.version"))) 
			inputString=XarayaModuleText.xarversion;
		
		ArrayList inserts = new ArrayList();
		//makes things simpler to just refer to the arraylist...
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.name"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.id"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.version"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.description"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.official"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.author"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.contact"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.admin"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.user"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.securityschema"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.class"));
		inserts.add(XarayaModuleMessages.getString("Xaraya.insert.category"));
	
		ArrayList names = new ArrayList();
		names.add(XarayaVersionModel.getModversionname());
		names.add(XarayaVersionModel.getModversionid());
		names.add(XarayaVersionModel.getModversionversion());
		names.add(XarayaVersionModel.getModversiondescription());
		names.add(XarayaVersionModel.getModversionofficial());
		names.add(XarayaVersionModel.getModversionauthor());
		names.add(XarayaVersionModel.getModversioncontact());
		names.add(XarayaVersionModel.getModversionadmin());
		names.add(XarayaVersionModel.getModversionuser());
		names.add(XarayaVersionModel.getModversionsecurityschema());
		names.add(XarayaVersionModel.getModversionclass());
		names.add(XarayaVersionModel.getModversioncategory());
		
		PipedOutputStream ps = null;
		PipedInputStream is = null;
		String buffer = inputString.toString();		
		for (int i=0; i<inserts.size(); i++)
		{
			String insert = (String)inserts.get(i);
			String replace = (String)names.get(i);
	
      buffer = StringUtil.replaceAll(buffer, insert, replace.toLowerCase());
			try {
				ps = new PipedOutputStream();
				is = new PipedInputStream(ps);
				PrintStream os = new PrintStream(ps);
				os.println(buffer);
				os.close();
			} catch (Exception e) {
				System.out.println("writing to file:"+fileName +"failed with:"+ e);
			}
		}
		return is;
	}
	

public void handleEvent(Event ev) {
	setPageComplete(validatePage());
}

public boolean canFlipToNextPage() {
	return isPageComplete();
}

protected void initializePage() {
	Iterator enum = currentSelection.iterator();
	if (enum.hasNext()) {
		Object next = enum.next();
		IResource selectedResource = null;
		if (next instanceof IResource) {
			selectedResource = (IResource)next;
		} else if (next instanceof IAdaptable) {
			selectedResource = (IResource)((IAdaptable)next).getAdapter(IResource.class);
		}
		if (selectedResource != null) {
			if (selectedResource.getType() == IResource.FILE)
				selectedResource = selectedResource.getParent();
			if (selectedResource.isAccessible())
				resourceGroup.setContainerFullPath(selectedResource.getFullPath());
		}
	}
	setPageComplete(false);
}

public void setVisible(boolean visible) {
	super.setVisible(visible);
	if(visible)
		resourceGroup.setFocus();
}

protected boolean validatePage() {
	boolean valid = true;
	String moduleName = new String();
	IWorkspace workspace = WorkbenchPlugin.getPluginWorkspace();
    IStatus nameStatus = null;
    String folderName = resourceGroup.getResource();
    moduleName = folderName;
    if (folderName.indexOf(IPath.SEPARATOR) != -1) {
        StringTokenizer tok = new StringTokenizer(folderName, String.valueOf(IPath.SEPARATOR));
        while (tok.hasMoreTokens()) {
            String pathFragment = tok.nextToken();
            nameStatus = workspace.validateName(pathFragment, IResource.FOLDER);
            if (!nameStatus.isOK()) {
                break;
            }
		}
    }
 	//If the name status was not set validate using the name
   	if(nameStatus == null && folderName.length() > 0)
        nameStatus = workspace.validateName(folderName, IResource.FOLDER);
    if (nameStatus != null && !nameStatus.isOK()) {
       	setErrorMessage(nameStatus.getMessage());
        return false;
    }

	if (!resourceGroup.areAllValuesValid()) {
		// if blank name then fail silently
		if (resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_RESOURCE_EMPTY
			|| resourceGroup.getProblemType() == ResourceAndContainerGroup.PROBLEM_CONTAINER_EMPTY) {
			setMessage(resourceGroup.getProblemMessage());
			setErrorMessage(null);
		} else {
			setErrorMessage(resourceGroup.getProblemMessage());
		}
		valid = false;
	}
	if (valid) {
		XarayaVersionModel.setModversionname(moduleName);
		setErrorMessage(null);
	} 
	return valid;
}

}