//------------------------------------------------------------------------------
// 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.HashMap;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.epf.export.ExportPlugin;
import org.eclipse.epf.export.ExportResources;
import org.eclipse.epf.library.IConfigurationClosure;
import org.eclipse.epf.library.ILibraryManager;
import org.eclipse.epf.library.LibraryManagerFactory;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.LibraryServiceUtil;
import org.eclipse.epf.library.configuration.ConfigurationClosure;
import org.eclipse.epf.library.layout.LayoutResources;
import org.eclipse.epf.library.util.LibraryUtil;
import org.eclipse.epf.persistence.refresh.RefreshJob;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodLibrary;

/**
 * Exports a library configuration.
 * 
 * @author Jinhua Xi
 * @since 1.0
 */
public class ConfigurationExportService {

	private ConfigurationExportData data;

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

	public void run(IProgressMonitor monitor) {
		try {
			if (data.selectedConfigs == null
					|| data.selectedConfigs.size() == 0) {
				return;
			}
			monitor.setTaskName(ExportResources.ConfigurationExportService_MSG0); //$NON-NLS-1$
			String exportLibPath = data.llData.getParentFolder();
			File exportLibFolder = new File(exportLibPath);
			if (!exportLibFolder.exists()) {
				exportLibFolder.mkdir();
			}
			MethodConfiguration config = (MethodConfiguration) data.selectedConfigs
					.get(0);
			exportConfig(config.getName(), exportLibFolder.getAbsolutePath(),
					monitor);
		} catch (Exception e) {
			ExportPlugin.getDefault().getLogger().logError(e);
		}
	}

	public void exportConfig(String selectedConfigName, String filePath,
			IProgressMonitor monitor) throws Exception {

		// need to disable the workspace refreshing
		boolean refresh = RefreshJob.getInstance().isEnabled();
		try {
			if (refresh) {
				// disable resource refreshing during import
				//
				RefreshJob.getInstance().setEnabled(false);
			}
			doEexportConfig(selectedConfigName, filePath, monitor);
		} finally {
			if (refresh) {
				// re-enable resource refreshing
				//
				RefreshJob.getInstance().setEnabled(true);
			}
		}
	}

	private void doEexportConfig(String selectedConfigName, String filePath,
			IProgressMonitor monitor) throws Exception {

		MethodLibrary currentLib = LibraryService.getInstance()
				.getCurrentMethodLibrary();

		try {
			// Load the whole Method Library.
			LibraryUtil.loadAll(currentLib);
		} catch (Throwable e) {
			ExportPlugin.getDefault().getLogger().logError(
					"Error loading library", e); //$NON-NLS-1$
			data.errorMsg = ExportResources.ConfigurationExportService_MSG2; //$NON-NLS-1$
			return;
		}

		// Copy the current library to a new library,
		// since we need to make changes when packaging the new library.
		MethodLibrary newLibrary = null;
		try {
			newLibrary = (MethodLibrary) EcoreUtil.copy(currentLib);
		} catch (Throwable e) {
			ExportPlugin.getDefault().getLogger().logError(e);
			data.errorMsg = ExportResources.ConfigurationExportService_MSG4; //$NON-NLS-1$
			return;
		}

		IConfigurationClosure closure = null;
		ILibraryManager libMgr = null;
		try {
			// Detach the new library from the current resource so it can be
			// added to a new Library Processor instance.
			LibraryUtil.detachFromResource(newLibrary);

			// Create a new Library Manager and create a new resource for the
			// new library.
			// TODO: Update the UI to prompt for the method library type.
			Map params = new HashMap();
			params.put("library.path", filePath); //$NON-NLS-1$
			
			// this will not work since this will mess up the main library
			// Jinhua Xi 07/13/06
//			MethodLibrary library = LibraryService.getInstance()
//					.createMethodLibrary("library.xmi", "xmi", params); //$NON-NLS-1$ //$NON-NLS-2$
//			LibraryService.getInstance().replaceMethodLibrary(library,
//					newLibrary);
//			LibraryService.getInstance().setCurrentMethodLibrary(newLibrary);

			String name = "library.xmi";	//$NON-NLS-1$
			String type = "xmi";		//$NON-NLS-1$
			libMgr = LibraryManagerFactory.getInstance()
				.createLibraryManager(type);	
			libMgr.createMethodLibrary(name, params);
			libMgr.setMethodLibrary(newLibrary);
			LibraryService.getInstance().setLibraryManager(libMgr);
			
			// Begin packaging the new library for export.
			MethodConfiguration config = LibraryServiceUtil
					.getMethodConfiguration(newLibrary, selectedConfigName);

			// Validate the configuration and make sure the global packages are
			// selected. If global packages are missing, the exported library
			// can't be loaded.
			LibraryUtil.validateMethodConfiguration(config);

			closure = new ConfigurationClosure(config);
			closure.packageLibrary(data.removeBrokenReferences);
		} catch (Throwable e) {
			ExportPlugin.getDefault().getLogger().logError(
					"Error making library configuration closure", e); //$NON-NLS-1$
			data.errorMsg = ExportResources.ConfigurationExportService_MSG1; //$NON-NLS-1$

			if (closure != null)
				closure.dispose();
			if ( libMgr != null ) {
				LibraryService.getInstance().removeLibraryManager(libMgr);
				libMgr.closeMethodLibrary();
				libMgr.dispose();
			}
			
			return;
		}

		try {
			LibraryUtil.saveAll(newLibrary);

			// the first round of save will create the resource structure,
			// need to save again to make sure all references are saved.
			// This step is critical since the first round only created the data
			// structure
			// some of the cross-referenced elements might be lost on the first
			// saving
			// for example, when create a method configuration with references
			// to a new plugin,
			// which are not saved yet, those references will be lost.
			// 145891 - Import Configuration: default config is loss after
			// import
			LibraryUtil.saveAll(newLibrary);

		} catch (Throwable e) {
			ExportPlugin.getDefault().getLogger().logError(
					"Error saving library", e); //$NON-NLS-1$
			data.errorMsg = ExportResources.ConfigurationExportService_MSG9; //$NON-NLS-1$

			if (closure != null)
				closure.dispose();
			if ( libMgr != null ) {
				LibraryService.getInstance().removeLibraryManager(libMgr);
				libMgr.closeMethodLibrary();
				libMgr.dispose();
			}
			return;
		}

		// Copy the resource files in the current library to the new library.
		// For simplicity sake, copy all resource files if the files do not
		// exist in the target library or if the files are newer
		String includes = "resources/**, **/resources/**"; //$NON-NLS-1$
		File srcDir = LibraryUtil.getLibraryRootPath(currentLib);
		File destDir = LibraryUtil.getLibraryRootPath(newLibrary);

		LayoutResources.copyDir(srcDir, destDir, includes, null);

		// Close the newly created library.
		if (closure != null)
			closure.dispose();
		if ( libMgr != null ) {
			LibraryService.getInstance().removeLibraryManager(libMgr);
			libMgr.closeMethodLibrary();
			libMgr.dispose();
		}
	}

}