//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// 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:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.export.services;

import java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.epf.export.ExportResources;
import org.eclipse.epf.library.util.ResourceHelper;
import org.eclipse.epf.persistence.MultiFileSaveUtil;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.MethodLibrary;
import org.eclipse.epf.uma.MethodPackage;
import org.eclipse.epf.uma.MethodPlugin;

/**
 * Exports one or more method plug-ins to a target directory.
 * 
 * @author Jinhua Xi
 * @author Kelvin Low
 * @since 1.0
 */
public class PluginExportService extends BaseExportService {

	PluginExportData data;

	/**
	 * Creates a new instance.
	 */
	public PluginExportService(PluginExportData data) {
		this.data = data;
	}

	public void run(IProgressMonitor monitor) {
		monitor.setTaskName(ExportResources.PluginExportService_MSG0); //$NON-NLS-1$

		List plugins = data.selectedPlugins;
		if (plugins == null || plugins.size() == 0) {
			return;
		}

		monitor.setTaskName(ExportResources.PluginExportService_MSG1); //$NON-NLS-1$

		// Create the library folder in the target directory.
		String exportLibPath = data.llData.getParentFolder();
		File exportLibFolder = new File(exportLibPath);
		if (!exportLibFolder.exists()) {
			exportLibFolder.mkdir();
		}

		File libFolder = null;

		monitor.setTaskName(ExportResources.PluginExportService_MSG2); //$NON-NLS-1$

		// Iterate the selected plug-ins and copy their associated model files.
		for (Iterator it = plugins.iterator(); it.hasNext();) {
			MethodPlugin plugin = (MethodPlugin) it.next();
			if (plugin == null) {
				continue;
			}

			// Step 1: Create the plug-in folder.
			URI uri = plugin.eResource().getURI();
			String path = uri.toFileString();

			File pluginFolder = (new File(path)).getParentFile();
			if (libFolder == null) {
				libFolder = pluginFolder.getParentFile();
			}

			String pluginPath = libFolder.toURI().relativize(
					pluginFolder.toURI()).getPath();
			File exportPluginFolder = new File(exportLibFolder, pluginPath);

			// Step 2: Copy the plug-in files.
			copyDir(pluginFolder, exportPluginFolder);			
		}

		monitor.setTaskName(ExportResources.PluginExportService_MSG3); //$NON-NLS-1$

		// Get the selected plug-in and configuration ids so we can remove the
		// unneeded stuff.
		getSelectedIds(data.selectedPlugins, data.associatedConfigMap);

		// Step 3: Load the library.xmi and the resmgr.xmi, remove the unneeded
		// stuff.
		LibraryDocument document = processLibraryFile(new File(libFolder, libraryFile), new File(
				exportLibFolder, exportFile));

		if ( document != null ) {
			// copy the conifuration files
			// 142379 - update plugin importing and exporting to match with the new file format
			copyConfigurationFiles(document, libFolder, exportLibFolder);
		}
		
		monitor.setTaskName(ExportResources.PluginExportService_MSG4); //$NON-NLS-1$
	}

	
	private void copyConfigurationFiles(LibraryDocument document, File libFolder, File exportLibFolder) {
		// // 142379 - update plugin importing and exporting to match with the new file format
		// Get the selected configuration ids.
		for (Iterator itc = data.associatedConfigMap.values().iterator(); itc.hasNext();) {
			List configs = (List) itc.next();
			if (configs == null || configs.size() == 0) {
				continue;
			}

			for (Iterator it = configs.iterator(); it.hasNext();) {
				MethodConfiguration config = (MethodConfiguration) it.next();
				String guid = config.getGuid();
				String uri = document.getResourceUri(guid);
				if (uri == null) {
					URI resUri = config.eResource().getURI();
					uri = MultiFileSaveUtil.METHOD_CONFIGURATION_FOLDER_NAME + File.separator + resUri.lastSegment();
					uri = document.decodeUri(uri);
				}				
				if ( uri != null ) {
					File src = new File(libFolder, uri);
					File target =  new File(exportLibFolder, uri);
					ResourceHelper.copyFile(src, target);
				}
			}
		}
	}

	public static void copyDir(File fromDir, File toDir) {
		Copy cp = new Copy();
		cp.setOverwrite(true);
		FileSet set = new FileSet();
		set.setDir(fromDir);
		cp.addFileset(set);
		cp.setTodir(toDir);
		cp.setProject(new Project());
		cp.setPreserveLastModified(true);
		cp.execute();
	}

	private void getSelectedIds(List plugins, Map configsMap) {
		selectedIds.clear();
		selectedPluginNames.clear();

		// Get the plug-in ids and names.
		MethodPlugin plugin = null;
		for (Iterator it = plugins.iterator(); it.hasNext();) {
			plugin = (MethodPlugin) it.next();
			String guid = plugin.getGuid();
			selectedPluginNames.add(plugin.getName());
			if (!selectedIds.contains(guid)) {
				selectedIds.add(guid);
			}
		}

		// Save the library guid so that the entry in resgr.xmi will be kept.
		if (plugin != null) {
			MethodLibrary lib = (MethodLibrary) plugin.eContainer();
			if (lib != null) {
				selectedIds.add(lib.getGuid());
			}
		}

		// Get the selected configuration ids.
		for (Iterator itc = configsMap.values().iterator(); itc.hasNext();) {
			List configs = (List) itc.next();
			if (configs == null || configs.size() == 0) {
				continue;
			}

			for (Iterator it = configs.iterator(); it.hasNext();) {
				MethodConfiguration config = (MethodConfiguration) it.next();
				String guid = config.getGuid();
				if (selectedIds.contains(guid)) {
					continue;
				}

				// Add the configuration.
				selectedIds.add(guid);

				// For each configuration, save the method plug-in and package
				// ids so that their entries in the resource file can be kept.
				List refs = config.eCrossReferences();
				for (Iterator itr = refs.iterator(); itr.hasNext();) {
					Object o = itr.next();
					if (o instanceof MethodPlugin || o instanceof MethodPackage) {
						guid = ((MethodElement) o).getGuid();
						if (!selectedIds.contains(guid)) {
							selectedIds.add(guid);
						}
					} else {
						System.out
								.println("Unexpected element type '" + ((MethodElement) o).getType().getName() //$NON-NLS-1$
										+ "' in configuration '" + config.getName() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
					}
				}
			}
		}
	}

}
