package com.shin1ogawa;

import java.io.File;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.dev.LocalDatastoreService;
import com.google.appengine.api.images.ImagesService;
import com.google.appengine.api.mail.MailService;
import com.google.appengine.api.memcache.dev.LocalMemcacheService;
import com.google.appengine.api.urlfetch.URLFetchService;
import com.google.appengine.api.users.UserService;
import com.google.appengine.tools.development.ApiProxyLocal;
import com.google.appengine.tools.development.StreamHandlerFactory;
import com.google.apphosting.api.ApiProxy;
import com.shin1ogawa.servicemock.ApiProxyLocalMock;
import com.shin1ogawa.servicemock.ServiceMock;

public class GaeServiceTestHelper {
	private final ApiProxyLocalMock apiProxyLocal;

	public GaeServiceTestHelper(File testAppDir) {
		this.apiProxyLocal = new ApiProxyLocalMock(testAppDir);
	}

	public GaeServiceTestHelper(ApiProxyLocalMock apiProxyLocal) {
		this.apiProxyLocal = apiProxyLocal;
	}

	public void setUp() {
		ApiProxy.setEnvironmentForCurrentThread(new TestEnvironment());
		ApiProxy.setDelegate(getApiProxyLocal());
		ApiProxyLocal proxy = (ApiProxyLocal) ApiProxy.getDelegate();
		proxy.setProperty(LocalDatastoreService.NO_STORAGE_PROPERTY,
				Boolean.TRUE.toString());
		// 単体テスト実行時は、HttpURLConnectionの実装として
		// "sun.net.www.protocol.http.Http[s]URLConnection"
		// が適用されてしまい、ApiProxyはすっ飛ばして動作してしまう。
		// URL.setURLStreamHandlerFactory()する事であっさりすげ替えが可能そうだが、URLStreamHandlerクラスが
		// AppEngineSDKで使用不可の対象なのでエラーマークがついてしまう。
		// そこで、StreamHandlerFactory.install()を実行する事で
		// AppEngine用のURL.setURLStreamHandlerFactory()が内部で実行され、HttpURLConnectionの実装として
		// "com.google.apphosting.utils.security.urlfetch.URLFetchServiceStreamHandler$Connection"
		// を適用させる。こうする事でURLFetchの動作がApiProxyLocal経由で実行されるようになる。
		StreamHandlerFactory.install();
	}

	public void tearDown() {
		ApiProxy.setDelegate(null);
		ApiProxy.setEnvironmentForCurrentThread(null);
	}

	public ServiceMock addServiceMock(ServiceMock serviceMock) {
		return apiProxyLocal.addServiceMock(serviceMock);
	}

	public ServiceMock removeServiceMock(ServiceMock serviceMock) {
		return apiProxyLocal.removeServiceMock(serviceMock);
	}

	public void setProperty(String key, String value) {
		apiProxyLocal.setProperty(key, value);
	}

	/**
	 * @return the apiProxyLocal
	 */
	public ApiProxyLocalMock getApiProxyLocal() {
		return apiProxyLocal;
	}

	public DatastoreService getDatastoreService() {
		return (DatastoreService) apiProxyLocal.getService("datastore_v3");
	}

	public URLFetchService getUrlFetchService() {
		return (URLFetchService) apiProxyLocal.getService("urlfetch");
	}

	public MailService getMailService() {
		return (MailService) apiProxyLocal.getService("mail");
	}

	public ImagesService getImagesService() {
		return (ImagesService) apiProxyLocal.getService("images");
	}

	/**
	 * TODO MemcacheServiceにはInterfaceが存在しない？
	 * 
	 * @return {@link LocalMemcacheService}
	 */
	public LocalMemcacheService getMemcacheService() {
		return (LocalMemcacheService) apiProxyLocal.getService("memcache");
	}

	public UserService getUserService() {
		return (UserService) apiProxyLocal.getService("user");
	}
}
