/*
 * Copyright (C) 2016 favdb
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package storybook.exim.importer;

import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import storybook.model.EntityUtil;
import storybook.model.Model;
import storybook.model.book.Book;
import storybook.model.hbn.dao.CategoryDAO;
import storybook.model.hbn.dao.ChapterDAO;
import storybook.model.hbn.dao.DAOutil;
import storybook.model.hbn.dao.EventDAO;
import storybook.model.hbn.dao.GenderDAO;
import storybook.model.hbn.dao.IdeaDAO;
import storybook.model.hbn.dao.ItemDAO;
import storybook.model.hbn.dao.ItemlinkDAO;
import storybook.model.hbn.dao.LocationDAO;
import storybook.model.hbn.dao.MemoDAO;
import storybook.model.hbn.dao.PartDAO;
import storybook.model.hbn.dao.PersonDAO;
import storybook.model.hbn.dao.RelationDAO;
import storybook.model.hbn.dao.SceneDAO;
import storybook.model.hbn.dao.StrandDAO;
import storybook.model.hbn.dao.TagDAO;
import storybook.model.hbn.dao.TaglinkDAO;
import storybook.model.hbn.dao._GenericDAO;
import storybook.model.hbn.entity.AbstractEntity;
import storybook.model.hbn.entity.Attribute;
import storybook.model.hbn.entity.Attributes;
import storybook.model.hbn.entity.Category;
import storybook.model.hbn.entity.Chapter;
import storybook.model.hbn.entity.Event;
import storybook.model.hbn.entity.Gender;
import storybook.model.hbn.entity.Idea;
import storybook.model.hbn.entity.Item;
import storybook.model.hbn.entity.Itemlink;
import storybook.model.hbn.entity.Location;
import storybook.model.hbn.entity.Memo;
import storybook.model.hbn.entity.Part;
import storybook.model.hbn.entity.Person;
import storybook.model.hbn.entity.Relationship;
import storybook.model.hbn.entity.Scene;
import storybook.model.hbn.entity.Strand;
import storybook.model.hbn.entity.Tag;
import storybook.model.hbn.entity.Taglink;
import storybook.tools.LOG;
import storybook.tools.xml.XmlUtil;
import storybook.ui.MainFrame;

/**
 *
 * @author favdb
 */
public class ImportUtil {

	private ImportUtil() {
		throw new IllegalStateException("Utility class");
	}

	static List<ImportEntity> list(Importer imp, String tobj) {
		//App.trace("ImportEntities.list("+imp.fileName+","+tobj+")");
		if (!imp.isOpened()) {
			LOG.err("error Importer is not opened");
			return (new ArrayList<>());
		}
		if (imp.isXml()) {
			return (listXml(imp, tobj));
		}
		return (listH2(imp, tobj));
	}

	static List<ImportEntity> listXml(Importer imp, String tobj) {
		//App.trace("ImportEntities.Xml("+imp.fileName+","+tobj+")");
		List<ImportEntity> entities = new ArrayList<>();
		NodeList nodes = imp.rootNode.getElementsByTagName(tobj);
		for (int i = 0; i < nodes.getLength(); i++) {
			Node n = nodes.item(i);
			if (!n.getParentNode().equals(imp.rootNode)) {
				continue;
			}
			switch (Book.getTYPE(tobj)) {
				case STRAND:
					Strand strand = Strand.fromXml(n);
					if (strand.getId() > 1) {
						entities.add(new ImportEntity(strand, n));
					}
					break;
				case PART:
					Part part = Part.fromXml(n);
					if (part.getId() > 1) {
						entities.add(new ImportEntity(part, n));
					}
					break;
				case CHAPTER:
					entities.add(new ImportEntity(Chapter.fromXml(n), n));
					break;
				case SCENE:
					entities.add(new ImportEntity(Scene.fromXml(n), n));
					break;
				case PERSON:
					entities.add(new ImportEntity(Person.fromXml(n), n));
					break;
				case GENDER:
					Gender gender = Gender.fromXml(n);
					//import only other than male female
					if (gender.getId() > 2) {
						entities.add(new ImportEntity(gender, n));
					}
					break;
				case CATEGORY:
					Category category = Category.fromXml(n);
					//import only other than central and secondary characters
					if (category.getId() > 2) {
						entities.add(new ImportEntity(category, n));
					}
					break;
				case LOCATION:
					entities.add(new ImportEntity(Location.fromXml(n), n));
					break;
				case ITEM:
					entities.add(new ImportEntity(Item.fromXml(n), n));
					break;
				case ITEMLINK:
					entities.add(new ImportEntity(Itemlink.fromXml(n), n));
					break;
				case TAG:
					entities.add(new ImportEntity(Tag.fromXml(n), n));
					break;
				case TAGLINK:
					entities.add(new ImportEntity(Taglink.fromXml(n), n));
					break;
				case EVENT:
					entities.add(new ImportEntity(Event.fromXml(n), n));
					break;
				default:
					break;
			}
		}
		return (entities);
	}

	@SuppressWarnings("unchecked")
	static List<ImportEntity> listH2(Importer imp, String tobj) {
		Session session = imp.bookModel.beginTransaction();
		_GenericDAO<?, ?> dao = null;
		List<AbstractEntity> entities;
		switch (Book.getTYPE(tobj)) {
			case STRAND:
				dao = new StrandDAO(session);
				break;
			case PART:
				dao = new PartDAO(session);
				break;
			case CHAPTER:
				dao = new ChapterDAO(session);
				break;
			case SCENE:
				dao = new SceneDAO(session);
				break;
			case PERSON:
				dao = new PersonDAO(session);
				break;
			case CATEGORY:
				dao = new CategoryDAO(session);
				break;
			case GENDER:
				dao = new GenderDAO(session);
				break;
			case LOCATION:
				dao = new LocationDAO(session);
				break;
			case ITEM:
				dao = new ItemDAO(session);
				break;
			case ITEMLINK:
				dao = new ItemlinkDAO(session);
				break;
			case TAG:
				dao = new TagDAO(session);
				break;
			case TAGLINK:
				dao = new TaglinkDAO(session);
				break;
			case IDEA:
				dao = new IdeaDAO(session);
				break;
			case MEMO:
				dao = new MemoDAO(session);
				break;
			case RELATION:
				dao = new RelationDAO(session);
				break;
			case EVENT:
				dao = new EventDAO(session);
				break;
			default:
				break;
		}
		List<ImportEntity> ientities = new ArrayList<>();
		if (dao != null) {
			entities = (List<AbstractEntity>) dao.findAll();
			for (AbstractEntity entity : entities) {
				ientities.add(new ImportEntity(entity, null));
			}
			imp.bookModel.commit();
		}
		return (ientities);
	}

	static AbstractEntity updateEntity(MainFrame mainFrame, ImportEntity newEntity, AbstractEntity oldEntity) {
		/*App.trace("ImportUtil.updateEntity("+"mainFrame,"+
			EntityUtil.getClassName(newEntity.entity) +","+
			EntityUtil.getClassName(oldEntity)+")");*/
		if (oldEntity != null) {
			newEntity.entity.setId(oldEntity.getId());
		} else {
			newEntity.entity.setId(-1L);
		}
		switch (Book.getTYPE(newEntity.entity)) {
			case STRAND:
				return (updateStrand(mainFrame, newEntity, (Strand) oldEntity));
			case PART:
				return (updatePart(mainFrame, newEntity, (Part) oldEntity));
			case CHAPTER:
				return (updateChapter(mainFrame, newEntity, (Chapter) oldEntity));
			case SCENE:
				return (updateScene(mainFrame, newEntity, (Scene) oldEntity));
			case CATEGORY:
				return (updateCategory(mainFrame, newEntity, (Category) oldEntity));
			case GENDER:
				return (updateGender(mainFrame, newEntity, (Gender) oldEntity));
			case PERSON:
				return (updatePerson(mainFrame, newEntity, (Person) oldEntity));
			case LOCATION:
				return (updateLocation(mainFrame, newEntity, (Location) oldEntity));
			case ITEM:
				return (updateItem(mainFrame, newEntity, (Item) oldEntity));
			case TAG:
				return (updateTag(mainFrame, newEntity, (Tag) oldEntity));
			case ITEMLINK:
				return (updateItemlink(mainFrame, newEntity, (Itemlink) oldEntity));
			case TAGLINK:
				return (updateTaglink(mainFrame, newEntity, (Taglink) oldEntity));
			case IDEA:
				return (updateIdea(mainFrame, newEntity, (Idea) oldEntity));
			case MEMO:
				return (updateMemo(mainFrame, newEntity, (Memo) oldEntity));
			case RELATION:
				return (updateRelation(mainFrame, newEntity, (Relationship) oldEntity));
			case EVENT:
				return (updateEvent(mainFrame, newEntity, (Event) oldEntity));
			default:
				LOG.err("Unknown object type \"" + EntityUtil.getClassName(newEntity.entity) + "\" do nothing");
		}
		return newEntity.entity;
	}

	private static AbstractEntity updateStrand(MainFrame mainFrame,
	   ImportEntity newEntity, Strand oldEntity) {
		//App.trace("ImportUtil.updateStrand(...)");
		// as is, no link to update
		Strand entity = (Strand) newEntity.entity;
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updatePart(MainFrame mainFrame,
	   ImportEntity newEntity, Part oldEntity) {
		//App.trace("ImportUtil.updatePart(...)");
		// creationTime, doneTime, objectiveTime, objectiveChars not modified
		Part entity = (Part) newEntity.entity;
		if (oldEntity != null) {
			entity.setCreationTime(oldEntity.getCreationTime());
			entity.setDoneTime(oldEntity.getDoneTime());
			entity.setObjectiveChars(oldEntity.getObjectiveChars());
			entity.setObjectiveTime(oldEntity.getObjectiveTime());
			if (oldEntity.hasSuperpart()) {
				entity.setSuperpart(oldEntity.getSuperpart());
			}
		}
		if (newEntity.node != null) {
			String str = XmlUtil.getText(newEntity.node, "superpart");
			if (!str.isEmpty()) {
				entity.setSuperpart(DAOutil.getPartDAO(mainFrame).findTitle(str));
			}
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateChapter(MainFrame mainFrame, ImportEntity newEntity, Chapter oldEntity) {
		//App.trace("ImportUtil.updateChapter(...)");
		Chapter entity = (Chapter) newEntity.entity;
		// creationTime, doneTime, objectiveTime, objectiveChars not modified
		if (oldEntity != null) {
			entity.setCreationTime(oldEntity.getCreationTime());
			entity.setDoneTime(oldEntity.getDoneTime());
			entity.setObjectiveChars(oldEntity.getObjectiveChars());
			entity.setObjectiveTime(oldEntity.getObjectiveTime());
		}
		if (newEntity.node != null) {
			String str = XmlUtil.getText(newEntity.node, "part");
			if (!str.isEmpty()) {
				entity.setPart(DAOutil.getPartDAO(mainFrame).findTitle(str));
			}
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateScene(MainFrame mainFrame, ImportEntity newEntity, Scene oldEntity) {
		//App.trace("ImportUtil.updateScene(...)");
		Scene entity = (Scene) newEntity.entity;
		if (oldEntity != null) {
			entity.setStrand(oldEntity.getStrand());
			entity.setChapter(oldEntity.getChapter());
			entity.setPersons(oldEntity.getPersons());
			entity.setItems(oldEntity.getItems());
		}
		if (newEntity.node != null) {
			String str = XmlUtil.getText(newEntity.node, "strand");
			if (!str.isEmpty()) {
				entity.setStrand(DAOutil.getStrandDAO(mainFrame).findTitle(str));
			}
			str = XmlUtil.getText(newEntity.node, "chapter");
			if (!str.isEmpty()) {
				entity.setChapter(DAOutil.getChapterDAO(mainFrame).findTitle(str));
			}
			List<String> list;
			list = XmlUtil.getList(newEntity.node, "strands");
			if (!list.isEmpty()) {
				List<Strand> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getStrandDAO(mainFrame).findTitle(xstr));
				}
				entity.setStrands(lstEntity);
			}
			list = XmlUtil.getList(newEntity.node, "persons");
			if (!list.isEmpty()) {
				List<Person> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getPersonDAO(mainFrame).findTitle(xstr));
				}
				entity.setPersons(lstEntity);
			}
			list = XmlUtil.getList(newEntity.node, "locations");
			if (!list.isEmpty()) {
				List<Location> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getLocationDAO(mainFrame).findTitle(xstr));
				}
				entity.setLocations(lstEntity);
			}
			list = XmlUtil.getList(newEntity.node, "items");
			if (!list.isEmpty()) {
				List<Item> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getItemDAO(mainFrame).findTitle(xstr));
				}
				entity.setItems(lstEntity);
			}
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateCategory(MainFrame mainFrame, ImportEntity newEntity, Category oldEntity) {
		//App.trace("ImportUtil.updateCategory(...)");
		Category entity = (Category) newEntity.entity;
		if (oldEntity != null) {
			entity.setSup(oldEntity.getSup());
		}
		if (newEntity.node != null) {
			String str = XmlUtil.getText(newEntity.node, "sup");
			if (!str.isEmpty()) {
				entity.setSup(DAOutil.getCategoryDAO(mainFrame).findTitle(str));
			}
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateGender(MainFrame mainFrame, ImportEntity newEntity, Gender oldEntity) {
		//App.trace("ImportUtil.updateGender(...)");
		Gender entity = (Gender) newEntity.entity;
		// as is, no link to update
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updatePerson(MainFrame mainFrame, ImportEntity newEntity, Person oldEntity) {
		//App.trace("ImportUtil.updatePerson(...)");
		Person entity = (Person) newEntity.entity;
		// gender, category, attributes not modified
		if (oldEntity != null) {
			entity.setGender(oldEntity.getGender());
			entity.setCategory(oldEntity.getCategory());
			entity.setAttributes(oldEntity.getAttributes());
		}
		if (newEntity.node != null) {
			String str;
			str = XmlUtil.getText(newEntity.node, "gender");
			if (!str.isEmpty()) {
				entity.setGender(DAOutil.getGenderDAO(mainFrame).findTitle(str));
			}
			str = XmlUtil.getText(newEntity.node, "category");
			if (!str.isEmpty()) {
				entity.setCategory(DAOutil.getCategoryDAO(mainFrame).findTitle(str));
			}
			List<String> list;
			list = XmlUtil.getList(newEntity.node, "attribute");
			if (!list.isEmpty()) {
				List<Attribute> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					String key, val;
					key = xstr.substring(1, xstr.indexOf("]"));
					val = xstr.substring(xstr.indexOf("]") + 1);
					Attribute attribute = new Attribute(key, val);
					Attribute findEntity = Attributes.find(mainFrame, key, val);
					if (findEntity == null) {
						Model model = mainFrame.getBookModel();
						Session session = model.beginTransaction();
						session.save(attribute);
						model.commit();
						findEntity = Attributes.find(mainFrame, key, val);
						if (findEntity != null) {
							lstEntity.add(findEntity);
						}
					} else {
						lstEntity.add(findEntity);
					}
				}
				entity.setAttributes(lstEntity);
			}
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateLocation(MainFrame mainFrame, ImportEntity newEntity, Location oldEntity) {
		//App.trace("ImportUtil.updateLocation(...)");
		Location entity = (Location) newEntity.entity;
		if (oldEntity != null) {
			entity.setSite(oldEntity.getSite());
		}
		if (newEntity.node != null) {
			String str;
			str = XmlUtil.getText(newEntity.node, "site");
			if (!str.isEmpty()) {
				entity.setSite(DAOutil.getLocationDAO(mainFrame).findTitle(str));
			}
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateItem(MainFrame mainFrame,
	   ImportEntity newEntity, Item oldEntity) {
		//App.trace("ImportUtil.updateItem(...)");
		Item entity = (Item) newEntity.entity;
		if (oldEntity != null) {
			entity.setType(oldEntity.getType());
		}
		if (newEntity.node != null) {
			//update nothing
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateTag(MainFrame mainFrame, ImportEntity newEntity, Tag oldEntity) {
		//App.trace("ImportUtil.updateTag(...)");
		Tag entity = (Tag) newEntity.entity;
		if (oldEntity != null) {
			entity.setType(oldEntity.getType());
		}
		if (newEntity.node != null) {
			//update nothing
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateIdea(MainFrame mainFrame, ImportEntity newEntity, Idea oldEntity) {
		//App.trace("ImportUtil.updateIdea(...)");
		Idea entity = (Idea) newEntity.entity;
		// nothing to change
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateMemo(MainFrame mainFrame, ImportEntity newEntity, Memo oldEntity) {
		//App.trace("ImportUtil.updateMemo(...)");
		Memo entity = (Memo) newEntity.entity;
		// nothing to change
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateTaglink(MainFrame mainFrame, ImportEntity newEntity, Taglink oldEntity) {
		//App.trace("ImportUtil.updateTaglink(...)");
		Taglink entity = (Taglink) newEntity.entity;
		if (oldEntity != null) {
		}
		if (newEntity.node != null) {
			//update nothing
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateItemlink(MainFrame mainFrame, ImportEntity newEntity, Itemlink oldEntity) {
		//App.trace("ImportUtil.updateItemlink(...)");
		Itemlink entity = (Itemlink) newEntity.entity;
		if (oldEntity != null) {
		}
		if (newEntity.node != null) {
			//update nothing
		}
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateEvent(MainFrame mainFrame, ImportEntity newEntity, Event oldEntity) {
		//App.trace(TT+".updateEvent(...)");
		Event entity = (Event) newEntity.entity;
		// nothing to change
		return ((AbstractEntity) entity);
	}

	private static AbstractEntity updateRelation(MainFrame mainFrame, ImportEntity newEntity, Relationship oldEntity) {
		//App.trace(TT+".updateRelation(...)");
		Relationship entity = (Relationship) newEntity.entity;
		if (oldEntity != null) {
		}
		if (newEntity.node != null) {
			String str;
			str = XmlUtil.getText(newEntity.node, "person1");
			if (!str.isEmpty()) {
				entity.setPerson1(DAOutil.getPersonDAO(mainFrame).findTitle(str));
			}
			str = XmlUtil.getText(newEntity.node, "person2");
			if (!str.isEmpty()) {
				entity.setPerson1(DAOutil.getPersonDAO(mainFrame).findTitle(str));
			}
			List<String> list;
			list = XmlUtil.getList(newEntity.node, "persons");
			if (!list.isEmpty()) {
				List<Person> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getPersonDAO(mainFrame).findTitle(xstr));
				}
				entity.setPersons(lstEntity);
			}
			list = XmlUtil.getList(newEntity.node, "locations");
			if (!list.isEmpty()) {
				List<Location> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getLocationDAO(mainFrame).findTitle(xstr));
				}
				entity.setLocations(lstEntity);
			}
			list = XmlUtil.getList(newEntity.node, "items");
			if (!list.isEmpty()) {
				List<Item> lstEntity = new ArrayList<>();
				for (String xstr : list) {
					lstEntity.add(DAOutil.getItemDAO(mainFrame).findTitle(xstr));
				}
				entity.setItems(lstEntity);
			}
		}
		return ((AbstractEntity) entity);
	}

}
