/******************************************************************************* 
 * Copyright (c) 2010 Red Hat, Inc. 
 * Distributed under license by Red Hat, Inc. All rights reserved. 
 * This program is 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: 
 * Red Hat, Inc. - initial API and implementation 
 ******************************************************************************/ 
package org.jboss.tools.common.model.filesystems.impl;

import java.util.HashMap;
import java.util.Map;

import org.jboss.tools.common.model.XModelObject;

/**
 * This factory provides a new ready to be loaded copy of delegated model object in case when 
 * the delegated model object is being loaded by another thread, and there is a danger of deadlock
 * in waiting for completion of its loading. If the delegate is loaded, factory returns null.
 * 
 * @author Viacheslav Kabanovich
 *
 */
public class ThreadSafeCopyFactory {
	XModelObject object;

	Thread loadingThread = Thread.currentThread();
	Map<Thread, XModelObject> concurrentlyLoaded = null;

	public ThreadSafeCopyFactory(XModelObject object) {
		this.object = object;
	}

    /**
     * Returns ready to be loaded copy of model object if and only if
     * this object is being loaded by another thread.
     * Otherwise, returns null.
     * 
     * @return
     */
    XModelObject getThreadSafeCopy() {
    	if(loadingThread == null) {
    		concurrentlyLoaded = null;
    		return null;
    	}
    	if(Thread.currentThread() == loadingThread) {
    		return null;
    	}

    	Map<Thread, XModelObject> map = concurrentlyLoaded;
    	XModelObject copy = null;
		if(map != null) {
			copy = map.get(Thread.currentThread());
			if(copy != null) return copy;
		}
		if(object.getParent() instanceof JarFolderImpl) {
			copy = ((JarFolderImpl)object.getParent()).createValidChildCopy(object);
		} else if(object.getParent() instanceof FolderImpl) {
			copy = ((FolderImpl)object.getParent()).createValidChildCopy(object);
		}
		if(copy != null) {
			//Let us wait a bit for this object, maybe there is no lock.
			for (int i = 0; i < 5; i++) {
				if(loadingThread != null && !loadingThread.isAlive()) {
					loadingThread = null;
				}
				Thread t = loadingThread;
				if (t != null) try {
					t.join(100);
				} catch (InterruptedException e) {
					//ignore
				}
				if(loadingThread == null) {
					return null;
				}
			}
			if(map == null) {
				if(concurrentlyLoaded != null) {
					map = concurrentlyLoaded;
				} else {
					map = new HashMap<Thread, XModelObject>();
					concurrentlyLoaded = map;
				}
			}
			map.put(Thread.currentThread(), (AbstractExtendedXMLFileImpl)copy);
		}
    	return copy;
    }

    public void destroy() {
    	loadingThread = null;
    	concurrentlyLoaded = null;
    }

}
