/* $Id: SpreadTree.java 683 2013-03-17 16:33:49Z shayashi $ */
package smart_gs.logical;

import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
import java.awt.dnd.DragSourceDragEvent;
import java.awt.dnd.DragSourceDropEvent;
import java.awt.dnd.DragSourceEvent;
import java.awt.dnd.DragSourceListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.awt.dnd.DragSource;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.JOptionPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import smart_gs.GSConstants;
import smart_gs.drawing_tool.view.View;
import smart_gs.logical.filter.ImageFileDirFilterForSpreadTree;
import smart_gs.logical.region.BookmarkRegion;
import smart_gs.logical.visitor.CreateXMLElementVisitor;
import smart_gs.reasoning_web.logical.LinkRemover;
import smart_gs.smleditor.swingui.GSEditor;
import smart_gs.spread_selection.IndexChangeTable;
import smart_gs.swingui.WorkspaceWindow;
import smart_gs.util.CanonicalPathString;
import smart_gs.util.GSPathStringGrammarChecker;
import smart_gs.util.GSStandardPath;
import smart_gs.util.StringUtils;
import smart_gs.logical.Preference;

@SuppressWarnings("serial")
public class SpreadTree extends JTree implements DragSourceListener, DropTargetListener, DragGestureListener {

	private static SpreadTree singleton = new SpreadTree();
	private List<Spread> registeredSpreads;
	private List<SpreadDirectory> registeredSpreadDirectories;
	private TreePath[] selectedPaths;
	

	// 2007/10/10 kazuhiro kobayashi
	/*
	 * 外部のファイルにあるimageとtextを設定するために変更
	 */
	private static String IMAGE_FOLDER_PATH_STRING;
	private static String DSC_FOLDER_PATH_STRING;
	private static File IMAGE_FOLDER_PATH;
	private static File DSC_FOLDER_PATH;
	private SpreadDirectory root;
	private DefaultMutableTreeNode rootNode;

	// ADD NorthGrid
	private static final String NAME = "SpreadTree";
	private static final DataFlavor localObjectFlavor = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType, NAME);
	private static final DataFlavor[] supportedFlavors = { localObjectFlavor };

	protected DragSource dragSource;
	protected DropTarget dropTarget;
	TreeNode dropTargetNode = null;
	TreeNode draggedNode = null;
	TreePath dragsourceTreePath = null;

	protected HashMap<String,String>  allowImageMap = new HashMap<String, String>();

	private SpreadTree() {
		super(new DefaultMutableTreeNode("root"));

		// 許可するイメージの拡張子を指定.
		String formatNames[] = ImageIO.getReaderFormatNames();
		for(int i=0;i<formatNames.length;i++){
			allowImageMap.put(formatNames[i].toLowerCase(), formatNames[i].toLowerCase());
		}

		// 2007/10/22 kazuhiro kobayashi
		Spread.resetIndex();

		this.registeredSpreads = new ArrayList<Spread>();
		this.registeredSpreadDirectories = new ArrayList<SpreadDirectory>();
		// 2007/10/11/kazuhiro kobayashi

		// Made it in the canonical absolute path.
		IMAGE_FOLDER_PATH_STRING = CanonicalPathString.get(new File(Preference.getInstance().getImageFolderPathString()));
		IMAGE_FOLDER_PATH = new File(IMAGE_FOLDER_PATH_STRING);
		DSC_FOLDER_PATH_STRING = CanonicalPathString.get(new File(Preference.getInstance().getDscFolderPathString()));
		DSC_FOLDER_PATH = new File(DSC_FOLDER_PATH_STRING);

		if (!IMAGE_FOLDER_PATH_STRING.equals("")) {
			this.root = new SpreadDirectory("root",
			        new File(SpreadTree.IMAGE_FOLDER_PATH_STRING));
			this.rootNode = new DefaultMutableTreeNode(this.root);
			((DefaultTreeModel) (this.getModel())).setRoot(this.rootNode);
			this.updateModel();
		}
//		2011.03.07 shayashi
		this.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
		// ADD NorthGrid
		setCellRenderer(new SpreadTreeCellRenderer());
		dragSource = new DragSource();
		dragSource.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);
		dropTarget = new DropTarget(this, this);
	}

	public List<File> getDSCFiles() {
		List<File> files = new ArrayList<File>();
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			if (this.registeredSpreads.get(i).hasDscFile()) {
				files.add(this.registeredSpreads.get(i).getDscFile());
			}
		}
		return files;
	}

	public void loadAllImages() {
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			if (this.registeredSpreads.get(i).hasDscFile()) {
				this.registeredSpreads.get(i).loadImage();

			}

		}
	}

	public static SpreadTree getInstance() {
		return singleton;
	}

	public List<Spread> getSpreads() {
		return this.registeredSpreads;
	}

	public void registerSpread(Spread spread) {
		this.registeredSpreads.add(spread);
	}

	public List<Spread> getDSCSpreads() {
		List<Spread> results = new ArrayList<Spread>();
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			if (this.registeredSpreads.get(i).hasDscFile()) {
				results.add(this.registeredSpreads.get(i));
			}
		}
		return results;
	}
	
//	2011.03.13 shayashi
	public TreePath[] getSelectedPaths() {
		return this.getSelectionModel().getSelectionPaths();
	}
	
	public SpreadDirectory getRootSpreadDirectory(){
		return root;
	}

	public boolean isRegistered(File file) {
		for (int i = 0; i < this.registeredSpreadDirectories.size(); i++) {
			if (this.registeredSpreadDirectories.get(i).getFile().equals(file)) {
				return true;
			}
		}
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			if (this.registeredSpreads.get(i).getFile().equals(file)) {
				return true;
			}
		}
		return false;
	}

	//	public boolean isRegustedTree(File file){
	//		for(Enumeration e = rootNode.children(); e.hasMoreElements();){
	//			DefaultMutableTreeNode child = (DefaultMutableTreeNode)e.nextElement();
	//			GSResource r = (GSResource)child.getUserObject();
	//			if( r instanceof SpreadDirectory) {
	//				SpreadDirectory d = (SpreadDirectory)r ;
	//				if( d.getFile().equals(file) ){
	//					return child;
	//				}
	//			} 
	//		}		
	//	}

	public SpreadDirectory getCurrentDirectory() {
		TreePath path = this.getSelectionModel().getSelectionPath();
		if (path == null) {
			return (SpreadDirectory) ((DefaultMutableTreeNode) this.getModel()
					.getRoot()).getUserObject();
		}
		Object selectedObject = ((DefaultMutableTreeNode) path
				.getLastPathComponent()).getUserObject();
		while (!(selectedObject instanceof SpreadDirectory)) {
			path = path.getParentPath();
			selectedObject = ((DefaultMutableTreeNode) path
					.getLastPathComponent()).getUserObject();
		}
		return (SpreadDirectory) selectedObject;
	}

	public DefaultMutableTreeNode getSelectedNode() {
		TreePath path = this.getSelectionModel().getSelectionPath();
		if (path == null) {
			return this.rootNode;
		}
		return (DefaultMutableTreeNode) path.getLastPathComponent();
	}

	public boolean isImage(File file){
		String fileName = file.getName();
		int index = fileName.lastIndexOf('.');
		if (index >= 0) { //拡張子がある場合
			String ext = fileName.substring(index + 1);
			if(allowImageMap.containsKey(ext.toLowerCase())){
				return true;
			}
		}
		return false;
	}
	
    // Register SpreadDirectories, Spreads. (Adding them to the  variables: resource, spreads, directories.)
	private void loadImages(SpreadDirectory parent,boolean sort) {
		File[] files = parent.getFile().listFiles(new ImageFileDirFilterForSpreadTree());
		if(sort){
			Arrays.sort(files, new SpreadFileComparator()); 
		}
		for (int i = 0; i < files.length; i++) {
			File file = files[i];

			if (file.isDirectory()) {
				if (this.isRegistered(file)) {
					SpreadDirectory directory = this.getDirectory(file);
					this.loadImages(directory,sort);
				} else {
					SpreadDirectory directory = new SpreadDirectory(parent,
							file.getName(), file);
					this.registeredSpreadDirectories.add(directory);
					parent.addResource(directory);
					this.loadImages(directory,sort);
				}
			} else if (!this.isRegistered(file)) {
				if(isImage(file)){
					Spread spread = new Spread(parent, file);
					parent.addResource(spread);
					this.registeredSpreads.add(spread);
				}
			}
		}
	}

	private SpreadDirectory getDirectory(File file) {
		for (int i = 0; i < this.registeredSpreadDirectories.size(); i++) {
			if (this.registeredSpreadDirectories.get(i).getFile().equals(file)) {
				return this.registeredSpreadDirectories.get(i);
			}
		}
		return null;
	}
	
//2011.03.16 shayashi deleted
//	public static void main(String[] args) {
//		SpreadTree.getInstance();
//	}

	public void updateModel() {
		this.root.setTree(this.rootNode);
		((DefaultTreeModel) this.getModel()).setRoot(rootNode);
		((DefaultTreeModel) this.getModel()).reload();
	}

	public DefaultMutableTreeNode getRootNode(){
		return rootNode;
	}

	public void restore(Element element) {
		NodeList list = element.getElementsByTagName("directory");
		if (list.getLength() < 1) {
			System.out.println("list error");
			return;
		}
		Element rootElement = (Element) list.item(0);
		this.registeredSpreads.clear();
		this.registeredSpreadDirectories.clear();
		// 2007/10/22 kazuhiro kobayashi
		Spread.resetIndex();
		this.rootNode.removeAllChildren();
		String imageFolderPath = Preference.getInstance().getImageFolderPathString();
		String name = rootElement.getAttribute("name");
		String uri = rootElement.getAttribute("uri");
		String originalURI = rootElement.getAttribute(GSResource.ORIGINAL_URI);
		String version = rootElement.getAttribute(GSResource.VERSION);
		File filepath = new File(imageFolderPath);
		this.root = new SpreadDirectory("root",filepath,uri,originalURI,version);
		this.root.setVersion(version);
		this.root.setName(name);
		this.rootNode.setUserObject(this.root);
		this.root.restore(rootElement,filepath);
		registeredSpreads = root.getSpreads();
		registeredSpreadDirectories = root.getSpreadDirectorys();
		//		this.loadImages(this.root,false);
		this.updateModel();
		//
		/*
		 * 20080912 shimizu edited
		if (!NAME_CORRESPONDENCE_FILE_PATH.equals("")) {
			this.setNameCorrespondence();
		}
		 */
	}

	public void save(Document document, Element parent) {
		Element element = document.createElement("spreadTree");
		parent.appendChild(element);
		CreateXMLElementVisitor visitor = new CreateXMLElementVisitor(document);
		this.root.accept(visitor);
		element.appendChild(visitor.getLastElement());
	}

	public void registerSpreadDirectory(SpreadDirectory directory) {
		this.registeredSpreadDirectories.add(directory);
	}

	public Spread getSpreadByResourceURI(String uri) {
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			if (extractSpreadURI(uri).equals(URICreator.getURIWithoutHeader(registeredSpreads.get(i)))
					|| extractSpreadURI(uri).equals(registeredSpreads.get(i).getOriginalURI().substring(GSConstants.URI_HEADER.length()))
					|| uri.equals(this.registeredSpreads.get(i).getURI()))
			{
				return registeredSpreads.get(i);
			}
		}
		return null;
	}
	private Object extractSpreadURI(String uri) {
		return uri.substring(uri.indexOf(URICreator.SEP2 + URICreator.SPREAD)+1);
	}
	public Spread getSpreadByURI(String uri) {
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			if (registeredSpreads.get(i).getURI().equals(uri)){
				return registeredSpreads.get(i);
			}
		}
		return null;
	}


	/**
	 * 正規化されかつ含まれている文字列から取得.
	 * @param uri
	 * @return
	 */
	public Spread getSpreadByURI2(String uri) {
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			String srcurl = registeredSpreads.get(i).getURI();
			srcurl = GSStandardPath.toStandardOnCurrentOS(srcurl);
			if (srcurl.indexOf(uri) != -1) {
				return registeredSpreads.get(i);
			}
		}
		return null;
	}
	
	
//	2011.03.28 shayashi deleted
//	public void setNameCorrespondence() {
//		this.setNameCorrespondenceFile();
//		for (int j = 0; j < this.nameCorrespondList.size(); j++) {
//			for (int i = 0; i < this.spreads.size(); i++) {
//				this.spreads.get(i).setUserName(this.nameCorrespondList.get(j));
//			}
//			for (int i = 0; i < this.directories.size(); i++) {
//				this.directories.get(i).setUserName(
//						this.nameCorrespondList.get(j));
//			}
//		}
//
//	}
//
//	public void setNameCorrespondenceFile() {
//		String filename = NAME_CORRESPONDENCE_FILE_PATH;
//		try {
//			FileReader fr = new FileReader(filename);
//			BufferedReader br = new BufferedReader(fr);
//			String str1 = null;
//			while ((str1 = br.readLine()) != null) {
//				String[] str2 = str1.split(",");
//				this.nameCorrespondList.add(str2);
//			}
//		} catch (IOException e) {
//			e.printStackTrace();
//		}
//	}
	
	
	public void export(Writer writer) throws IOException{
		for (int i = 0; i < this.registeredSpreads.size(); i++) {
			Spread spread = this.registeredSpreads.get(i);
			boolean isBr = false;
			// FirstIDAT
			{
				String xmlstr = spread.getFirstIDAT().getSource();
				xmlstr = StringUtils.replaceString(xmlstr, "<br>", "\n");
				Pattern pattern = Pattern.compile("<.+?>", Pattern.DOTALL);
				Matcher matcher = pattern.matcher(xmlstr);
				xmlstr = matcher.replaceAll("");
				xmlstr = xmlstr.trim();
				if(!xmlstr.trim().equals("")){
					writer.write(xmlstr);
					writer.write("\n");
					isBr = true;
				}
			}
			// SecondIDAT
			{
				String xmlstr = spread.getSecondIDAT().getSource();
				xmlstr = StringUtils.replaceString(xmlstr, "<br>", "\n");
				Pattern pattern = Pattern.compile("<.+?>", Pattern.DOTALL);
				Matcher matcher = pattern.matcher(xmlstr);
				xmlstr = matcher.replaceAll("");
				xmlstr = xmlstr.trim();
				if(!xmlstr.trim().equals("")){
					writer.write(xmlstr);
					writer.write("\n");
					isBr = true;
				}
			}
			// ThirdIDAT
			{
				String xmlstr = spread.getThirdIDAT().getSource();
				xmlstr = StringUtils.replaceString(xmlstr, "<br>", "\n");
				Pattern pattern = Pattern.compile("<.+?>", Pattern.DOTALL);
				Matcher matcher = pattern.matcher(xmlstr);
				xmlstr = matcher.replaceAll("");
				xmlstr = xmlstr.trim();
				if(!xmlstr.trim().equals("")){
					writer.write(xmlstr);
					writer.write("\n");
					isBr = true;
				}
			}
			if(isBr){
				writer.write("\n");
			}
		}
	}
	// ADD NorthGrid 以下D&Dイベント
	/**
	 * ドラッグ＆ドロップ操作が完了.
	 * @param dsde
	 */
	public void dragDropEnd(DragSourceDropEvent dsde) {
		dropTargetNode = null;
		draggedNode = null;
		dragsourceTreePath = null;
		// 再表示
		WorkspaceWindow.setUpdated(true);
		repaint();
	}
	/**
	 * カーソルのホットスポットがプラットフォーム依存のドロップサイトに入力された.
	 * @param dsde
	 */
	public void dragEnter(DragSourceDragEvent dsde) {
		dsde.getDragSourceContext().setCursor(DragSource.DefaultMoveDrop);
	}
	/**
	 * カーソルのホットスポットがプラットフォーム依存のドロップサイトを終了したとき.
	 * @param dse
	 */
	public void dragExit(DragSourceEvent dse) {
		dse.getDragSourceContext().setCursor(DragSource.DefaultMoveNoDrop);
	}
	/**
	 * ドロップサイトに移動.
	 * @param dsde
	 */
	public void dragOver(DragSourceDragEvent dsde) {
		//shayashi 2011.03.18
		selectedPaths = null;
		selectedPaths = getSelectedPaths();

	}
	/**
	 * ジェスチャーを変更.
	 * @param dsde
	 */
	public void dropActionChanged(DragSourceDragEvent dsde) {}
	/**
	 * ドラックが受け入れたとき.
	 * @param dtde
	 */
	public void dragEnter(DropTargetDragEvent dtde) {
		dtde.acceptDrag(DnDConstants.ACTION_COPY_OR_MOVE);
	}
	/**
	 * ドラッグ終了.
	 * @oaram dte
	 */
	public void dragExit(DropTargetEvent dte) {}
	/**
	 * ドラッグ中の処理.
	 * @prama dtde
	 */
	public void dragOver(DropTargetDragEvent dtde) {
		DataFlavor[] f = dtde.getCurrentDataFlavors();
		boolean isDataFlavorSupported = f[0].getHumanPresentableName().equals(NAME);
		if(!isDataFlavorSupported) {
			//サポートされていないDataFlavorである(例えばデスクトップからファイルなど)
			rejectDrag(dtde);
			return;
		}
		Point pt = dtde.getLocation();
		TreePath path = getPathForLocation(pt.x, pt.y);
		//		begin 2011.03.21 shayashi for automatic scroll
		//		MouseMotionListner in SpreadTreePanel did not work.
		//		Thus it is implemented here.
		Rectangle r2 = new Rectangle(pt.x, pt.y, 10, 10);
		Rectangle r1 = new Rectangle(pt.x-10, pt.y-10, 10, 10);
		scrollRectToVisible(r1);
		scrollRectToVisible(r2);
		//      end
		if(path==null) {
			//ノード以外の場所である(例えばJTreeの余白など)
			rejectDrag(dtde);
			return;
		}
		Object droppedObject;
		try {
			droppedObject = dtde.getTransferable().getTransferData(localObjectFlavor);
		}catch(Exception ex) {
			rejectDrag(dtde);
			return;
		}
		// 別ディレクトリへの移動は禁止
		if(path==null || !path.getParentPath().toString().equals(dragsourceTreePath.getParentPath().toString())){
			rejectDrag(dtde);
			return;
		}

		
		selectedPaths = null;
		selectedPaths = getSelectedPaths();
//		2011.03.20, 27 shaysahi: checking if all the selected items are in the same directory.
		if (! areSelectedPathsInSameNode(selectedPaths)) {
			rejectDrag(dtde);
			return;
		}
		

		DefaultMutableTreeNode droppedNode = (DefaultMutableTreeNode) droppedObject;
		DefaultMutableTreeNode parentOfDroppedNode = (DefaultMutableTreeNode) droppedNode.getParent();
		DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) path.getLastPathComponent();
		DefaultMutableTreeNode parentOfTargetNode = (DefaultMutableTreeNode) targetNode.getParent();


		while(parentOfTargetNode!=null) {
			if(droppedNode.equals(parentOfTargetNode)) {
				//親ノードを子ノードにドロップしようとしている
				rejectDrag(dtde);
				return;
			}
			parentOfTargetNode = (DefaultMutableTreeNode)parentOfTargetNode.getParent();
		}
		dropTargetNode = targetNode;
		dtde.acceptDrag(dtde.getDropAction());
		repaint();
	}

	private boolean areSelectedPathsInSameNode(TreePath[] selectedPaths2) {
		if (selectedPaths != null){
			int size = selectedPaths.length;
			if (size != 0){
				DefaultMutableTreeNode parentOfFirstSelectedNode = 
					(DefaultMutableTreeNode) selectedPaths[0].getParentPath().getLastPathComponent();
				for (int i = 1; i<size;i++){
					DefaultMutableTreeNode parentOfSelectedNode = 
						(DefaultMutableTreeNode) selectedPaths[i].getParentPath().getLastPathComponent();
					if (!parentOfSelectedNode.equals(parentOfFirstSelectedNode)){
						return false;
					}
				}
			}
		}
		return true;
	}

	/**
	 *  DropTarget へのドロップで、ドラッグ操作が終了.
	 *  @param dtde
	 */
	public void drop(DropTargetDropEvent dtde) {
		Object droppedObject;
		//shayashi 2011.03.18, 03.20
		try {
			droppedObject = dtde.getTransferable().getTransferData(localObjectFlavor);
		}catch(Exception e) {
			e.printStackTrace();
			dtde.dropComplete(false);
			return;
		}
		DefaultTreeModel model = (DefaultTreeModel) getModel();
		Point p = dtde.getLocation();
		TreePath targetPath = getPathForLocation(p.x, p.y);
		if(targetPath==null || !(droppedObject instanceof MutableTreeNode)) {
			dtde.dropComplete(false);
			return;
		}
		DefaultMutableTreeNode droppedNode = (DefaultMutableTreeNode) droppedObject;

		DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) targetPath.getLastPathComponent();
		DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) targetNode.getParent();
		if(targetNode.equals(droppedNode)) {
			//自分を自分にはドロップ不可
			dtde.dropComplete(false);
			return;
		}
		
		// accept to drop
		dtde.acceptDrop(DnDConstants.ACTION_MOVE);
		
//		2011.03.16 shayashi changed BEGIN
//		Process for the drop
//		Check if the droppedNode is selected or not, and memorize the smaller and larger node's indexes.
		TreePath pathOfDroppedNode = new TreePath(droppedNode.getPath());
		int size=-1;
		int droppedNodeIndexInSelection;
		boolean droppedNodeIsSelected;
		if (selectedPaths == null) {
			droppedNodeIsSelected = false;
		} else {
			size= selectedPaths.length;
			droppedNodeIsSelected = false;
			for (int i=0;i<size;i++){
				if (pathOfDroppedNode.equals(selectedPaths[i])) {
					droppedNodeIsSelected = true;
					droppedNodeIndexInSelection = i;
					break;
				}
			}
		}
		List<GSResource> resources = ((SpreadDirectory)parentNode.getUserObject()).getResources();
		int droppedNodeIndex = model.getIndexOfChild(parentNode, droppedNode);
		int targetNodeIndex = model.getIndexOfChild(parentNode, targetNode);
		if (droppedNodeIsSelected == false || size == 1){
			model.removeNodeFromParent(droppedNode);
			GSResource elm = resources.get(droppedNodeIndex);
			resources.remove(droppedNodeIndex);
//					0 is a meaningless default value.
			int insertionPointIndex = 0;
			if (droppedNodeIndex < targetNodeIndex) {
				insertionPointIndex = targetNodeIndex-1;
			} else if (droppedNodeIndex > targetNodeIndex){
				insertionPointIndex = targetNodeIndex;
			} 
			resources.add(insertionPointIndex,elm);
			model.insertNodeInto(droppedNode, parentNode, insertionPointIndex);
//			Select droppedNode to make it stand out.
			setSelectionPath(pathOfDroppedNode);
//			finally set the new SpreadDirectory
			((SpreadDirectory)parentNode.getUserObject()).setResources(resources);
		} else {
			int insertPointIndex=targetNodeIndex;
			MutableTreeNode[] tmpForJTree = new MutableTreeNode[size];
			GSResource[] tmpForSpreadTree = new GSResource[size];
//			copy selected nodes to tmpForTree/tmpForSpreadTree buffers.
			for (int i=0;i<size;i++){
				MutableTreeNode selectedNode = (MutableTreeNode)selectedPaths[i].getLastPathComponent();
				tmpForJTree[i] = selectedNode;
				tmpForSpreadTree[i] = resources.get(model.getIndexOfChild(parentNode, selectedNode));
			}
			int insertionPointIndex=-1;
//			remove selected items from children of parentNode and resource, and adjust the insertionPointIndex.
			int offset =0;
			for (int i=0;i<size;i++){
				insertionPointIndex = targetNodeIndex;
				MutableTreeNode selectedNode = (MutableTreeNode)selectedPaths[i].getLastPathComponent();
				int selectedNodeIndex = 
					model.getIndexOfChild(selectedPaths[i].getParentPath().getLastPathComponent(),selectedNode);	
				GSResource elm = resources.get(selectedNodeIndex);
				model.removeNodeFromParent(selectedNode);
				resources.remove(selectedNodeIndex);
				if (selectedNodeIndex < insertionPointIndex) {
					offset++;
				} else if (selectedNodeIndex >= insertionPointIndex){
					//insertionPointIndex = insertionPointIndex;
				} 
			}
			insertionPointIndex = insertionPointIndex-offset;
//			for debug 2011.03.23 shayashi
//			System.out.printf("insertPointIndex:%d\n",insertionPointIndex);
//			int bound = model.getChildCount(selectedPaths[0].getParentPath().getLastPathComponent());
//			for (int i = 0; i<bound;i++) System.out.printf("%d:%s\n", i,model.getChild(selectedPaths[0].getParentPath().getLastPathComponent(),i));
//			System.out.printf("%d\n",insertionPointIndex);
			//			insert items of two buffers to JTree and Spread/SpreadDirectory graph-tree.
			for (int i=size-1;i>=0;i--){
				resources.add(insertionPointIndex,tmpForSpreadTree[i]);
				model.insertNodeInto(tmpForJTree[i], parentNode ,insertionPointIndex);
			}
//			Select the dropped(dragged) nodes to make them stand out.
			setSelectionPaths(selectedPaths);
//			finally set the new SpreadDirectory
			((SpreadDirectory)parentNode.getUserObject()).setResources(resources);
		}

        //		post processing
		new AutomaticNumbering().execAndAdjustSpreadSelectionLists(this.rootNode);		
		// MoveTooBarをアップデートする
		WorkspaceWindow.getInstance().updateMoveToolBar();
        // updated is marked
		WorkspaceWindow.setUpdated(true);
		repaint();
        //		drop event ends
		dtde.dropComplete(true);
	}
//		2011.03.16 shayashi changed END

	/**
	 * ジェスチャーを変更.
	 * @param dtde
	 */
	public void dropActionChanged(DropTargetDragEvent dtde) {
       // NOP 
	}

	/**
	 * D&Dの操作を開始する。
	 * @param dge ドラッグ開始ジェスチャーを検出イベント
	 */
	public void dragGestureRecognized(DragGestureEvent dge) {
		Point clickPoint = dge.getDragOrigin();
		TreePath path = getPathForLocation(clickPoint.x, clickPoint.y);
		if(path==null || path.getParentPath()==null) {
			return;
		}
		dragsourceTreePath = path;
		draggedNode = (TreeNode) path.getLastPathComponent();
		if(draggedNode instanceof DefaultMutableTreeNode){
			Transferable trans = new SpreadTreeTransferable(draggedNode);
			dragSource.startDrag(dge,Cursor.getDefaultCursor(),	trans, this);
		}
	}
	/**
	 * ドラックの停止.
	 * @param dtde
	 */
	private void rejectDrag(DropTargetDragEvent dtde) {
		dtde.rejectDrag();
		// dropTargetNode(flag)をnull
		dropTargetNode = null;
		//JTree描画
		repaint();
	}
	/**
	 * 
	 * データ変換クラス.
	 * アプリ以外からのドラックをチェックする.
	 */
	class SpreadTreeTransferable implements Transferable {
		Object object;
		public SpreadTreeTransferable(Object o) {
			object = o;
		}
		//@Override
		public Object getTransferData(DataFlavor df) throws UnsupportedFlavorException, IOException {
			if(isDataFlavorSupported(df)) {
				return object;
			}else{
				throw new UnsupportedFlavorException(df);
			}
		}
		//@Override
		public boolean isDataFlavorSupported(DataFlavor df) {
			return (df.getHumanPresentableName().equals(NAME));
		}
		//@Override
		public DataFlavor[] getTransferDataFlavors() {
			return supportedFlavors;
		}
	}
	/**
	 * 
	 * Rendererクラス
	 * D&D中の操作をラインを付加して表示する.
	 *
	 */
	class SpreadTreeCellRenderer
	extends DefaultTreeCellRenderer {
		boolean isTargetNode;
		boolean isTargetNodeLeaf;
		boolean isLastItem;
		Insets normalInsets, lastItemInsets;
		int BOTTOM_PAD = 30;
		public SpreadTreeCellRenderer() {
			super();
			normalInsets = super.getInsets();
			lastItemInsets =
				new Insets(normalInsets.top,
						normalInsets.left,
						normalInsets.bottom + BOTTOM_PAD,
						normalInsets.right);
		}
		public Component getTreeCellRendererComponent(JTree tree,
				Object value,
				boolean isSelected,
				boolean isExpanded,
				boolean isLeaf,
				int row,
				boolean hasFocus) {
			isTargetNode = (value == dropTargetNode);
			isTargetNodeLeaf = (isTargetNode &&
					((TreeNode)value).isLeaf());
			// isLastItem = (index == list.getModel().getSize()-1);
			boolean showSelected = isSelected & (dropTargetNode == null);
			DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer)super.getTreeCellRendererComponent(tree, value, isSelected, isExpanded,isLeaf, row, hasFocus);
			if(value != null){
				if(value instanceof DefaultMutableTreeNode){
					DefaultMutableTreeNode defaultMutableTreeNode = (DefaultMutableTreeNode)value;
					Object obj = defaultMutableTreeNode.getUserObject();
					if(obj != null){
						if(obj instanceof SpreadDirectory){
							Icon icon = renderer.getOpenIcon();
							renderer.setIcon(icon);
						}
					}
				}
			}
			return renderer;

		}

//		2011.03.16 shayashi changed: moving items always underlined
		public void paintComponent(Graphics g) {
			super.paintComponent(g);
			if (isTargetNode) {
				g.setColor(Color.black);
				g.drawLine(0, 0, getSize().width, 0);
			}
		}
	}

	class SpreadFileComparator implements Comparator<File>{

		public int compare(File o1, File o2) {
			return o1.compareTo(o2);
		}
	}

	//　This generates an IndexChangeTable
	class 	AutomaticNumbering {
		private int counter = 0;
		int ict_max = Spread.getCurrentMaxPageIndex();
		IndexChangeTable ict = new IndexChangeTable(ict_max);

		private void exec(DefaultMutableTreeNode parentNode){
			Enumeration<DefaultMutableTreeNode> enumeration = parentNode.children();
			while(enumeration.hasMoreElements()){
				DefaultMutableTreeNode childrenNode = enumeration.nextElement();
				String childrenStr = childrenNode.toString();
				if(childrenNode.getUserObject() instanceof Spread){
					// shayashi 20101003 making index-map point2/2points (A)
					Spread spread = (Spread)childrenNode.getUserObject();
					if (counter <= ict_max) ict.set(spread.getPageViewIndex(), counter);
					spread.setPageViewIndex(counter);
					counter++;
				} else if(childrenNode.getUserObject() instanceof SpreadDirectory){
					exec(childrenNode);
				}
			}
			WorkspaceWindow.setUpdated(true);
		}

		public void execAndAdjustSpreadSelectionLists(DefaultMutableTreeNode rootNode){
			exec(rootNode);
			SpreadSelectionListManager.getInstance().adjustSpreadSelctionLists(ict);
		}
	}



	//	public Spread getSpreadByIndex (Integer index){ return getSpreads().get(2); }
	public Spread getSpreadByIndex (Integer index){
		List<Spread> toseek = getSpreads();
		Spread result = null;
		for (int i = toseek.size() - 1; i >= 0; i--) {
			if ( toseek.get(i).getPageIndex()== index ) {
				result = toseek.get(i);
			}
		}
		return result;
	}
	
	public List<GSResource> getBookmarks() {
		ArrayList<GSResource> bookmarks = new ArrayList<GSResource>();
		for (Spread spread:this.registeredSpreads) {
			for (Region region:spread.getRegions()) {
				if (region.getView().getType() == View.BOOKMARK) {
					bookmarks.add((BookmarkRegion)region);
				}
			}
		}
		return bookmarks;		
	}
	

	public void sortSelectedItemsByName() {
		DefaultTreeModel model = (DefaultTreeModel) this.getModel();
		selectedPaths = null;
		selectedPaths = getSelectedPaths();
		int size = selectedPaths.length;
		if (size == 0) return;
//		2011.03.28 shaysahi: checking if all the selected items are in the same directory.
		if (! areSelectedPathsInSameNode(selectedPaths)){
			JOptionPane.showMessageDialog(singleton, "Items must be in the same directory");
			return;
		}
		DefaultMutableTreeNode parentNode = 
			(DefaultMutableTreeNode) selectedPaths[0].getParentPath().getLastPathComponent();
		List<GSResource> resources = ((SpreadDirectory)parentNode.getUserObject()).getResources();
		
//		get all selected items' indexes, sort them, and its smallest, which is insertionPointIndex.
		int[] indexes = new int[size];
		for (int i=0;i<size;i++) {
			indexes[i] = parentNode.getIndex((DefaultMutableTreeNode) selectedPaths[i].getLastPathComponent());				
		}
		Arrays.sort(indexes);
		for (int i=0;i<size-1;i++) {
			if (indexes[i+1] > indexes[i]+1){
				JOptionPane.showMessageDialog(singleton, "Items must be consective:"+indexes[i]+","+indexes[i+1]+"\n");
				return;
			}
		}
		int insertionPointIndex = indexes[0];
		
//		Two buffers
		MutableTreeNode[] tmpForJTree = new MutableTreeNode[size];
		GSResource[] tmpForSpreadTree = new GSResource[size];
//		copy selected nodes to tmpForTree/tmpForSpreadTree buffers, and sort them.
		for (int i=0;i<size;i++){
			MutableTreeNode selectedNode = (MutableTreeNode)selectedPaths[i].getLastPathComponent();
			tmpForJTree[i] = selectedNode;
			tmpForSpreadTree[i] = resources.get(model.getIndexOfChild(parentNode, selectedNode));
		};
		size = size;
		Arrays.sort(tmpForJTree,new DefaultMutableTreeNodeNameComparator());
		Arrays.sort(tmpForSpreadTree,new GSResourceNameComparator());
		
		//		remove selected items from the children of parentNode and resource.
		for (int i=size-1;i>=0;i--){
			parentNode.remove(insertionPointIndex+i);
			resources.remove(insertionPointIndex+i);
		}

//		for debug 2011.03.23 shayashi
//		System.out.printf("insertPointIndex:%d\n",insertionPointIndex);
//		int bound = model.getChildCount(selectedPaths[0].getParentPath().getLastPathComponent());
//		for (int i = 0; i<bound;i++) System.out.printf("%d:%s\n", i,model.getChild(selectedPaths[0].getParentPath().getLastPathComponent(),i));
//		System.out.printf("%d\n",insertionPointIndex);
		//			insert items of two buffers to JTree and Spread/SpreadDirectory graph-tree.
		for (int i=size-1;i>=0;i--){
			resources.add(insertionPointIndex,tmpForSpreadTree[i]);
			model.insertNodeInto(tmpForJTree[i], parentNode ,insertionPointIndex);
		}
//		finally set the new SpreadDirectory
		((SpreadDirectory)parentNode.getUserObject()).setResources(resources);
		
//		renumbering and redraw
		new AutomaticNumbering().execAndAdjustSpreadSelectionLists(this.rootNode);
		WorkspaceWindow.setUpdated(true);
		updateUI();
		repaint();
	}

	
//	Making or adding Spreads, SpreadDirectories.
	
	// Make a node&SpreadDirectory under the parent pair of parentTreeNode&parentSpreadDir with the name "name".
	// It returns the "node" made. If the given name is already used in the parent node, it returns null.
	// If the OS directory does not exist, it is created.
	
	
	public DefaultMutableTreeNode makeNewSpreadDirectory(DefaultMutableTreeNode parentTreeNode,String name){
		return makeNewSpreadDirectory(parentTreeNode, name, false);
	}
	
	public DefaultMutableTreeNode makeNewSpreadDirectoryImportMode(DefaultMutableTreeNode parentTreeNode,String name){
		return makeNewSpreadDirectory(parentTreeNode, name, true);
	}
	
	public DefaultMutableTreeNode makeNewSpreadDirectory(DefaultMutableTreeNode parentTreeNode,String name, boolean importMode){
		if (!GSPathStringGrammarChecker.isFileDirIdentifier(name)) {
			JOptionPane.showMessageDialog(null, String.format("Error: name %s cannot be used in SMART-GS.",name));
			return null;
		}
		if ( name.equals(".") || name.equals("..")) {
			JOptionPane.showMessageDialog(null, String.format("Error: name %s is not allowed to avoid confusion.",name));
			return null;
		}
		if ( name.equals("DscLocation")) {
			JOptionPane.showMessageDialog(null, String.format("Error: name %s is used by SMART-GS system, and so cannot be used.",name));
			return null;
		}
		

		Enumeration<DefaultMutableTreeNode> enm = parentTreeNode.children();
		while (enm.hasMoreElements()){
			DefaultMutableTreeNode nextNode = enm.nextElement();
			GSResource rsrc = (GSResource)nextNode.getUserObject();
			String tmp = rsrc.getName();
			if (tmp.equalsIgnoreCase(name)) {
				JOptionPane.showMessageDialog(null, 
						String.format("Error: new directory   %s   cannot be made, since name   %s   already exists in %s\nRemark: name equality check is case-senseless for Windows File Systems",
								name, tmp, makePathString(parentTreeNode.getPath())));
				return null;
			}
		}


		SpreadDirectory parentSpreadDir = (SpreadDirectory) parentTreeNode.getUserObject();

		if (!importMode) {
			String[] children = parentSpreadDir.getFile().list();
			for (int i=0;i<children.length;i++) {
				String tmp = children[i];
				if (tmp.equalsIgnoreCase(name)) {
					JOptionPane.showMessageDialog(null, 
							String.format("Error: new directory   %s   cannot be made, since name   %s   already exists in the file system %s. Consider to import it\nRemark: name equality check is case-senseless for Windows File Systems",
									name, tmp, parentSpreadDir.getFile().getPath()));
					return null;
				}
			}
		}
		
		
		File newDir = new File(parentSpreadDir.getFile(),name);
		
		if (!newDir.exists()) {
			boolean check = newDir.mkdir();
			if (!check) {
				System.out.printf("Error: directory %s could not be made.\n", CanonicalPathString.get(newDir));
				return null;
			}
			File newDscDir = new File(newDir,"dsc");
			check = newDscDir.mkdir();
			if (!check) {
				System.out.printf("Error: dsc directory %s could not be made.\n", CanonicalPathString.get(newDscDir));
				return null;
			}
		}
		SpreadDirectory directory = new SpreadDirectory(parentSpreadDir,name, newDir);
		this.registeredSpreadDirectories.add(directory);
		parentSpreadDir.addResource(directory);
		DefaultMutableTreeNode directoryNode = new DefaultMutableTreeNode(directory);
		parentTreeNode.add(directoryNode);
		this.updateUI();
		repaint();
		return directoryNode;
	}

	public static String makePathString(TreeNode[] array_path) {
		StringBuffer tmp = new StringBuffer();
		int size = array_path.length;
		for (int i=0; i<size;i++){
			tmp.append("/");
			tmp.append(array_path[i]);
		}
		return tmp.toString();
	}

	// Add NorhtGrid
    // If the file (assumed to be an OS-directory)
    // already registered in SpreadTree, then the corresponding node of the tree is returned.
	// :note by shayashi.
	public DefaultMutableTreeNode addSpreadDirectory(DefaultMutableTreeNode treeNode,SpreadDirectory parent, File file){
		boolean ans =file.isDirectory();
		if (file.isDirectory()) {
			if (!this.isRegistered(file)) {
				SpreadDirectory directory = new SpreadDirectory(parent,	file.getName(), file);
//				shayashi OK Kukita 2011/05/20
				this.registeredSpreadDirectories.add(directory);
				parent.addResource(directory);
				DefaultMutableTreeNode directoryNode = new DefaultMutableTreeNode(directory);
				treeNode.add(directoryNode);
				return directoryNode;
			}else{
//				already exits
				for(Enumeration<DefaultMutableTreeNode> e = treeNode.children(); e.hasMoreElements();){
					DefaultMutableTreeNode child = e.nextElement();
					GSResource r = (GSResource)child.getUserObject();
					if( r instanceof SpreadDirectory) {
						SpreadDirectory d = (SpreadDirectory)r ;
						if( d.getFile().equals(file) ){
							return child;
						}
					} 
				}
			}
		}
		
        // mock return value. This should not happen.
		System.out.print("Something wrong with SpreadTree.addDirectory()\n");
		return null;
	}
	public void addLoadImage(DefaultMutableTreeNode treeNode,SpreadDirectory parent,File file){
		if (!file.isDirectory()) {
			if (!this.isRegistered(file)) {
				if(this.isImage(file)){
					{
						Spread spread = new Spread(parent, file);
//						shayashi OK Kukita 2011/05/20
						parent.addResource(spread);
						this.registeredSpreads.add(spread);
						treeNode.add(new DefaultMutableTreeNode(spread));
					}
					new AutomaticNumbering().execAndAdjustSpreadSelectionLists(this.rootNode);		
				}
			}
		}
		this.updateUI();
	}

//	add file node　SELECTED by the selection model.
//	
	public void addImage (File file) {
	//		2011.04.05 shayashi
		SpreadTree tree = SpreadTree.getInstance();
		if(file != null){
			if(tree.isRegistered(file)) return;
			DefaultMutableTreeNode spreadTreeNode = tree.getSelectedNode();
			SpreadDirectory spreadDirectory = (SpreadDirectory) spreadTreeNode.getUserObject();
			tree.addLoadImage(spreadTreeNode, spreadDirectory, file);
		}
	}
	
	public void addImage (DefaultMutableTreeNode spreadTreeNode, File file) {
		//		2011.07.04 shayashi
			SpreadTree tree = SpreadTree.getInstance();
			if(file != null){
				if(tree.isRegistered(file)) return;
				SpreadDirectory spreadDirectory = (SpreadDirectory) spreadTreeNode.getUserObject();
				tree.addLoadImage(spreadTreeNode, spreadDirectory, file);
			}
		}
	
//	openDirectory is the SpreadDirectory deep underneath which the new image file imageFile is added.
//	SpreadDirectories between openDirectory and the Spread of imageFile are added, if not exist.
	public void addImageFile(String rootDir,String openDirectoryPathInString, SpreadDirectory openDirectory, File imageFile){
		if(singleton.isRegistered(imageFile)) return;
		String imageFilePath = CanonicalPathString.get(imageFile);
		
		DefaultMutableTreeNode treeNode = singleton.getSelectedNode();
		SpreadDirectory parent = openDirectory;
		if(!rootDir.equals(openDirectoryPathInString)){
			
			String dir = imageFilePath.substring(openDirectoryPathInString.length(),imageFilePath.length()-imageFile.getName().length());
//			String dir = openDirectoryPathInString.substring(rootDir.length(),openDirectoryPathInString.length());
			dir = GSStandardPath.win2standard(dir);
			StringTokenizer st = new StringTokenizer(dir, "/");
			StringBuffer dirBuf = new StringBuffer();
			if(!rootDir.endsWith("/")){
				rootDir+="/";
			}
			dirBuf.append(openDirectoryPathInString);
			
	        while (st.hasMoreTokens()) {
	        	dirBuf.append(st.nextToken() + "/");
	        	File newDir = new File(dirBuf.toString());
	        	
		        treeNode = singleton.addSpreadDirectory(treeNode, parent, newDir);
		        parent = (SpreadDirectory)treeNode.getUserObject();
	        }
		}
		singleton.addLoadImage(treeNode,parent, imageFile);
	}
	
	//	The arguments must be existing directories.
	public void addDir(DefaultMutableTreeNode theTargetNode, File parentDirectory, String newDirName) {
		DefaultMutableTreeNode newDirNode = makeNewSpreadDirectoryImportMode(theTargetNode,newDirName);
		if (newDirNode == null) return;
		File newDirOnFileSystem = new File(parentDirectory,newDirName);
		File [] list = newDirOnFileSystem.listFiles((FilenameFilter) new ImageFileDirFilterForSpreadTree());
		for(int i=0; i < list.length; i++){
			if(list[i].isDirectory()){
				String dirName = list[i].getName();
				addDir(newDirNode, newDirOnFileSystem, dirName);
			}else{
				this.addImage(newDirNode, list[i]);
			}
		}
	}
	

//	End of Making or adding Spreads, SpreadDirectories.
	
	
//	Removing Spreads, SpreadDirectories.
	
//	2011.03.15 shayashi, delete selected items in SpreadTree using
//	removeSpread and removeSpreaddirectory
	public void removeSelectedItems() {
		TreePath[] paths = getSelectedPaths();
		int size = paths.length;
		
		Object[] options = {"delete the items", "don\'t delete the items","Cancel"};
		int selectedProcessOption = 
			JOptionPane.showOptionDialog(WorkspaceWindow.getInstance().getFrame(),"From Image Folder,",	
					"Deletion options",
					JOptionPane.YES_NO_CANCEL_OPTION,
					JOptionPane.QUESTION_MESSAGE,
					null,
					options,
					options[0]);
		
		if (selectedProcessOption == JOptionPane.CANCEL_OPTION) return;
		// delete items from ImageTree 
		for (int i=0; i<size; i++){
			GSResource item = (GSResource)((DefaultMutableTreeNode)paths[i].getLastPathComponent()).getUserObject();
			if (item == null) break;
			if (item instanceof Spread) removeSpread(paths[i]) ;
			else if (item instanceof SpreadDirectory) {removeDirectory(paths[i]);}
			else System.out.print("Bug in SpreadTree");
			//				post processing
			new AutomaticNumbering().execAndAdjustSpreadSelectionLists(this.rootNode);
			WorkspaceWindow.setUpdated(true);
			repaint();
		}
		// delete files and directories
		if (selectedProcessOption == 0) {
			// delete the files corresponding to the items
			for (int i=0; i<size; i++){
				GSResource item = (GSResource)((DefaultMutableTreeNode)paths[i].getLastPathComponent()).getUserObject();
				if (item == null) break;
				if (item instanceof Spread) {
					Spread spread = (Spread)item;
					File imageFile = spread.getImageFile();
					File dscFile = spread.getDscFile();
					File dscLineSegFile = spread.getDscLineSegFile();
					File lineSegFile = spread.getLineSegFile();
					if (imageFile.exists()) imageFile.delete();
					if (dscFile != null && dscFile.exists()) dscFile.delete();
					if (dscLineSegFile.exists()) dscLineSegFile.delete();
					if (lineSegFile.exists()) lineSegFile.delete();
				} else {
					// directory!
					Object[] nodes = paths[i].getPath();
					File image_fileDir_path = IMAGE_FOLDER_PATH;
					// nodes[j] for j=0 is 'root'
					for (int j=1; j<nodes.length;j++) {
						image_fileDir_path = new File(image_fileDir_path,nodes[j].toString());
					}
					deleteDir(image_fileDir_path);

					// Delete the counterpart in DSC Folder.
					if (! IMAGE_FOLDER_PATH_STRING.equals(DSC_FOLDER_PATH)) {
						File dsc_fileDir_path = DSC_FOLDER_PATH;
						// nodes[j] for j=0 is 'root'
						for (int j=1; j<nodes.length;j++) {
							dsc_fileDir_path = new File(dsc_fileDir_path,nodes[j].toString());
						}
						deleteDir(dsc_fileDir_path);
					}
				}
			}
		}
	}

	// Deletes all files and subdirectories under dir.
	// Returns true if all deletions were successful.
	// If a deletion fails, the method stops attempting to delete and returns false.
	// If dir does not exists, then it returns true.
	private static boolean deleteDir(File dir) {
	    if (dir.isDirectory()) {
	        String[] children = dir.list();
	        for (int i=0; i<children.length; i++) {
	            boolean success = deleteDir(new File(dir, children[i]));
	            if (!success) {
	                return false;
	            }
	        }
	    }
	    // The directory is now empty so delete it
	    if (dir.exists()) return dir.delete();
	    else return true;
	}


	//	2011.03.15 shayashi
	//	deletes a spread by removeSpread, removeDirectory
	//	this calls AutomaticNumberting and execAndAdjustSpreadSelectionLists
	public void removeSpread(TreePath path){
		if (path == null) {return;}
		Object obj = path.getLastPathComponent();
//		obj may be null, as it has been already removed　by remove command itself. So check!
		if (obj == null) {return;}
			
		Spread deletespread = (Spread)((DefaultMutableTreeNode)obj).getUserObject();
		if (deletespread == null) {return;}
		String nameStr = deletespread.toString();
		
		DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) path.getLastPathComponent();
		DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) targetNode.getParent();

		int smallest = Integer.MAX_VALUE;
		if(nameStr.indexOf(":") != -1){
			String numberStr = nameStr.substring(0,nameStr.indexOf(":"));
			try{
				smallest  = Integer.parseInt(numberStr);
			}catch(NumberFormatException e){}
		}
		
		//	This loop finds the index of the spread to be deleted in the children index list of the parent node.
		//	If it is found, then deleteflg is ture and the index to find is the value of deletecount
		Enumeration<DefaultMutableTreeNode> enumeration = parentNode.children();
		SpreadDirectory spreadDirectory = (SpreadDirectory)parentNode.getUserObject();
		int deletecount = 0;
		boolean deleteflg = false;
		while(enumeration.hasMoreElements()){
			DefaultMutableTreeNode childrenNode = enumeration.nextElement();
			String childrenStr = childrenNode.toString();
			if(childrenNode.getUserObject() instanceof Spread){
				if(childrenStr.equals(nameStr)){
					deleteflg = true;
					removeLink(((Spread)childrenNode.getUserObject()).getURI());
					registeredSpreads.remove((Spread)childrenNode.getUserObject());
					spreadDirectory.remove((Spread)childrenNode.getUserObject());
					break;
				}
			}
			deletecount++;
		}
		if(deleteflg){
			parentNode.remove(deletecount);
			this.updateUI();
		}else{
			return;
		}
		this.repaint();
	}


	public void removeDirectory(TreePath path){
		if (path == null) return;
		Object obj = path.getLastPathComponent();
//		obj may be null, as it has been already removed　by remove command itself. So check!
		if (obj == null) return;
		SpreadDirectory deleteDirectory = (SpreadDirectory)((DefaultMutableTreeNode)obj).getUserObject();
		if (deleteDirectory == null) return;
		List<SpreadDirectory> listdir =  deleteDirectory.getSpreadDirectorys();
		for(int i=0;i<listdir.size();i++){
			SpreadDirectory spreadDirectory = listdir.get(i);
			removeLink(spreadDirectory.getURI());
			registeredSpreadDirectories.remove(spreadDirectory);
		}
		List<Spread> listfile = deleteDirectory.getSpreads();
		for(int i=0;i<listfile.size();i++){
			Spread spread = listfile.get(i);
			removeLink(spread.getURI());
			registeredSpreads.remove(spread);
		}
		deleteDirectory.removeAllChildren();
		registeredSpreadDirectories.remove(deleteDirectory);
		removeLink(deleteDirectory.getURI());
		DefaultMutableTreeNode targetNode = (DefaultMutableTreeNode) path.getLastPathComponent();
		DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode) targetNode.getParent();
		Object  parentObject = parentNode.getUserObject();
		((SpreadDirectory)parentObject).removeDirectory(deleteDirectory);
		parentNode.remove(targetNode);
		this.updateUI();
		repaint();
	}

	private void removeLink(String url){
		LinkRemover.removeLinksOf(url);
	}

	public void clear() {
		this.registeredSpreads.clear();
		this.registeredSpreadDirectories.clear();
		this.rootNode.removeAllChildren();
		this.root.clear();

		this.updateUI();
		this.repaint();
	}
	
	//	End of SpreadTree Class
}
