//------------------------------------------------------------------------------
// 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.library.util;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.epf.common.utils.FileUtil;
import org.eclipse.epf.common.utils.NetUtil;
import org.eclipse.epf.library.ILibraryManager;
import org.eclipse.epf.library.LibraryPlugin;
import org.eclipse.epf.library.LibraryResources;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.edit.command.MethodElementAddCommand.BasicResourceManager;
import org.eclipse.epf.library.edit.util.TngUtil;
import org.eclipse.epf.uma.ContentDescription;
import org.eclipse.epf.uma.DescribableElement;
import org.eclipse.epf.uma.GuidanceDescription;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.MethodPlugin;
import org.eclipse.epf.uma.util.UmaUtil;
import org.eclipse.osgi.util.NLS;

public class CopyAttachmentsToNewLocation extends BasicResourceManager {

	private Collection modifiedResourceSet;

	private boolean debug;

	private Map elementToOldPluginMap;

	private MethodPlugin lastOldPlugin = null;

	public CopyAttachmentsToNewLocation() {
		debug = LibraryPlugin.getDefault().isDebugging();
	}

	/**
	 * Copy attachments within a library, from one plugin to another
	 */
	public Collection copyReferencedContents(Collection elements,
			Map elementToOldPluginMap) {
		lastOldPlugin = null;
		modifiedResourceSet = new HashSet();
		if (elementToOldPluginMap == null) {
			return modifiedResourceSet;
		}
		this.elementToOldPluginMap = elementToOldPluginMap;

		Iterator iter = elements.iterator();
		while (iter.hasNext()) {
			Object o = iter.next();
			if (o instanceof Resource) {
				Resource r = (Resource) o;
				Iterator resourceIter = r.getContents().iterator();
				while (resourceIter.hasNext()) {
					EObject e = (EObject) resourceIter.next();
					HandleAttachmentsPlugin(e);
				}
			} else if (o instanceof EObject) {
				EObject e = (EObject) o;
				HandleAttachmentsPlugin(e);
			}
		}
		return modifiedResourceSet;
	}

	private void HandleAttachmentsPlugin(EObject e) {
		// handle self
		MethodElement elementToProcess = null;
		// find the old plugin, if there is one
		if (elementToOldPluginMap != null
				&& (MethodPlugin) elementToOldPluginMap.get(e) != null) {
			lastOldPlugin = (MethodPlugin) elementToOldPluginMap.get(e);
		}

		if (lastOldPlugin != null) {
			if (e instanceof DescribableElement) {
				DescribableElement de = (DescribableElement) e;

				// Custom icons
				try {
					File libDirFile = new File(LibraryService.getInstance()
							.getCurrentMethodLibraryPath());
					// shape icon
					java.net.URI shapeIconUri = de.getShapeicon();
					if (shapeIconUri != null) {
						java.net.URI srcShapeUri = TngUtil.getFullPathURI(de,
								shapeIconUri);
						File srcFile = new File(srcShapeUri);
						File tgtFile = new File(srcFile.getAbsolutePath()
								.replaceFirst(
										"\\" + File.separator
												+ lastOldPlugin.getName()
												+ "\\" + File.separator,
										"\\"
												+ File.separator
												+ UmaUtil.getMethodPlugin(de)
														.getName() + "\\"
												+ File.separator));
						if (!tgtFile.exists()) {
							FileUtil.copyfile(srcFile, tgtFile);
						}
						java.net.URI newShapeIconUri = new java.net.URI(NetUtil
								.encodeFileURL(FileUtil.getRelativePath(
										tgtFile, libDirFile)));
						de.setShapeicon(newShapeIconUri);
						modifiedResourceSet.add(de.eResource());
					}

					// node icon
					java.net.URI nodeIconUri = de.getNodeicon();
					if (nodeIconUri != null) {
						java.net.URI srcNodeUri = TngUtil.getFullPathURI(de,
								nodeIconUri);
						File srcFile = new File(srcNodeUri);
						File tgtFile = new File(srcFile.getAbsolutePath()
								.replaceFirst(
										"\\" + File.separator
												+ lastOldPlugin.getName()
												+ "\\" + File.separator,
										"\\"
												+ File.separator
												+ UmaUtil.getMethodPlugin(de)
														.getName() + "\\"
												+ File.separator));
						if (!tgtFile.exists()) {
							FileUtil.copyfile(srcFile, tgtFile);
						}
						java.net.URI newNodeIconUri = new java.net.URI(NetUtil
								.encodeFileURL(FileUtil.getRelativePath(
										tgtFile, libDirFile)));
						de.setNodeicon(newNodeIconUri);
						modifiedResourceSet.add(de.eResource());
					}
				} catch (Exception ex) {
					LibraryPlugin.getDefault().getLogger().logError(ex);
				}
				// don't need to process our description because that gets passed in as a separate element
				return;
			} else if (e instanceof ContentDescription) {
				elementToProcess = (ContentDescription) e;
			} else if (e instanceof MethodElement) {
				elementToProcess = (MethodElement) e;
			} else {
				if (debug) {
					System.out
							.println("CopyAttachmentsToNewLocation.HandleAttachmentsPlugin: unknown type " + e); //$NON-NLS-1$
				}
			}

			if (elementToProcess != null
					&& elementToProcess.eResource() != null) {
				// set up ContentResourceScanner for this element
				// give ContentResourceScanner same directory for sourceRootPath
				// and targetRootPath
				ILibraryManager manager = (ILibraryManager) LibraryService
						.getInstance().getCurrentLibraryManager();
				
				URI elementURI = manager != null ? manager.getElementRelativeURI(elementToProcess) : null;
				if (elementURI == null || elementURI.segmentCount() < 1)
					return;
				String targetPluginDir = LibraryService.getInstance()
						.getCurrentMethodLibraryPath()
						+ File.separator
						+ NetUtil.decodedFileUrl(elementURI.segment(0));
				ContentResourceScanner scanner = new ContentResourceScanner(
						new File(targetPluginDir));
				scanner.setTargetRootPath(new File(targetPluginDir));

				// iterate thru element's content

				String contentPath = ResourceHelper
						.getElementPath((MethodElement) elementToProcess);
				if (contentPath.length() == 0) {
					LibraryPlugin
							.getDefault()
							.getLogger()
							.logWarning(
									NLS.bind(LibraryResources.CopyAttachmentsToNewLocation_log_noContentPath, (new Object[] { ((MethodElement) elementToProcess).getName() }))); 
					return;
				}

				String oldContentPath = contentPath.replaceFirst(UmaUtil
						.getMethodPlugin(elementToProcess).getName(),
						lastOldPlugin.getName());
				Iterator iter = elementToProcess.eClass().getEAllAttributes()
						.iterator();
				while (iter.hasNext()) {
					EAttribute attrib = (EAttribute) iter.next();
					Object o = elementToProcess.eGet(attrib);
					if (o instanceof String) {
						String content = (String) o;
						if (content.length() > 0) {
							String newContent = scanner.resolveResourcesPlugin(
									content, contentPath, oldContentPath);
							if (newContent != null
									&& newContent.trim().length() != 0
									&& !content.equals(newContent)) {
								elementToProcess.eSet(attrib, newContent);
								modifiedResourceSet.add(elementToProcess
										.eResource());
							}
						}
					}
				}

				// Template attachments
				if (elementToProcess instanceof GuidanceDescription) {
					String attachmentString = ((GuidanceDescription) elementToProcess)
							.getAttachments();
					List attachmentList = TngUtil
							.convertTemplateAttachmentsToList(attachmentString);
					for (iter = attachmentList.iterator(); iter.hasNext();) {
						String attachment = (String) iter.next();
						if (attachment != null
								&& attachment.trim().length() > 0) {
							try {
								File srcContentPath = new File(LibraryService
										.getInstance()
										.getCurrentMethodLibraryPath(),
										oldContentPath);
								File srcFile = new File(srcContentPath,
										attachment);
								File tgtContentPath = new File(LibraryService
										.getInstance()
										.getCurrentMethodLibraryPath(),
										contentPath);
								File tgtFile = new File(tgtContentPath,
										attachment);
								if (!tgtFile.exists()) {
									FileUtil.copyfile(srcFile, tgtFile);
								}
							} catch (IOException ex) {
								LibraryPlugin.getDefault().getLogger()
										.logError(ex);
							}
						}
					}
				}
			}
		}

		// handle children
		Iterator iter = e.eAllContents();
		while (iter.hasNext()) {
			EObject child = (EObject) iter.next();
			HandleAttachmentsPlugin(child);
		}
	}

	/**
	 * Copy all attachments from one library to another
	 * 
	 * @param oldLibDir
	 *            Original library root
	 * @param newLibDir
	 *            New library root
	 * @param xmiList
	 *            list of xmi File's (pass null to process all files in
	 *            newLibDir)
	 * @param monitor
	 *            optional (can be null) IProgressMonitor
	 */
	public static void copyAttachmentsLibrary(String oldLibDir,
			String newLibDir, List xmiList, IProgressMonitor monitor) {

		// get list of .xmi files in newLibDir
		if (xmiList == null)
			xmiList = FileUtil.fileList(new File(newLibDir), "xmi"); //$NON-NLS-1$

		if (monitor != null)
			monitor.subTask(LibraryResources.copyingAttachmentsTask_name);

		Iterator iter = xmiList.iterator();
		while (iter.hasNext()) {
			if (monitor != null)
				monitor.worked(1);
			File xmiFile = (File) iter.next();
			if (xmiFile.exists()) {
				// parse xmi file
				SAXParserXMI parser = new SAXParserXMI(null);
				parser.parse(xmiFile.getAbsolutePath());
				// iterate thru it's elements, checking content for attachments
				ContentResourceScanner scanner = new ContentResourceScanner(
						new File(oldLibDir));
				scanner.setTargetRootPath(new File(newLibDir));
				HandleAttachments(parser.xmiMap, scanner, xmiFile.getParent()
						.substring(newLibDir.length()));
			}
		}
	}

	private static void HandleAttachments(HashMap eMap,
			ContentResourceScanner scanner, String contentPath) {
		// handle self
		String content = SAXParserXMI.getElementContent(eMap);
		if (content != null) {
			// scan content for attachments
			scanner.resolveResources(content, contentPath);
		}

		// handle children
		Iterator iter = ((ArrayList) eMap.get("children")).iterator(); //$NON-NLS-1$
		while (iter.hasNext()) {
			HashMap childMap = (HashMap) iter.next();
			HandleAttachments(childMap, scanner, contentPath);
		}
	}

}
