package lib.morkim.mfw.repo;

import java.util.HashMap;
import java.util.Map;

import lib.morkim.mfw.app.MorkimApp;
import lib.morkim.mfw.domain.Entity;
import lib.morkim.mfw.repo.gateway.AbstractGateway;
import lib.morkim.mfw.repo.gateway.EmptyGateway;
import lib.morkim.mfw.repo.gateway.Gateway;

public abstract class MorkimRepository implements Repository {

	protected MorkimApp context;
	protected Map<Class<?>, Class<? extends AbstractGateway<? extends Entity>>> map;

	protected abstract int version();

	public MorkimRepository(MorkimApp application) {
		this.context = application;

		map = new HashMap<>();
		mapGateways(map);

		RepoVersion repoVersion = createVersionGateway();
		int savedVersion = repoVersion.get();

		int currentVersion = version();
		for (int version = savedVersion + 1; version <= currentVersion; version++) {

			onUpgrade(currentVersion);

			if (version == currentVersion) repoVersion.set(currentVersion);
		}
	}


	/**
	 * Override this method to associate a specific {@link Entity} to a specific {@link Gateway}.
	 * Gateway translate application data models from/to their persisted form.
	 * @param map The map to add entity/gateway pairs
	 */
	protected abstract void mapGateways(Map<Class<?>, Class<? extends AbstractGateway<? extends Entity>>> map);

	protected RepoVersion createVersionGateway() {
		return new RepoVersion(context);
	}

	@Override
	public <E extends Entity> Gateway<E> get(Class<E> entityClass) {

		Class<? extends AbstractGateway<E>> gatewayClass = (Class<? extends AbstractGateway<E>>) map.get(entityClass);

		try {
			AbstractGateway<E> gateway = gatewayClass.<E>newInstance();
			gateway.setMorkimApp(context);
			return gateway;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}

		return new EmptyGateway<>();
	}

	/**
	 * Checks for data persistence upgrades. Use the toVersion parameter to handle
	 * the upgrade to a specific version. This method will be called n number of times
	 * depending on the difference between the old repository version number and the
	 * latest repository version number.
	 * So if old version number is 3 and the latest version number is 6 then this method will
	 * be called 3 times with progressive {@code toVersion} parameter.
	 * This will basically hold your repository change history.
	 * Remember that the latest database version is determined by
	 * overriding the {@link #version()} method and returning the latest version number.
	 * @param toVersion The version to upgrade to
	 */
	protected abstract void onUpgrade(int toVersion);
}

@@ -945,17 +945,16 @@
 %09%09%7D%0A%09%7D%0A%0A
-%0A
 %09/**%0A%09 *
@@ -1570,16 +1570,47 @@
 );%0A%0A
+%09%09if (gatewayClass != null) %7B%0A%09
 %09%09try %7B%0A
 %09%09%09A
@@ -1605,16 +1605,17 @@
 %09%09try %7B%0A
+%09
 %09%09%09Abstr
@@ -1669,16 +1669,17 @@
 ance();%0A
+%09
 %09%09%09gatew
@@ -1707,16 +1707,17 @@
 xt);%0A%09%09%09
+%09
 return g
@@ -1724,16 +1724,17 @@
 ateway;%0A
+%09
 %09%09%7D catc
@@ -1756,32 +1756,33 @@
 nException e) %7B%0A
+%09
 %09%09%09e.printStackT
@@ -1791,16 +1791,17 @@
 ce();%0A%09%09
+%09
 %7D catch 
@@ -1829,16 +1829,17 @@
 on e) %7B%0A
+%09
 %09%09%09e.pri
@@ -1854,16 +1854,21 @@
 race();%0A
+%09%09%09%7D%0A
 %09%09%7D%0A%0A%09%09r

return empty gateway if no mapping exists