//------------------------------------------------------------------------------
// 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.services;
import java.util.Collection;
import java.util.Iterator;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.epf.library.ILibraryManager;
import org.eclipse.epf.library.ILibraryServiceListener;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.events.ILibraryChangeListener;
import org.eclipse.epf.uma.MethodConfiguration;
import org.eclipse.epf.uma.MethodElement;
import org.eclipse.epf.uma.MethodLibrary;

import com.ibm.icu.util.Calendar;

/**
 * @author Jinhua Xi
 * @since 1.0
 */
public class VersionManager {

	private ILibraryManager manager;

	private ILibraryServiceListener libSvcListener = null;
	private ILibraryChangeListener libListener = null;

	private boolean inProcessing = false;

	public VersionManager(ILibraryManager manager) {
		this.manager = manager;
		initialize();
	}

	private void initialize() {
		libSvcListener = new ILibraryServiceListener() {

			public void configurationSet(MethodConfiguration config) {
				//System.out.println("configuration set: " + LibraryUtil.getTypeName(config));
			}

			public void libraryClosed(MethodLibrary library) {
				//System.out.println("Library closed: " + LibraryUtil.getTypeName(library));
			}

			public void libraryCreated(MethodLibrary library) {
				//System.out.println("Library closed: " + LibraryUtil.getTypeName(library));
			}

			public void libraryOpened(MethodLibrary library) {
				//System.out.println("Library opened: " + LibraryUtil.getTypeName(library));
			}

			public void libraryReopened(MethodLibrary library) {
				//System.out.println("Library reopened: " + LibraryUtil.getTypeName(library));
			}

			public void librarySet(MethodLibrary library) {
				//System.out.println("Library set: " + LibraryUtil.getTypeName(library));
			}
			
		};
		LibraryService.getInstance().addListener(libSvcListener);
		
		// add library change listener
		libListener = new ILibraryChangeListener() {
			public void libraryChanged(int option, Collection changedItems) {
				if (option == ILibraryChangeListener.OPTION_CHANGED
					//	|| option == ILibraryChangeListener.OPTION_CREATED
						|| option == ILibraryChangeListener.OPTION_DELETED) {
					if (!inProcessing && changedItems != null) {
						inProcessing = true;
						try {
							processChanges(option, changedItems);
						} finally {
							inProcessing = false;
						}
					}
				}
			}
		};

		manager.addListener(libListener);
	}

	public void dispose() {
		LibraryService.getInstance().removeListener(libSvcListener);

		ILibraryManager manager = (ILibraryManager) LibraryService
				.getInstance().getCurrentLibraryManager();
		if (manager != null) {
			manager.removeListener(libListener);
		}
	}

	private void processChanges(int option, Collection changedItems) {
		// System.out.println("================= BEGIN: processChanges
		// ================");
		// System.out.println("changed items: " + changedItems);
		// System.out.println("================= END: processChanges
		// ================");

		if (changedItems == null || changedItems.size() == 0) {
			return;
		}

		for (Iterator it = changedItems.iterator(); it.hasNext();) {
			MethodElement element = (MethodElement) it.next();
			org.eclipse.epf.uma.MethodUnit pkg;

			// note only package has version,
			// it the changed element is a package
			if (element instanceof org.eclipse.epf.uma.MethodUnit) {
				pkg = (org.eclipse.epf.uma.MethodUnit) element;
				switch (option) {
				case ILibraryChangeListener.OPTION_CHANGED:
					updateVersion(pkg);
					break;

				case ILibraryChangeListener.OPTION_NEWCHILD:
					updateVersion(pkg);
					updateVersion((org.eclipse.epf.uma.MethodUnit) pkg
							.eContainer());
					break;

				case ILibraryChangeListener.OPTION_DELETED:
					updateVersion((org.eclipse.epf.uma.MethodUnit) pkg
							.eContainer());
					break;
				}
			} else if (element != null) // TODO: changedItems somtimes contains
			// null element. This must not be the
			// case.
			{
				// it the element is not a package, update the parent
				EObject parent = element.eContainer();
				while (parent != null
						&& !(parent instanceof org.eclipse.epf.uma.MethodUnit)) {
					parent = parent.eContainer();
				}

				if (parent != null) {
					pkg = (org.eclipse.epf.uma.MethodUnit) parent;
					updateVersion(pkg);
				}

				/*
				 * switch (option) { case ILibraryChangeListener.OPTION_CHANGED:
				 * case ILibraryChangeListener.OPTION_CREATED: case
				 * ILibraryChangeListener.OPTION_DELETED: updateVersion(pkg);
				 * break; }
				 */
			}
		}
	}

	public void updateVersion(org.eclipse.epf.uma.MethodUnit pkg) {
		if (pkg == null) {
			return;
		}

		// String oldVer = pkg.getVersion();

		// create a version number based on the date
		Calendar c = Calendar.getInstance();
		int y = c.get(Calendar.YEAR);
		int m = c.get(Calendar.MONTH) + 1;
		int d = c.get(Calendar.DATE);
		long t = c.getTimeInMillis();

		String baseVer = Integer.toString(y) + Integer.toString(m)
				+ Integer.toString(d);
		String miniVer = Long.toHexString(t);

		boolean oldNotify = pkg.eDeliver();
		try {
			pkg.eSetDeliver(false);
			/*
			 * System.out.println("=============================");
			 * System.out.println(" eDeviler()=" + pkg.eDeliver());
			 * System.out.println("=============================");
			 */
			pkg.setVersion(baseVer + "." + miniVer); //$NON-NLS-1$
		} finally {
			pkg.eSetDeliver(oldNotify);
		}
	}

}
