/**
 *
 */
package kr.co.kihyun.beans.entity.util;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.jdo.JDOObjectNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.PersistenceManagerFactory;
import javax.jdo.Transaction;

import kr.co.kihyun.beans.entity.Category;
import kr.co.kihyun.moumi.MoumiConfig;
import org.datanucleus.jdo.JDOPersistenceManagerFactory;
import org.datanucleus.store.rdbms.SchemaTool;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author bhs
 *
 */
public class SchemaOrganizer {
	private static final Logger LOG = LoggerFactory.getLogger(SchemaOrganizer.class);

	private PersistenceManagerFactory pmf;

	public SchemaOrganizer(PersistenceManagerFactory pmf) {
		setPMF(pmf);
	}

	public final PersistenceManagerFactory getPMF() {
		return this.pmf;
	}

	public final void setPMF(PersistenceManagerFactory pmf) {
		this.pmf = pmf;
	}

	public void validateSchema() {
		Set<String> inputClassNames = getEntityClassNames();

		createOrValidateSchemaForClasses(inputClassNames);
	}

	protected Set<String> getEntityClassNames() {
		Set<String> inputClassNames = new HashSet<String>();

		inputClassNames.add("kr.co.kihyun.beans.entity.AcceptenceLimitStrategy");
		inputClassNames.add("kr.co.kihyun.beans.entity.UnlimitStrategy");
		inputClassNames.add("kr.co.kihyun.beans.entity.LimitByDeadlineStrategy");
		inputClassNames.add("kr.co.kihyun.beans.entity.LimitBySubmitDateStrategy");
		inputClassNames.add("kr.co.kihyun.beans.entity.LimitByWriteDateStrategy");
		inputClassNames.add("kr.co.kihyun.beans.entity.Board");
		inputClassNames.add("kr.co.kihyun.beans.entity.Category");
		inputClassNames.add("kr.co.kihyun.beans.entity.CpuPercent");
		inputClassNames.add("kr.co.kihyun.beans.entity.DayCount");
		inputClassNames.add("kr.co.kihyun.beans.entity.Emul");
		inputClassNames.add("kr.co.kihyun.beans.entity.MDept");
		inputClassNames.add("kr.co.kihyun.beans.entity.Memo");
		inputClassNames.add("kr.co.kihyun.beans.entity.MUser");
		inputClassNames.add("kr.co.kihyun.beans.entity.Repoadm");
        inputClassNames.add("kr.co.kihyun.beans.entity.ShareDoc");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotDoc");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotItem");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotLog");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotReport");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotReportVersion");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotReportHistory");
		inputClassNames.add("kr.co.kihyun.beans.entity.TotTable");
		inputClassNames.add("kr.co.kihyun.beans.entity.UserDept");
		inputClassNames.add("kr.co.kihyun.beans.entity.UserHistory");
		inputClassNames.add("kr.co.kihyun.beans.entity.UserPart");
		inputClassNames.add("kr.co.kihyun.beans.entity.UserUser");

		return inputClassNames;
	}

	private void createOrValidateSchemaForClasses(Set<String> inputClassNames) throws RuntimeException {
		SchemaTool schematool = new SchemaTool();

		try {
			for (String className : inputClassNames)
				LOG.debug("validate {}", className);
			schematool.validateSchema((JDOPersistenceManagerFactory) pmf, inputClassNames);
		} catch (Exception e) {
			LOG.info("Schema is invalid or not exist. So will be (re)created.");
			try {
				schematool.createSchema((JDOPersistenceManagerFactory) pmf, inputClassNames, true);
			} catch (Exception e1) {
				LOG.error("Schema (re)creation failed!");
				throw new RuntimeException(e1);
			}
		}
	}

	/**
	 *
	 */
//	public void validateUsers() {
//		PersistenceManager pm = pmf.getPersistenceManager();
//		Transaction tx = pm.currentTransaction();
//		List<MUser> userList = null;
//		List<MDept> deptList = null;
//		MDept mDept = null;
//		MUser mUser = null;
//		Query q = null;
//		try {
//			tx.begin();
//			q = pm.newQuery(MDept.class, "sysAuth == sys_auth");
//			q.declareParameters("kr.co.kihyun.moumi.SysAuth sys_auth");
//			deptList = (List<MDept>) q.execute(SysAuth.SYSADM);
//			if (deptList.isEmpty()) {
//				mDept = new MDept("PASSCODE",
//						"ADMINDEPT", (MDept) null);
//				mDept.setSysAuth(SysAuth.SYSADM);
//				pm.makePersistent(mDept);
//			}
//
//			q = pm.newQuery(MUser.class, "sysAuth == sys_auth");
//			q.declareParameters("kr.co.kihyun.moumi.SysAuth sys_auth");
//			userList = (List<MUser>) q.execute(SysAuth.SYSADM);
//			if (userList.isEmpty()) {
//				q = pm.newQuery(MDept.class,
//						"sysAuth == sys_auth");
//				q.declareParameters("kr.co.kihyun.moumi.SysAuth sys_auth");
//				deptList = (List<MDept>) q.execute(SysAuth.SYSADM);
//				mUser = new MUser("admin", "moumi", deptList.isEmpty() ? mDept
//						: deptList.iterator().next());
//				mUser.setName("Administrator");
//				mUser.setSysAuth(SysAuth.SYSADM);
//				Set<MDept> depts =
//						new HashSet<MDept>();
//				depts.add(mUser.getUpperDept(pm));
//				mUser.setDepts(depts);
//				pm.makePersistent(mUser);
//			}
//
//			q = pm.newQuery(MDept.class, "sysAuth == sys_auth");
//			q.declareParameters("kr.co.kihyun.moumi.SysAuth sys_auth");
//			deptList = (List<MDept>) q.execute(SysAuth.TOTPER);
//			if (deptList.isEmpty()) {
//				deptList = new ArrayList<MDept>();
//				userList = new ArrayList<MUser>();
//				Set<MDept> depts;
//
//				mDept = new MDept("PASSCODE", "DEPTA", (MDept) null);
//				mDept.setSysAuth(SysAuth.TOTPER);
//				deptList.add(mDept);
//				mUser = new MUser("usera1", "a1", mDept);
//				mUser.setName("user a1");
//				mUser.getRoles().add(Role.DOC_MANAGER);
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept(pm));
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mUser =
//						new MUser("usera2", "a2", mDept);
//				mUser.setName("user a2");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept(pm));
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mDept = new MDept("PASSCODE",
//						"DEPTB", (MDept) null);
//				mDept.setSysAuth(SysAuth.TOTPER);
//				mDept.setDocUnit(false);
//				deptList.add(mDept);
//				mUser =
//						new MUser("userb1", "b1", mDept);
//				mUser.setName("user b1");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mUser = new MUser("userb2", "b2",
//						mDept);
//				mUser.setName("user b2");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept()); //
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mDept = new MDept("PASSCODE", "DEPTBA", mDept);
//				mDept.setSysAuth(SysAuth.TOTPER);
//				deptList.add(mDept);
//				mUser = new MUser("userba1", "ba1", mDept);
//				mUser.setName("user ba1");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mUser = new MUser("userba2", "ba2", mDept);
//				mUser.setName("user ba2");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mDept = new MDept("PASSCODE", "DEPTC", (MDept) null);
//				mDept.setSysAuth(SysAuth.TOTPER);
//				deptList.add(mDept);
//				mUser = new MUser("userc1", "c1", mDept);
//				mUser.setName("user c1");
//				mUser.getRoles().add(Role.DOC_MANAGER);
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mUser = new MUser("userc2", "c2",
//						mDept);
//				mUser.setName("user c2");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mDept = new MDept("PASSCODE", "DEPTCA", mDept);
//				mDept.setSysAuth(SysAuth.TOTPER);
//				mDept.setDocUnit(false);
//				deptList.add(mDept);
//				mUser = new MUser("userca1",
//						"ca1", mDept);
//				mUser.setName("user ca1");
//				mUser.getRoles().add(Role.DOC_MANAGER);
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				mUser = new MUser("userca2",
//						"ca2", mDept);
//				mUser.setName("user ca2");
//				depts = new HashSet<MDept>();
//				depts.add(mUser.getUpperDept());
//				mUser.setDepts(depts);
//				userList.add(mUser);
//				pm.makePersistentAll(deptList);
//				pm.makePersistentAll(userList);
//			}
//
//	tx.commit(); } finally { if (tx.isActive()) tx.rollback(); pm.close(); } }

	// TODO: localization
	public void validateCategories() {
		PersistenceManager pm = pmf.getPersistenceManager();
		Transaction tx = pm.currentTransaction();
		try {
			tx.begin();

			try {
				pm.getObjectById(Category.class, Category.ID_BOARD);
			} catch (JDOObjectNotFoundException jonfe) {
				List<Category> childCategories = new ArrayList<Category>();
				Category upperCategory = new Category(Category.ID_BOARD, MoumiConfig.getMessageBundle().getString(
						"moumi.message.board"));
				pm.makePersistent(upperCategory);
				Category childCategory;
				childCategory = new Category(Category.ID_SYSTEM_NOTICE);
				childCategory.setName(MoumiConfig.getMessageBundle().getString("moumi.message.board.notice"));
				childCategory.setPriority(1);
				childCategories.add(childCategory);
				childCategory = new Category(Category.ID_FAQ);
				childCategory.setName(MoumiConfig.getMessageBundle().getString("moumi.message.board.faq"));
				childCategory.setPriority(2);
				childCategories.add(childCategory);
				//childCategory = new Category(Category.ID_QNA);
				//childCategory.setName(MoumiConfig.getMessageBundle().getString("moumi.message.board.qna"));
				childCategory.setPriority(2);
				childCategories.add(childCategory);
				childCategory = new Category(Category.ID_PDS);
				childCategory.setName(MoumiConfig.getMessageBundle().getString("moumi.message.board.pds"));
				childCategory.setPriority(3);
				childCategories.add(childCategory);
				upperCategory.setChildCategories(childCategories);
				pm.makePersistentAll(childCategories);
			}
			try {
				pm.getObjectById(Category.class, Category.ID_TOT_DOC_COMMENT);
			} catch (JDOObjectNotFoundException jonfe) {
				pm.makePersistent(new Category(Category.ID_TOT_DOC_COMMENT, MoumiConfig.getMessageBundle().getString(
						"moumi.message.tot_doc.comment")));
			}

			tx.commit();
		} finally {
			if (tx.isActive())
				tx.rollback();
			pm.close();
		}

	}
}
