//package com.hammurapi.store.local;
//
//import java.util.ArrayList;
//import java.util.Collection;
//import java.util.Comparator;
//import java.util.LinkedList;
//
//import com.hammurapi.extract.Extractor;
//import com.hammurapi.extract.Predicate;
//import com.hammurapi.store.Store;
//import com.hammurapi.store.Transaction;
// TODO Split into AbstactTransaction and LocalTransaction.
///**
// * Local (in-JVM) transaction. Local transaction shall be created and committed/rolled back in the same thread.
// * @author Pavel Vlasov
// *
// * @param <T>
// * @param <PK>
// */
//public class LocalTransaction<T, PK> implements Transaction<T, PK> {
//	
//	private LinkedList<Runnable> undoLog = new LinkedList<Runnable>();
//	
//	private boolean active = true;
//	
//	public enum IsolationLevel {
//		NONE,
//		READ,
//		WRITE
//	}
//	
//	private LocalStore<T, PK> store;
//	private IsolationLevel isolationLevel;
//
//	public Handle<T, PK> put(final T obj) {
//		checkActive();
//		final Handle<T, PK> ret = store.put(obj);
//		
//		Runnable undoTask = new Runnable() {
//
//			@Override
//			public void run() {
//				ret.remove();
//			}
//			
//		};
//		undoLog.addFirst(undoTask);
//		return new Handle<T, PK>() {
//
//			@Override
//			public void update(T obj) {
//				final T prev = createSnapshot(get());
//				ret.update(obj);
//				
//				Runnable undoTask = new Runnable() {
//
//					@Override
//					public void run() {
//						ret.update(prev);
//					}
//					
//				};
//				undoLog.addFirst(undoTask);
//			}
//
//			@Override
//			public void remove() {
//				final T e = get();
//				ret.remove();
//				
//				Runnable undoTask = new Runnable() {
//
//					@Override
//					public void run() {
//						store.put(e);
//					}
//					
//				};
//				undoLog.addFirst(undoTask);
//			}
//
//			@Override
//			public T get() {
//				return ret.get();
//			}
//
//			@Override
//			public PK getPrimaryKey() {
//				return ret.getPrimaryKey();
//			}
//			
//		};
//	}
//
//	public Iterable<T> getAll() {
//		checkActive();
//		return store.getAll();
//	}
//
//	public T getByPrimaryKey(PK primaryKey) {
//		checkActive();
//		return store.getByPrimaryKey(primaryKey);
//	}
//
//	public Iterable<T> get(Predicate<T, ? extends Store<T, PK>> selector) {
//		checkActive();
//		return store.get(selector);
//	}
//
//	public <V> Iterable<V> get(
//			Predicate<T, ? extends Store<T, PK>> selector,
//			Extractor<T, V, ? extends Store<T, PK>> extractor, 
//			boolean ordered,
//			Comparator<V> comparator) {
//		checkActive();
//		return store.get(selector, extractor, ordered, comparator);
//	}
//
//	public void clear() {
//		checkActive();
//		final Collection<T> contents = new ArrayList<T>();
//		for (T element: store.getAll()) {
//			contents.add(element);			
//		}
//		Runnable undoTask = new Runnable() {
//
//			@Override
//			public void run() {
//				for (T e: contents) {
//					store.put(e);
//				}
//			}
//			
//		};
//		undoLog.addFirst(undoTask);
//		store.clear();
//	}
//
//	public boolean remove(final T obj) {
//		checkActive();
//		Runnable undoTask = new Runnable() {
//
//			@Override
//			public void run() {
//				store.put(obj);
//			}
//			
//		};
//		undoLog.addFirst(undoTask);
//		return store.remove(obj);
//	}
//
//	public int remove(Predicate<T, ? extends Store<T, PK>> selector) {
//		checkActive();
//		
//		final Collection<T> removed = new ArrayList<T>();
//		for (T e: get(selector)) {
//			removed.add(e);
//		}
//		Runnable undoTask = new Runnable() {
//
//			@Override
//			public void run() {
//				for (T e: removed) {
//					store.put(e);
//				}
//			}
//			
//		};
//		undoLog.addFirst(undoTask);
//		return store.remove(selector);
//	}
//
//	public int update(Predicate<T, ? extends Store<T, PK>> selector, UpdateTask<T, PK> updater) {
//		checkActive();
//		for (LocalStore<T, PK>.HandleImpl hi: store.getHandles(selector)) {
//			Runnable undoTask = updater.execute(hi.get(), hi.getPrimaryKey());
//			if (undoTask!=null) {
//				undoLog.addFirst(undoTask);				
//			}
//		}
//		return store.update(selector, updater);
//	}
//
//	public <V> void addIndex(
//			Extractor<T, V, ? extends Store<T, PK>> extractor,
//			boolean unique,
//			boolean ordered, 
//			Comparator<V> comparator) {
//		checkActive();
//		store.addIndex(extractor, unique, ordered, comparator);
//	}
//
//	public Extractor<T, PK, Store<T, PK>> getPrimaryKeyExtractor() {
//		return store.getPrimaryKeyExtractor();
//	}
//
//	public LocalTransaction(LocalStore<T, PK> store, IsolationLevel isolationLevel) {
//		this.store = store;
//		this.isolationLevel = isolationLevel;
//		switch (isolationLevel) {
//		case READ:
//			store.readLock().lock();
//			break;
//		case WRITE:
//			store.writeLock().lock();
//			break;
//		}
//	}
//	
//	private void checkActive() {
//		if (!active) {
//			throw new IllegalStateException("Transaction has been completed");
//		}
//	}
//
//	@Override
//	public void commit() {
//		checkActive();
//		switch (isolationLevel) {
//		case READ:
//			store.readLock().unlock();
//			break;
//		case WRITE:
//			store.writeLock().unlock();
//			break;
//		}
//	}
//
//	@Override
//	public void rollback() {
//		checkActive();		
//		for (Runnable undoTask: undoLog) {
//			undoTask.run();
//		}
//		switch (isolationLevel) {
//		case READ:
//			store.readLock().unlock();
//			break;
//		case WRITE:
//			store.writeLock().unlock();
//			break;
//		}
//	}
//
//	/**
//	 * Creates a "snapshot" of object for rolling back changes.
//	 * This implementation simply returns its argument.
//	 * @param obj
//	 * @return
//	 */
//	protected T createSnapshot(T obj) {
//		return obj;
//	}
//
//	@Override
//	public void processAll(ProcessTask<T, PK> processor) {
//		store.processAll(processor);
//		
//	}
//
//	@Override
//	public void process(Predicate<T, ? extends Store<T, PK>> selector, ProcessTask<T, PK> processor) {
//		store.process(selector, processor);
//	}
//}
