package jp.cloudzero.util.servlet;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
//import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.ho.yaml.Yaml;

import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;

public class InitServlet extends HttpServlet {
	
	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = -953575177319388350L;
	
	private static final String PATH_INF = "/WEB-INF/";
	private static final String DATA_YAML = "data.yaml";
	
	private Map<String, List<Map<String, String>>> dataMap = null;
	
	@SuppressWarnings("unchecked")
	public void init(ServletConfig config) throws ServletException {
		super.init(config);
		String docbase = config.getServletContext().getRealPath("");
		String yamlPath = docbase + PATH_INF + DATA_YAML;
		Object data = null;
		try {
			FileInputStream is = new FileInputStream(yamlPath);
			data = Yaml.load(is);
		} catch (FileNotFoundException e) {
			throw new ServletException(e);
		}
		if (data != null) {
			dataMap = (Map<String, List<Map<String, String>>>)data;
		}
	}
	
	public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
		boolean result = false;
		String res = "";
		if (dataMap != null) {
			switch (Integer.parseInt(request.getParameter("mode"))) {
			// データのクリア
			case 1:
				res = clearData();
				break;
			// データの投入
			case 2:
				String from = request.getParameter("from");
				String to = request.getParameter("to");
				res = loadData(((from == null) ? 0 : Integer.parseInt(from)), ((to == null) ? -1 : Integer.parseInt(to)));
				break;
			default:
				throw new RuntimeException("不明なmodeです");
			}
			result = true;
		}
		response.setContentType("text/plain");
		response.getWriter().println(result ? "successed" : "faild");
		if (result) {
//			printLoadedData(response.getWriter());
			response.getWriter().print(res);
		}
	}
	
	/**
	 * データのクリア
	 */
	private String clearData() {
		Set<String> kinds = dataMap.keySet();
		// Entityごとにループ
		StringBuffer sb = new StringBuffer();
		for (String kind : kinds) {
			clearKind(kind);
			sb.append("Kind cleared [" + kind + "].");
			sb.append("\n");
		}
		return sb.toString();
	}
	
	/**
	 * データの投入
	 */
	private String loadData(int from, int to) {
		// データソースへの接続サービス生成
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		// 生成データ
		List<Entity> entities = new ArrayList<Entity>();
		Set<String> kinds = dataMap.keySet();
		// Entityごとにループ
		int i = 0;
		for (String kind : kinds) {
			List<Map<String, String>> yamlEntities = dataMap.get(kind);
			// データ件数分ループして初期値設定
			for (Map<String, String> yamlEntity : yamlEntities) {
				if (this.isFromValid(i, from) && this.isToValid(i, to)) {
					// Entity生成
					Entity entity = new Entity(kind);
					Set<Map.Entry<String, String>> yamlEntrySet = yamlEntity.entrySet();
					// プロパティの設定
					for (Map.Entry<String, String> yamlEntry : yamlEntrySet) {
						entity.setProperty(yamlEntry.getKey(), String.valueOf(yamlEntry.getValue()));
					}
					entities.add(entity);
				}
				i++;
			}
		}
		if (entities.size() == 0) {
			throw new RuntimeException("ロードするデータがありません。");
		}
		service.put(entities);
		return "";
	}
	
/*	private void printLoadedData(PrintWriter pw) {
		Set<String> kinds = dataMap.keySet();
		StringBuffer sb = new StringBuffer();
		for (String kind : kinds) {
			sb.append("Initialized data list of [" + kind + "].");
			sb.append("\n");
			Iterable<Entity> result = getEntities(kind);
			for (Entity entityRes : result) {
				Map<String, Object> resData = entityRes.getProperties();
				StringBuffer outputLine = new StringBuffer();
				Key key = entityRes.getKey();
				outputLine.append(key.getId() + " => ");
				for (Map.Entry<String, Object> resDataEntry : resData.entrySet()) {
					outputLine.append(resDataEntry.getKey() + " : " + resDataEntry.getValue() + ", ");
				}
				sb.append(outputLine);
				sb.append("\n");
			}
		}
		pw.print(sb.toString());
	}*/
	
	/**
	 * 開始件数を超えているかどうか
	 * @param count
	 * @param from
	 * @return
	 */
	private boolean isFromValid(int count, int from) {
		boolean ret = false;
		// 開始件数が設定されていない場合OK
		if (from == 0) {
			ret = true;
		// 開始件数が設定されている場合、開始件数を超えているかどうか
		} else {
			ret = (count >= (from - 1));
		}
		return ret;
	}
	
	/**
	 * 終了件数を超えているかどうか
	 * @param count
	 * @param to
	 * @return
	 */
	private boolean isToValid(int count, int to) {
		boolean ret = false;
		// 終了件数が設定されていない場合OK
		if (to == -1) {
			ret = true;
		// 終了件数が設定されている場合、終了件数を超えていないかどうか
		} else {
			ret = (count <= (to - 1));
		}
		return ret;
	}
	
	private Iterable<Entity> getEntities(String kind) {
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		Query query = new Query(kind);
		PreparedQuery pq = service.prepare(query);
		return pq.asIterable();
	}
	
	private void clearKind(String kind) {
		List<Key> keys = new ArrayList<Key>();
		Iterable<Entity> entities = getEntities(kind);
		for (Entity entity : entities) {
			keys.add(entity.getKey());
		}
		DatastoreService service = DatastoreServiceFactory.getDatastoreService();
		service.delete(keys);
	}
}