// Path: src/com/blochstech/bitcoincardterminal/Utils/ResourceHolder.java
// public class ResourceHolder {
// 	//private Object lockKey; Usually as key in hashmap or unnecessary.
// 	private Object holder;
// 	private Thread holdingThread;
// 	
// 	//public Object LockKey(){ return lockKey; } //The value or resource being locked upon.
// 	public Object Holder(){ return holder; } //The object with access (only for extra restrictive cases).
// 	public Thread HoldingThread(){ return holdingThread; } //The thread that has the lock, re-entry should generally be allowed.
// 	
// 	public ResourceHolder(Object holder, Thread holdingThread){
// 		//this.lockKey = lockKey;
// 		this.holder = holder;
// 		this.holdingThread = holdingThread;
// 	}
// 	public ResourceHolder(Object holder){
// 		//this.lockKey = lockKey;
// 		this.holder = holder;
// 		this.holdingThread = Thread.currentThread();
// 	}
// }
// 
// Path: src/com/blochstech/bitcoincardterminal/Utils/SyntacticSugar.java
// public class SyntacticSugar {
// 	@SuppressWarnings("unchecked")
// 	public static <T> T castAs(Object castee){
// 		try{
// 			return (T) castee;
// 		}catch(Exception ex){
// 			return null;
// 		}
// 	}
// 	
// 	public static boolean EqualWithinMargin(Double value1, Double value2, Double margin){
// 		return value1 * (1+margin) >= value2 && value2 * (1+margin) >= value1;
// 	}
// }
// 
// Path: src/com/blochstech/bitcoincardterminal/Utils/Tags.java
// public class Tags {
// 	//Set this to false when building to Google Play app store.
// 	public static final boolean DEBUG = false;
// 	
// 	public static final String APP_TAG = "BitcoinCardTerminal";
// }


import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import android.os.Environment;
import android.util.Log;
import com.blochstech.bitcoincardterminal.Utils.ResourceHolder;
import com.blochstech.bitcoincardterminal.Utils.SyntacticSugar;
import com.blochstech.bitcoincardterminal.Utils.Tags;
	
	public synchronized void Open(Object holder) throws Exception{
		ResourceHolder holderObj;
		long startTime = System.currentTimeMillis();
		boolean wait = true;
		while(wait){
			holderObj = pathsInUse.get(FileCachePath);
			if(holderObj == null){
				pathsInUse.put(FileCachePath, new ResourceHolder(holder));
				wait = false;
			} else if (holderObj.Holder() == holder && holderObj.HoldingThread() == Thread.currentThread()){
				wait = false;
			} else {
				if(startTime + 20000 < System.currentTimeMillis())
					throw new Exception("Deadlock for 20 seconds while opening generic cache. Path: " + FileCachePath);
				try {
					this.wait();
				} catch (InterruptedException e) {}
			}
		}
		//Permit re-entry:
		return;
	}
	
	public synchronized void Close(Object holder){ //TODO: Find all usages and make sure they are called even if exception happens.
		if(isHolder(holder)){
			pathsInUse.remove(FileCachePath);
			this.notifyAll();
		}else{
			if(Tags.DEBUG)
// Path: src/com/blochstech/bitcoincardterminal/Utils/ResourceHolder.java
// public class ResourceHolder {
// 	//private Object lockKey; Usually as key in hashmap or unnecessary.
// 	private Object holder;
// 	private Thread holdingThread;
// 	
// 	//public Object LockKey(){ return lockKey; } //The value or resource being locked upon.
// 	public Object Holder(){ return holder; } //The object with access (only for extra restrictive cases).
// 	public Thread HoldingThread(){ return holdingThread; } //The thread that has the lock, re-entry should generally be allowed.
// 	
// 	public ResourceHolder(Object holder, Thread holdingThread){
// 		//this.lockKey = lockKey;
// 		this.holder = holder;
// 		this.holdingThread = holdingThread;
// 	}
// 	public ResourceHolder(Object holder){
// 		//this.lockKey = lockKey;
// 		this.holder = holder;
// 		this.holdingThread = Thread.currentThread();
// 	}
// }
// 
// Path: src/com/blochstech/bitcoincardterminal/Utils/SyntacticSugar.java
// public class SyntacticSugar {
// 	@SuppressWarnings("unchecked")
// 	public static <T> T castAs(Object castee){
// 		try{
// 			return (T) castee;
// 		}catch(Exception ex){
// 			return null;
// 		}
// 	}
// 	
// 	public static boolean EqualWithinMargin(Double value1, Double value2, Double margin){
// 		return value1 * (1+margin) >= value2 && value2 * (1+margin) >= value1;
// 	}
// }
// 
// Path: src/com/blochstech/bitcoincardterminal/Utils/Tags.java
// public class Tags {
// 	//Set this to false when building to Google Play app store.
// 	public static final boolean DEBUG = false;
// 	
// 	public static final String APP_TAG = "BitcoinCardTerminal";
// }


// Path: src/com/blochstech/bitcoincardterminal/DataLayer/GenericFileCache.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import android.os.Environment;
import android.util.Log;
import com.blochstech.bitcoincardterminal.Utils.ResourceHolder;
import com.blochstech.bitcoincardterminal.Utils.SyntacticSugar;
import com.blochstech.bitcoincardterminal.Utils.Tags;

	
	public synchronized void Open(Object holder) throws Exception{
		ResourceHolder holderObj;
		long startTime = System.currentTimeMillis();
		boolean wait = true;
		while(wait){
			holderObj = pathsInUse.get(FileCachePath);
			if(holderObj == null){
				pathsInUse.put(FileCachePath, new ResourceHolder(holder));
				wait = false;
			} else if (holderObj.Holder() == holder && holderObj.HoldingThread() == Thread.currentThread()){
				wait = false;
			} else {
				if(startTime + 20000 < System.currentTimeMillis())
					throw new Exception("Deadlock for 20 seconds while opening generic cache. Path: " + FileCachePath);
				try {
					this.wait();
				} catch (InterruptedException e) {}
			}
		}
		//Permit re-entry:
		return;
	}
	
	public synchronized void Close(Object holder){ //TODO: Find all usages and make sure they are called even if exception happens.
		if(isHolder(holder)){
			pathsInUse.remove(FileCachePath);
			this.notifyAll();
		}else{
			if(Tags.DEBUG)
				Log.e(Tags.APP_TAG, "A non-lock holder tried to close the generic cache. Path: " + FileCachePath);