package j3deditor.bin.hierarchy;


import j3deditor.bin.hierarchy.util.HNodeType;

import java.util.ArrayList;


/**
 * Contains and manages all scenes.
 *
 * @author Risto Seene
 */
public class HierarchyManager extends HierarchyNode{


	/** contains all scenes attached to this node */
	private ArrayList<J3DeScene> sceneList;

	/** array that contains all selected scenes */
	private J3DeScene[] selectedScenes = null;


	/**
	 * Creates an instance of <code>HierarchyManager</code>.
	 */
	public HierarchyManager(){
		super("ROOT", HNodeType.ROOT, 0);
		sceneList = new ArrayList<J3DeScene>();
	}


	/**
	 * Creates new blank <code>J3DeScene</code> object
	 * and attaches it to this hierarchy node.
	 * 
	 * @return the newly created scene which has been
	 * 	already added to this <code>HierarchyManager</code>
	 */
	public HierarchyNode addNewScene(){
		J3DeScene scene = new J3DeScene("new Scene");
		scene.setParent(this);
		sceneList.add(scene);
		return scene;
	}


	/**
	 * Loads the <code>J3DeScene</code> from specified file
	 * and attaches it to this hierarchy node.
	 *
	 * @param filePath
	 *	the path of file where the scene will be loaded from
	 * @return the newly created scene which has been
	 * 	already added to this <code>HierarchyManager</code>
	 * @throws Exception
	 *	if loading the scene fails
	 */
	public HierarchyNode addNewScene(String filePath) throws Exception{
		String name = filePath.substring(filePath.lastIndexOf(java.io.File.separator) + 1, filePath.lastIndexOf("."));
		J3DeScene scene = new J3DeScene("", filePath);
		scene.setName(name);
		scene.setFile(filePath);
		scene.setParent(this);
		sceneList.add(scene);
		return scene;
	}


	/**
	 * Removes the scene at the specified index.
	 *
	 * @param index
	 *	index of node which will be removed
	 */
	public void removeScene(int index){
		sceneList.remove(index);
	}


	/**
	 * Removes the specified scene node.
	 *
	 * @param child
	 *	child node to be removed
	 */
	public void removeScene(HierarchyNode child){
		removeScene(getIndexOfChild(child));
	}


	/**
	 * Returns the child at the specified index.
	 *
	 * @param index
	 *	index of child
	 * @return Returns the child with the specified index
	 */
	public HierarchyNode getChild(int index){
		return sceneList.get(index);
	}


	/**
	 * Returns the number of children.
	 *
	 * @return Returns the number of children as integer
	 */
	public int getNumberOfChildren(){
		return sceneList.size();
	}


	/**
	 * Returns the index of specified child.
	 *
	 * @param child
	 *	child node which index will be returned
	 * @return Returns the index of specified child
	 */
	public int getIndexOfChild(HierarchyNode child){
		return sceneList.indexOf(child);
	}


	/**
	 * Tests if this node has child which name
	 * equals to the name of the given node.
	 *
	 * @param object
	 *	node which name will be tested
	 * @return Returns <code>true</code> if the name of the given
	 *	node equals to the name of this node,
	 *	otherwise <code>false</code>
	 */
	protected boolean hasNamedChild(HierarchyNode object){
		String name = object.toString();
		for(int i = 0; i < sceneList.size(); i++){
			if(!(sceneList.get(i).equals(object)) && name.equals(sceneList.get(i).toString())){
				return true;
			}
		}
		return false;
	}


	/**
	 * Forces all scenes to copy their selected objects.
	 */
	public void copyFromScenes(){
		for(int i = 0; i < sceneList.size(); i++){
			sceneList.get(i).copyObjects();
		}
	}


	/**
	 * Forces all scenes to cut their selected objects.
	 */
	public void cutFromScenes(){
		for(int i = 0; i < sceneList.size(); i++){
			sceneList.get(i).cutObjects();
		}
	}


	/**
	 * Forces all scenes to paste their copied/cut objects
	 * to the selected scenes.
	 */
	public void pasteToScenes(){
		ArrayList<HierarchyNode> selObj = new ArrayList<HierarchyNode>();
		for(int i = 0; i < sceneList.size(); i++){
			try{
				for(int j = 0; j < sceneList.get(i).getCopiedObjects().length; j++){
					selObj.add(sceneList.get(i).getCopiedObjects()[j]);
				}
			} catch(Throwable t){
			}
		}
		HierarchyNode[] selectedObjects = selObj.toArray(new HierarchyNode[selObj.size()]);

		for(int i = 0; i < selectedScenes.length; i++){
			selectedScenes[i].pasteContent(selectedObjects);
		}
	}


	/**
	 * Forces every scene to delete their selected objects.
	 */
	public void deleteFromScenes(){
		for(int i = 0; i < sceneList.size(); i++){
			if(sceneList.get(i).getSelectedObjects().length > 0){
				sceneList.get(i).deleteObjects(sceneList.get(i).getSelectedObjects());
			}
		}
	}


	/**
	 * Sets all selected nodes.
	 *
	 * @param objects
	 *	array of nodes to be set selected
	 */
	public void setSelectedObjects(HierarchyNode[] objects){
		ArrayList<J3DeScene> scenes = new ArrayList<J3DeScene>();
		ArrayList<HierarchyNode>[] obj = new ArrayList[sceneList.size()];
		for(int i = 0; i < obj.length; i++){
			obj[i] = new ArrayList<HierarchyNode>();
		}

		for(int i = 0; i < objects.length; i++){
			if(objects[i] instanceof J3DeScene){
				scenes.add((J3DeScene)objects[i]);
			} else if(!(objects[i] instanceof HierarchyManager)){
				int index = getIndexOfChild(objects[i].getParent());
				obj[index].add(objects[i]);
			}
		}

		selectedScenes = scenes.toArray(new J3DeScene[scenes.size()]);
		for(int i = 0; i < sceneList.size(); i++){
			sceneList.get(i).setSelectedObjects(obj[i].toArray(new HierarchyNode[obj[i].size()]));
		}
	}


	/**
	 * Returns all selected scenes and objects from all scenes.
	 *
	 * @return Returns array of all selected objects
	 */
	public HierarchyNode[] getSelectedObjects(){
		ArrayList<HierarchyNode> objects = new ArrayList<HierarchyNode>();

		if(selectedScenes != null){
			for(int i = 0; i < selectedScenes.length; i++){
				objects.add(selectedScenes[i]);
			}
		}
		for(int i = 0; i < sceneList.size(); i++){
			try{
				for(int j = 0; j < sceneList.get(i).getSelectedObjects().length; j++){
					objects.add(sceneList.get(i).getSelectedObjects()[j]);
				}
			} catch(Throwable t){
			}
		}

		return objects.toArray(new HierarchyNode[objects.size()]);
	}


	/**
	 * Tests if there are any objects copied from
	 * any scene.
	 *
	 * @return Returns <code>true</code> if any scene has
	 *	copied objects,
	 *	otherwise <code>false</code>
	 */
	public boolean hasCopiedObjects(){
		for(int i = 0; i < sceneList.size(); i++){
			if(sceneList.get(i).getCopiedObjects().length > 0){
				return true;
			}
		}

		return false;
	}

}
