package storybook.ui.panel.tree;

import java.awt.Point;
import java.awt.dnd.DnDConstants;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.hibernate.Session;
import storybook.ctrl.Ctrl;
import storybook.model.Model;
import storybook.model.hbn.entity.Scenes;
import storybook.model.hbn.dao.ChapterDAO;
import storybook.model.hbn.dao.PartDAO;
import storybook.model.hbn.entity.Chapter;
import storybook.model.hbn.entity.Part;
import storybook.model.hbn.entity.Scene;
import storybook.ui.MainFrame;

public class DefaultTreeTransferHandler extends AbstractTreeTransferHandler {

	private static final String TT = "DefaultTreeTransferHandler";

	public DefaultTreeTransferHandler(TreePanel treePanel, int action) {
		super(treePanel, action, true);
	}

	@Override
	public boolean canPerformAction(Tree target, TreeNode draggedNode, int action, Point location) {
		TreePath pathTarget = target.getPathForLocation(location.x, location.y);
		if (pathTarget == null) {
			target.setSelectionPath(null);
			return (false);
		}
		target.setSelectionPath(pathTarget);
		if (action == DnDConstants.ACTION_MOVE) {
			DefaultMutableTreeNode node = (DefaultMutableTreeNode) pathTarget.getLastPathComponent();
			Object draggedObject = ((DefaultMutableTreeNode) draggedNode).getUserObject();
			if (node != null) {
				Object targetObject = node.getUserObject();
				if (targetObject != null) {
					if (draggedObject instanceof Scene) {
						return (targetObject instanceof Chapter) || (targetObject instanceof Scene);
					} else if (draggedObject instanceof Chapter) {
						return (targetObject instanceof Part) || (targetObject instanceof Chapter);
					}
				}
			}
		}
		return (false);
	}

	@Override
	public boolean executeDrop(Tree targetTree, TreeNode draggedNode, TreeNode targetNode, int action) {
		if (action == DnDConstants.ACTION_MOVE) {
			Object draggedObject = ((DefaultMutableTreeNode) draggedNode).getUserObject();
			Object targetObject = ((DefaultMutableTreeNode) targetNode).getUserObject();

			if ((draggedObject instanceof Scene) && (targetObject instanceof Chapter)) {
				dropSceneInChapter((Scene) draggedObject, (Chapter) targetObject);
			} else if ((draggedObject instanceof Scene) && (targetObject instanceof Scene)) {
				dropSceneBeforeScene((Scene) draggedObject, (Scene) targetObject);
			} else if ((draggedObject instanceof Chapter) && (targetObject instanceof Part)) {
				dropChapterInPart((Chapter) draggedObject, (Part) targetObject);
			} else if ((draggedObject instanceof Chapter) && (targetObject instanceof Chapter)) {
				dropChapterBeforeChapter((Chapter) draggedObject, (Chapter) targetObject);
			}
			return (true);
		}
		return (false);
	}

	private void dropChapterBeforeChapter(Chapter dragged, Chapter target) {
		MainFrame frame = (MainFrame) SwingUtilities.getWindowAncestor(getTree());
		Model model = frame.getBookModel();
		Session session = model.beginTransaction();
		PartDAO dao = new PartDAO(session);
		List<Chapter> toUpdate = new ArrayList<>();
		List<Chapter> chapters = dao.findChapters(target.getPart());
		int refChapterNumber = target.getChapterno();
		for (Chapter chapter : chapters) {
			int chapterNum = chapter.getChapterno();
			if (!chapter.equals(dragged) && chapterNum >= refChapterNumber) {
				chapter.setChapterno(chapterNum + 1);
				toUpdate.add(chapter);
			}
		}
		dragged.setPart(target.getPart());
		dragged.setChapterno(refChapterNumber);
		model.commit();
		Ctrl ctrl = frame.getBookController();
		ctrl.updateEntity(dragged);
		for (Chapter chapter : toUpdate) {
			ctrl.updateEntity(chapter);
		}
		ctrl.updateEntity(target.getPart());
		Session session1 = model.beginTransaction();
		PartDAO dao1 = new PartDAO(session1);
		int newNum = 1;
		List<Chapter> chapters1 = dao1.findChapters(target.getPart());
		for (Chapter chapter : chapters1) {
			chapter.setChapterno(newNum++);
		}
		model.commit();
		for (Chapter chapter : chapters1) {
			ctrl.updateEntity(chapter);
		}
		ctrl.updateEntity(target.getPart());
		getTreePanel().treeRefresh();
		frame.setUpdated();
	}

	private void dropChapterInPart(Chapter dragged, Part target) {
		MainFrame frame = (MainFrame) SwingUtilities.getWindowAncestor(getTree());
		Model model = frame.getBookModel();
		Session session = model.beginTransaction();
		PartDAO dao = new PartDAO(session);
		List<Chapter> chapters = dao.findChapters(target);
		int lastChapterNumber = 0;
		for (Chapter chapter : chapters) {
			int chapterNum = chapter.getChapterno();
			if (chapterNum > lastChapterNumber) {
				lastChapterNumber = chapterNum;
			}
		}
		dragged.setPart(target);
		dragged.setChapterno(lastChapterNumber + 1);
		model.commit();
		Ctrl ctrl = frame.getBookController();
		ctrl.updateEntity(dragged);
		ctrl.updateEntity(target);
		getTreePanel().treeRefresh();
		frame.setUpdated();
	}

	private void dropSceneBeforeScene(Scene dragged, Scene target) {
		MainFrame frame = (MainFrame) SwingUtilities.getWindowAncestor(getTree());
		Model model = frame.getBookModel();
		Session session = model.beginTransaction();
		ChapterDAO dao = new ChapterDAO(session);
		List<Scene> toUpdate = new ArrayList<>();
		List<Scene> scenes = dao.findScenes(target.getChapter());
		int refSceneNumber = target.getSceneno();
		for (Scene scene : scenes) {
			int sceneNum = scene.getSceneno();
			if (!scene.equals(dragged)
					&& sceneNum >= refSceneNumber) {
				scene.setSceneno(sceneNum + 1);
				toUpdate.add(scene);
			}
		}
		dragged.setChapter(target.getChapter());
		dragged.setSceneno(refSceneNumber);
		model.commit();
		Ctrl ctrl = frame.getBookController();
		ctrl.updateEntity(dragged);
		for (Scene scene : toUpdate) {
			ctrl.updateEntity(scene);
		}
		ctrl.updateEntity(target.getChapter());
		Session session1 = model.beginTransaction();
		ChapterDAO dao1 = new ChapterDAO(session1);
		int newNum = 1;
		List<Scene> scenes1 = dao1.findScenes(target.getChapter());
		for (Scene scene : scenes1) {
			scene.setSceneno(newNum++);
		}
		model.commit();
		for (Scene scene : scenes1) {
			ctrl.updateEntity(scene);
		}
		ctrl.updateEntity(target.getChapter());
		getTreePanel().treeRefresh();
		frame.setUpdated();
	}

	private void dropSceneInChapter(Scene dragged, Chapter target) {
		//LOG.trace(TT + ".dropSceneInChapter(dragged=" + dragged.getName() + ", target=" + target.getName() + ")");
		MainFrame frame = (MainFrame) SwingUtilities.getWindowAncestor(getTree());
		Model model = frame.getBookModel();
		Session session = model.beginTransaction();
		ChapterDAO dao = new ChapterDAO(session);
		List<Scene> scenes = dao.findScenes(target);
		int lastSceneNumber = 0;
		for (Scene scene : scenes) {
			lastSceneNumber = Math.max(lastSceneNumber, scene.getSceneno());
		}
		if (target.getChapterno() == -1) {
			dragged.setChapter(null);
		} else {
			dragged.setChapter(target);
		}
		int c = 1;
		if (!frame.getPref().sceneIsRenumAuto()) {
			c = frame.getPref().sceneGetRenumInc();
		}
		dragged.setSceneno(lastSceneNumber + c);
		model.commit();
		Ctrl ctrl = frame.getBookController();
		ctrl.updateEntity(dragged);
		if (target.getChapterno() != -1) {
			ctrl.updateEntity(target);
		}
		Scenes.renumber(frame, target);
		frame.setUpdated();
	}

}
