package org.richfaces.realworld.tree;

import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.SelectItem;
import javax.imageio.ImageIO;

import org.ajax4jsf.context.AjaxContext;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Begin;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Synchronized;
import org.jboss.seam.annotations.TransactionPropagationType;
import org.jboss.seam.annotations.Transactional;
import org.richfaces.component.UIDatascroller;
import org.richfaces.component.UIDragSupport;
import org.richfaces.component.UITree;
import org.richfaces.component.UITreeNode;
import org.richfaces.component.html.HtmlTree;
import org.richfaces.event.DataScrollerEvent;
import org.richfaces.event.DropEvent;
import org.richfaces.event.NodeSelectedEvent;
import org.richfaces.model.TreeNode;
import org.richfaces.model.TreeRowKey;
import org.richfaces.realworld.domain.Album;
import org.richfaces.realworld.domain.Image;
import org.richfaces.realworld.domain.User;
import org.richfaces.realworld.fileupload.FileManager;
import org.richfaces.realworld.util.NavigationEnum;
import org.richfaces.realworld.util.SelectedImageIndex;

@Name("treeSelectionManager")
@Scope(ScopeType.CONVERSATION)
@Synchronized(timeout=200000)
public class TreeSelectionManager implements Serializable{

	@In(required=false)
	private User user;
	
	private NavigationEnum mainArea;
	
	@In(required=false)  @Out(required=false)
	private Image selectedImage;

	@In(required=false)  @Out(required=false)
	private Album selectedAlbum;
	
	@In(required=false) @Out(required=false)
	private SelectedImageIndex selectedImageIndex;
	
	@In(create=true)
	FileManager fileManager;
	
	@In(required=false)
	TreeActionManager treeActionManager;

	private String nodeTitle;

	public void showFileUpload(TreeAlbumItem item){
		selectedAlbum = item.getAlbum();
		if(item.isLeaf()){
			selectedImage=null;
		}else{
			selectedImage = ((TreeImageItem)(item.getImages().get(0))).getImage();
		}
		this.setMainArea(NavigationEnum.FILE_UPLOAD);
	}
	
	@Observer("updateMainArea")
    public void updateMainArea(NavigationEnum mainArea) {
        this.setMainArea(mainArea);
    }

	public void scrollerListener(DataScrollerEvent event) {
		List<Image> images = selectedAlbum.getImages();
		if (event.getNewScrolVal().equals("previous")) {
			for(int index = 0 ; index < images.size(); index++){
				if(images.get(index) == selectedImage){
					selectedImage = images.get(index - 1);
					selectedImageIndex.setSelectedImageIndex(index);
				}
			}
		} else if (event.getNewScrolVal().equals("last")) {
			selectedImage = images.get(images.size() - 1);
			selectedImageIndex.setSelectedImageIndex(images.size());
		} else if (event.getNewScrolVal().equals("next")) {
			for(int index = 0 ; index < images.size(); index++){
				if(images.get(index) == selectedImage){
						selectedImage = images.get(index + 1);
						selectedImageIndex.setSelectedImageIndex(index + 2);
						return;
				}
			}
		} else if (event.getNewScrolVal().equals("first")) {
			selectedImage = images.get(0);
			selectedImageIndex.setSelectedImageIndex(1);
		}

	}
	
	public void dropListener(DropEvent dropEvent) {
		
		// resolve drag destination attributes
		UITreeNode destNode = (dropEvent.getSource() instanceof UITreeNode) ? (UITreeNode) dropEvent.getSource() : null;
		UITree destTree = destNode != null ? destNode.getUITree() : null;
		TreeRowKey dropNodeKey = (dropEvent.getDropValue() instanceof TreeRowKey) ? (TreeRowKey) dropEvent.getDropValue() : null;
		TreeNode droppedInNode = dropNodeKey != null ? destTree.getTreeNode(dropNodeKey) : null;
		
		// resolve drag source attributes
		UITreeNode srcNode = (dropEvent.getDraggableSource() instanceof UITreeNode) ? (UITreeNode) dropEvent.getDraggableSource() : null;
		UITree srcTree = srcNode != null ? srcNode.getUITree() : null;
		TreeRowKey dragNodeKey = (dropEvent.getDragValue() instanceof TreeRowKey) ? (TreeRowKey) dropEvent.getDragValue() : null;
		TreeNode draggedNode = dragNodeKey != null ? srcTree.getTreeNode(dragNodeKey) : null;
		if (dropEvent.getDraggableSource() instanceof UIDragSupport && srcTree == null && draggedNode == null && dropEvent.getDragValue() instanceof TreeNode) {	    
		    srcTree = destTree;
		    draggedNode = (TreeNode) dropEvent.getDragValue();
		    dragNodeKey = srcTree.getTreeNodeRowKey(draggedNode) instanceof TreeRowKey ? (TreeRowKey) srcTree.getTreeNodeRowKey(draggedNode) : null;
		}

		// Note: check if we dropped node on to itself or to item instead of
		// folder here
		if (droppedInNode != null && (droppedInNode.equals(draggedNode) || droppedInNode.getParent().getParent() != null || draggedNode.getParent().getParent() == null)) {
		    System.out.println("Warning: Can't drop on itself or to pic itself! Also can't move folders");
		    return;
		}

		if (dropNodeKey != null) {
		    // add destination node for rerender
		    destTree.addRequestKey(dropNodeKey);

		    Object state = null;
		    if (dragNodeKey != null) { // Drag from this or other tree
			TreeNode parentNode = draggedNode.getParent();
			// 1. remove node from tree
			state = srcTree.removeNode(dragNodeKey);
			// 2. add parent for rerender
			Object rowKey = srcTree.getTreeNodeRowKey(parentNode);
			srcTree.addRequestKey(rowKey);
			//TODO refactor this code
			if (dropEvent.getDraggableSource() instanceof UIDragSupport) {
			    // if node was gragged in it's parent place dragged node to
			    // the end of selected nodes in grid
			    if (droppedInNode.equals(parentNode)) {
			    }
			}
		    } else if (dropEvent.getDragValue() != null) { // Drag from some
								    // drag source
			draggedNode.setData(dropEvent.getDragValue().toString());
		    }

		    // generate new node id
		    Object id = getNewId(destTree.getTreeNode(dropNodeKey));
		    destTree.addNode(dropNodeKey, draggedNode, id, state);
		}

		AjaxContext ac = AjaxContext.getCurrentInstance();
		ac.addRenderedArea("mainform:imageList");
		Image draggedImage = ((TreeImageItem)draggedNode).getImage();
		draggedImage.setAlbumName(((TreeAlbumItem)droppedInNode).getAlbum().getName());
		treeActionManager.editImage(draggedImage);
		// Add destination tree to reRender
		try {
		    ac.addComponentToAjaxRender(destTree);
		} catch (Exception e) {
		    System.err.print(e.getMessage());
		}
		
	    }
	
	private Object getNewId(TreeNode parentNode) {
		Map<Object, TreeNode> childs = new HashMap<Object, TreeNode>();
		Iterator<Map.Entry<Object, TreeNode>> iter = parentNode.getChildren();
		while (iter != null && iter.hasNext()) {
		    Map.Entry<Object, TreeNode> entry = iter.next();
		    childs.put(entry.getKey(), entry.getValue());
		}

		Integer index = 1;
		while (childs.containsKey(index)) {
		    index++;
		}
		return index;
	    }

	public Boolean adviseNodeSelected(UITree tree) {
		TreeRowKey treeRowKey = (TreeRowKey) tree.getRowKey();
		TreeNode treeNode = (TreeNode) tree.getRowData(treeRowKey);
		if (treeNode instanceof TreeAlbumItem) {
			TreeAlbumItem currentNode = (TreeAlbumItem) treeNode;
			return currentNode.getAlbum() == selectedAlbum;
		} else if (treeNode instanceof TreeImageItem) {
			return ((TreeImageItem) treeNode).getImage() == selectedImage;
		}
		return null;
	}

	public Boolean adviseNodeOpened(UITree tree) {
		TreeRowKey treeRowKey = (TreeRowKey) tree.getRowKey();
		TreeNode treeNode = (TreeNode) tree.getRowData(treeRowKey);
		if (treeNode instanceof TreeAlbumItem) {
			TreeAlbumItem currentNode = (TreeAlbumItem) treeNode;
			return currentNode.getAlbum() == selectedAlbum;
		}
		return null;
	}

	public void processSelection(NodeSelectedEvent event) {
		try{
		HtmlTree tree = (HtmlTree) event.getComponent();
		if (tree.getRowData() instanceof TreeImageItem) {
			nodeTitle = ((TreeImageItem) (tree.getRowData())).getImage()
					.getName();
		} else if (tree.getRowData() instanceof TreeAlbumItem) {
			nodeTitle = ((TreeAlbumItem) (tree.getRowData())).getAlbum()
					.getName();
		}
		TreeNode<String> currentNode = tree.getModelTreeNode(tree.getRowKey());
		if(currentNode instanceof TreeImageItem){
				Image image = ((TreeImageItem)currentNode).getImage();
				selectedImage = image;
				Album album = ((TreeAlbumItem)currentNode.getParent()).getAlbum();
				if(album != selectedAlbum){
					selectedAlbum = album;
				}
				int index = album.getIndex(image);
				setDataScrollerIndex(index);
				return;
		}else if(currentNode instanceof TreeAlbumItem){
			TreeAlbumItem node = (TreeAlbumItem)currentNode;
			setDataScrollerIndex(0);
			if (node.isLeaf()) {
				selectedImage = null;
				Album album = node.getAlbum();
				selectedAlbum = album;
			}else{
				if(node.getAlbum() == selectedAlbum){
					return;
				}else{
					selectedAlbum = node.getAlbum();
						selectedImage = node.getAlbum().getImages().get(0);
				}		
			}
		}
		}
		catch(Exception e){
			//Bla-bla-bla
		}
	}

	public void updateScroller(ActionEvent event){
		this.setDataScrollerIndex(selectedImageIndex.getSelectedImageIndex()- 1);
	}
	
	private void setDataScrollerIndex(int index) {
		UIComponent component = FacesContext.getCurrentInstance().getViewRoot();
		UIDatascroller scroller = (UIDatascroller)component.findComponent("mainform:sc1");
		//scroller.setPage(index+1);
		Map<String, Object> attributes = scroller.getDataTable().getAttributes();
		attributes.put(UIDatascroller.SCROLLER_STATE_ATTRIBUTE, index+1);
		selectedImageIndex.setSelectedImageIndex(index+1);
	}
	
	public void incrementSlideshowIndex() {
		int index = selectedAlbum.getIndex(selectedImage);
		if(selectedAlbum.getImages().size() == index +1){
			index = -1;
		}
		selectedImage = selectedAlbum.getImages().get(index +1);
		UIComponent component = FacesContext.getCurrentInstance().getViewRoot();
		UIDatascroller scroller = (UIDatascroller)component.findComponent("mainform:sc1");
		//scroller.setPage(index+2);
		Map<String, Object> attributes = scroller.getDataTable().getAttributes();
		attributes.put(UIDatascroller.SCROLLER_STATE_ATTRIBUTE, index+2);
		selectedImageIndex.setSelectedImageIndex(index+2);
	}

	public String getNodeTitle() {
		return nodeTitle;
	}

	public void setNodeTitle(String nodeTitle) {
		this.nodeTitle = nodeTitle;
	}

	public NavigationEnum getMainArea() {
		return mainArea;
	}

	public void setMainArea(NavigationEnum mainArea) {
		this.mainArea = mainArea;
	}
	
	public SelectItem[] getAvailableIndexOfImages(){
		SelectItem[] group = new SelectItem[selectedAlbum.getImages().size()];
		for(int i = 0; i < selectedAlbum.getImages().size(); i++){
			group[i] = new SelectItem(i+1);
		}
		return group;
	}
	
	public void updateSelectedItems(Image image){
		selectedImage = image;
		Integer index = selectedAlbum.getIndex(selectedImage);
		setDataScrollerIndex(index);
	}
}
