package appengine.util;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.dev.LocalDatastoreService;
import com.google.appengine.tools.development.ApiProxyLocal;
import com.google.appengine.tools.development.ApiProxyLocalImpl;
import com.google.apphosting.api.ApiProxy;
import com.google.apphosting.api.ApiProxy.ApiProxyException;
import com.google.apphosting.api.ApiProxy.Delegate;
import com.google.apphosting.api.ApiProxy.Environment;
import com.google.apphosting.api.ApiProxy.LogRecord;

public class TestUtil {

	private TestUtil() {
	}

	public static void setUpAppEngine(String folderName, boolean noStrage) {
		ApiProxy.setEnvironmentForCurrentThread(DEFAULT_ENVIRONMENT);
		ApiProxy.setDelegate(new ApiProxyLocalImpl(new File(folderName)) {
		});
		if (noStrage) {
			((ApiProxyLocalImpl) ApiProxy.getDelegate()).setProperty(
					LocalDatastoreService.NO_STORAGE_PROPERTY, Boolean.TRUE
							.toString());
		}
	}

	public static void tearDownAppEngine() {
		if (ApiProxy.getDelegate() != null) {
			((ApiProxyLocal) ApiProxy.getDelegate()).getService("datastore_v3")
					.stop();
			ApiProxy.setDelegate(null);
		}
		ApiProxy.setEnvironmentForCurrentThread(null);
	}

	public static void delegateToTraceLowLevel() {
		@SuppressWarnings("unchecked")
		Delegate<Environment> original = ApiProxy.getDelegate();
		ApiProxy.setDelegate(new TraceLowLevelDelegate(original));
	}

	public static void restoreDelegateFromTraceLowLevel() {
		if (ApiProxy.getDelegate() instanceof TraceLowLevelDelegate) {
			ApiProxy.setDelegate(((TraceLowLevelDelegate) ApiProxy
					.getDelegate()).getOriginal());
		}
	}

	static class TraceLowLevelDelegate implements Delegate<Environment> {

		final Logger logger = Logger.getLogger(TraceLowLevelDelegate.class
				.getName());
		final Delegate<Environment> original;

		TraceLowLevelDelegate(Delegate<Environment> original) {
			this.original = original;
		}

		public byte[] makeSyncCall(Environment environment, String packageName,
				String methodName, byte[] request) throws ApiProxyException {
			logger.info("makeSyncCall: serviceName=" + packageName
					+ ", methodName=" + methodName);
			return getOriginal().makeSyncCall(environment, packageName,
					methodName, request);
		}

		public void log(Environment environment, LogRecord logRecord) {
			getOriginal().log(environment, logRecord);
		}

		Delegate<Environment> getOriginal() {
			return original;
		}
	}

	static final ApiProxy.Environment DEFAULT_ENVIRONMENT = new ApiProxy.Environment() {

		/**
		 * sdkで起動した時に{@code ApiProxy.getCurrentEnvironment().getAppId()}で取得される値
		 */
		public String getAppId() {
			return "gae-j-template";
		}

		/**
		 * sdkで起動した時に{@code ApiProxy.getCurrentEnvironment().getVersionId()}
		 * で取得される値
		 */
		public String getVersionId() {
			return "gae-j-template.1";
		}

		public String getRequestNamespace() {
			return "";
		}

		public String getAuthDomain() {
			throw new UnsupportedOperationException();
		}

		public boolean isLoggedIn() {
			throw new UnsupportedOperationException();
		}

		public String getEmail() {
			throw new UnsupportedOperationException();
		}

		public boolean isAdmin() {
			throw new UnsupportedOperationException();
		}

		public Map<String, Object> getAttributes() {
			Map<String, Object> map = new HashMap<String, Object>();
			return map;
		}
	};
}
