package be.kuleuven.cs.distrinet.chameleon.oo.expression;

import java.lang.ref.SoftReference;

import be.kuleuven.cs.distrinet.chameleon.core.Config;
import be.kuleuven.cs.distrinet.chameleon.core.element.ElementImpl;
import be.kuleuven.cs.distrinet.chameleon.core.lookup.LocalLookupContext;
import be.kuleuven.cs.distrinet.chameleon.core.lookup.LookupException;
import be.kuleuven.cs.distrinet.chameleon.core.lookup.Target;
import be.kuleuven.cs.distrinet.chameleon.core.reference.CrossReferenceTarget;
import be.kuleuven.cs.distrinet.chameleon.oo.statement.CheckedExceptionList;
import be.kuleuven.cs.distrinet.chameleon.oo.statement.ExceptionSource;
import be.kuleuven.cs.distrinet.chameleon.oo.type.Type;
import be.kuleuven.cs.distrinet.rejuse.java.collections.RobustVisitor;

/**
 * A class of elements representing expressions in a language. Each expression has a type.
 *  
 * @author Marko van Dooren
 */

public abstract class Expression extends ElementImpl implements CrossReferenceTarget {

	/**
	 * Return the type of this expression. The actual computation of the type is done in actualType. This
	 * method performs the caching. Enable or disable caching of expression types using Config.CACHE_EXPRESSION_TYPES.
	 */
 /*@
   @ public behavior
   @
   @ post \result == actualType();
   @*/
	public synchronized final Type getType() throws LookupException {
		Type result = null;
		if(Config.cacheExpressionTypes()) {
			result = (_typeCache == null ? null : _typeCache.get());
		}
		if(result == null) {
		  result = actualType();
			if(Config.cacheExpressionTypes()) {
				_typeCache = new SoftReference<Type>(result);
			}
		}
		return result;
	}
	
	@Override
	public synchronized void flushLocalCache() {
		super.flushLocalCache();
		_typeCache = null;
	}
	
	private SoftReference<Type> _typeCache;
	
	protected abstract Type actualType() throws LookupException;

	/**
	 * @see {@link Target#targetContext()}
	 */
  public LocalLookupContext<?> targetContext() throws LookupException {
    return getType().targetContext();
  }

  public void prefix(CrossReferenceTarget target) throws LookupException {
    // Do nothing by default.
  }
  
  public void prefixRecursive(CrossReferenceTarget target) throws LookupException {
    // Do nothing by default.
  }
  
  public void substituteParameter(String name, Expression expr) throws LookupException {
    // Do nothing by default.
  }

//  /**
//   * See superclass.
//   */
//  public final Set getExceptions() throws LookupException {
//    final Set result = getDirectExceptions();
//    try {
//      new RobustVisitor() {
//        public Object visit(Object element) throws LookupException {
//          result.addAll(((InvocationTarget)element).getExceptions());
//          return null;
//        }
//
//        public void unvisit(Object element, Object undo) {
//          //NOP
//        }
//      }.applyTo(children());
//      return result;
//    }
//    catch (LookupException e) {
//      throw e;
//    }
//    catch (Exception e) {
//      e.printStackTrace();
//      throw new Error();
//    }
//  }

  public CheckedExceptionList getCEL() throws LookupException {
    final CheckedExceptionList cel = getDirectCEL();
    try {
      new RobustVisitor() {
        public Object visit(Object element) throws LookupException {
          cel.absorb(((ExceptionSource)element).getCEL());
          return null;
        }

        public void unvisit(Object element, Object undo) {
          //NOP
        }
      }.applyTo(children());
      return cel;
    }
    catch (LookupException e) {
      throw e;
    }
    catch (Exception e) {
      e.printStackTrace();
      throw new Error();
    }
  }
  
  public CheckedExceptionList getDirectCEL() throws LookupException {
    return new CheckedExceptionList();
  }
  
  public CheckedExceptionList getAbsCEL() throws LookupException {
    final CheckedExceptionList cel = getDirectAbsCEL();
    try {
      new RobustVisitor() {
        public Object visit(Object element) throws LookupException {
          cel.absorb(((ExceptionSource)element).getAbsCEL());
          return null;
        }

        public void unvisit(Object element, Object undo) {
          //NOP
        }
      }.applyTo(children());
      return cel;
    }
    catch (LookupException e) {
      throw e;
    }
    catch (Exception e) {
      e.printStackTrace();
      throw new Error();
    }
  }
  
  public CheckedExceptionList getDirectAbsCEL() throws LookupException {
    return getDirectCEL();
  }
  
}

@@ -52,16 +52,69 @@
 ssion;%0A%0A
+import java.util.concurrent.atomic.AtomicReference;%0A%0A
 import j
@@ -1364,29 +1364,16 @@
 %09public 
-synchronized 
 final Ty
@@ -1470,16 +1470,62 @@
 es()) %7B%0A
+%09%09%09SoftReference%3CType%3E tcache = _cache.get();%0A
 %09%09%09resul
@@ -1529,22 +1529,18 @@
 sult = (
-_typeC
+tc
 ache == 
@@ -1553,22 +1553,18 @@
  null : 
-_typeC
+tc
 ache.get
@@ -1666,27 +1666,41 @@
  %7B%0A%09%09%09%09_
-typeCache =
+cache.compareAndSet(null,
  new Sof
@@ -1723,16 +1723,17 @@
 (result)
+)
 ;%0A%09%09%09%7D%0A%09
@@ -1780,21 +1780,8 @@
 lic 
-synchronized 
 void
@@ -1828,16 +1828,18 @@
 ache();%0A
+//
 %09%09_typeC
@@ -1852,20 +1852,287 @@
  null;%0A%09
-%7D%0A%09%0A
+%09boolean success = false;%0A%09%09do %7B%0A%09%09%09success = _cache.compareAndSet(_cache.get(), null);%0A%09%09%7D while(! success);%0A%0A%09%7D%0A%09%0A//%09private final AtomicBoolean _cacheLock = new AtomicBoolean();%0A%09private final AtomicReference%3CSoftReference%3CType%3E%3E _cache = new AtomicReference%3C%3E();%0A%09%0A//
 %09private

replace synchronization with CAS loops