/*
   Tamot --- Task Modelling Editor
   Copyright (C) 2000 Commonwealth Scientific and Industrial Research Organisation
   (CSIRO), Australia. All rights reserved. 

   The Software, owned by CSIRO Australia, has been developed by the CSIRO 
   Intelligent Interactive Technology group. 
   For more information, please see http://www.cmis.csiro.au/iit/.

   Redistribution in source and binary forms, with or without modification, are not permitted.

   The Software is a beta-test version for internal research and evaluation purposes 
   by the Licensee. The Software is still at a development stage. 
   It has not undergone complete testing and may have inherent errors,
   bugs or deficiencies that can affect the operation of the Software. 

   We encourage your feedback and suggestions. Any bugs / suggestions found please email to
   Shijian.Lu@cmis.csiro.au and Thomas.Lo@cmis.csiro.au. 

   After you have signed the Beta-Test Software License Agreement with the CSIRO,
   CSIRO grants you a non-exclusive, non-transferable license to use it only for your 
   personal, non-commercial and lawful end use. Implied licenses are negated. 

   Warranty Disclaimer : 

   CSIRO supplies the Software on an "as is" basis and makes no warranties that use of
   the Software by the Licensee will not infringe any third party’s 
   Intellectual Property Rights nor that the Software will be of merchantable quality,
   or suitable for a particular purpose. CSIRO excludes all terms, conditions and
   warranties implied by custom, the general law or statute in relation to the
   Software.
*/

package taskModellingTool;

import javax.swing.*;
import java.util.*;
import javax.swing.tree.*;
import java.awt.Dimension;
import javax.swing.text.DefaultStyledDocument;


public class PasteManager {
    
    private static int bcIndex = 0;       // keep track of the index for generating the name
                                          // of the newly pasted boolean connector
    
    private static TreeMap booleanConnectorTreeMap = new TreeMap();
    
    private static int oldFrameWidth, oldFrameHeight;
    private static int newFrameWidth, newFrameHeight;

    // old ID (key), new linkableComponent (value)
    private static TreeMap pastedLinkableComponentTreeMap = new TreeMap();

    
    private static void pasteMultipleLinkableComponents(int posx, int posy, boolean auto, 
        TreePath treePath, String name, String parentName,
        LinkableComponent [] lcList) {
            
        TMUtility.display("pasteMultipleLinkableComponents : posx",posx);
        TMUtility.display("                                : posy",posy);
        TMUtility.display("                                : auto",auto);
        
        TMClipboard.findOffsetXY();
        
        int newOffsetX = -1;    // (newOffsetX,newOffsetY) is the top-left point of the first pasted component
        int newOffsetY = -1;
        
        final int FRAME_OFFSET = 10;  // minimum offset from the left-edge or the top-edge of the frame

        GraphicPanel gp = null;
        
        //TMUtility.display("pasteMultipleLinkableComponents : name",name);
        //TMUtility.display("pasteMultipleLinkableComponents : parentName",parentName);
        
        for (int i=0; i<lcList.length; i++) {
            LinkableComponent lc = lcList[i];
            
            Integer oldID = new Integer(lc.ID);
            
            LinkableComponent newLC = pasteLinkableComponent(posx,posy,auto,treePath,name,parentName,oldID);
            
            pastedLinkableComponentTreeMap.put(oldID,newLC);
            
            //TMUtility.display("pasteMultipleLinkableComponents : oldID",lc.ID);
            //TMUtility.displayLinkableComponent("pasteMultipleLinkableComponents",newLC);
            
            if ((newOffsetX < 0) || (newOffsetY < 0)) {
                newOffsetX = newLC.getX();
                newOffsetY = newLC.getY();
                
                if (newOffsetX < FRAME_OFFSET) newOffsetX = FRAME_OFFSET;
                if (newOffsetY < FRAME_OFFSET) newOffsetY = FRAME_OFFSET;
            }

            autoAdjustLinkableComponentPlace(newOffsetX,newOffsetY,newLC,lc);
            
            if (i == 0) gp = initFrameSize(newLC);
            adjustFrameSize(gp,newLC);
            
            //TMUtility.displayLinkableComponent("multiplePaste",newLC);
        }
        
        setNewFrameSize(gp);
    }
    
    private static void pasteMultipleLinks(TreePath treePath, String name, String parentName) {

        int linkIndex = GenericComponent.getIndex(Link.REF_STRING);

        // get the Link list from Clipboard
        Link [] linkList = TMClipboard.getLinks();

        //TMUtility.display("pasteMultipleLinks : name",name);
        //TMUtility.display("pasteMultipleLinks : parentName",parentName);
        
        for (int i=0; i<linkList.length; i++) {
            Link oldLink = linkList[i];
            
            Integer oldID = new Integer(oldLink.ID);
            
            // name is the parentName as the link is pasted to it
            //Link newLink = getPastedLink(oldID,linkIndex++,parentName);
            Link newLink = getPastedLink(oldID,linkIndex++,name);
        
            pasteLink(treePath,name,parentName,newLink);

            //TMUtility.displayLink("pasteMultipleLinks",newLink);
        }
    }
    
    public static void multiplePaste(int posx, int posy, boolean auto, 
        TreePath treePath, String name, String parentName) {
            
        //TMUtility.display("multiplePaste","");
        
        pastedLinkableComponentTreeMap.clear();
        booleanConnectorTreeMap.clear();

        // get the LinkableComponent list from Clipboard
        LinkableComponent [] lcList = TMClipboard.getLinkableComponents();

        if (checkIfRecursiveTask(treePath,lcList)) return;

        pasteMultipleLinkableComponents(posx,posy,auto,treePath,name,parentName,lcList);
        
        pasteMultipleLinks(treePath,name,parentName);

        // display attributes of the currentComponent in the attribute panel
        Manager.attributesPanel.displayAttributes(Manager.currentComponent);
        
        //mark parent task as dirty TRUE if it is not the root
        Manager.markTaskDirty(name,true);
        
        FileManager.MODIFIED = true;
    }
    
    /**
     * Recursive paste of a cut component
     */
    public static void paste(int posx,int posy) {
        boolean auto = (posx<0)||(posy<0);

        // get information
        TreePath treePath = Manager.tree.getSelectionPath();
        String name = Manager.treePathToString(treePath);
        String parentName;        
        boolean okComp = (name.equals(Manager.ROOT_STRING));
        if (!okComp) {
            parentName = Manager.treePathToString(Manager.truncTreePath(treePath));
            okComp = (Manager.skeleton.stringToGenericComponent(name,parentName) 
                instanceof CompositeComponent);
        }
        else
            parentName = Manager.skeleton.ROOT_STRING;
        
        //TMUtility.display("paste : name",name);
        //TMUtility.display("paste : parentName",parentName);
        //TMUtility.display("paste : okComp",okComp);

        if ((!okComp) || (TMClipboard.isEmpty())) return;
        
        if (TMClipboard.size() > 1) {
            posx = -1;
            posy = -1;
            auto = true;
            
            multiplePaste(posx,posy,auto,treePath,name,parentName);
            
            return;
        }

        Integer id2 = TMClipboard.getFirstID();
        
        if (checkIfRecursiveTask(treePath,id2)) return;
        
        pasteLinkableComponent(posx,posy,auto,treePath,name,parentName,id2);

        // display attributes of the currentComponent in the attribute panel
        Manager.attributesPanel.displayAttributes(Manager.currentComponent);
        
        //mark parent task as dirty TRUE if it is not the root
        Manager.markTaskDirty(name,true);
        
        FileManager.MODIFIED = true;
    }

    // check if pasting recursively
    private static boolean checkIfRecursiveTask(TreePath treePath, LinkableComponent [] lcList) {
        for (int i=0; i<lcList.length; i++) {
            LinkableComponent lc = lcList[i];
            
            Integer id2 = new Integer(lc.ID);
            
            if (checkIfRecursiveTask(treePath,id2)) return true;
        }
        
        return false;
    }
    
    private static boolean checkIfRecursiveTask(TreePath treePath, Integer id2) {
        boolean result = false;
        
        LinkableComponent lcBackup = TMClipboard.getLinkableComponent(id2);
        Node clipNodeBackup = TMClipboard.getNode(id2);
        
        //clipNodeBackup.printNode();
        
        boolean recursiveTaskFlag = checkIfRecursiveTask(treePath,lcBackup.getName());
        if (!recursiveTaskFlag) 
            recursiveTaskFlag = checkIfRecursiveTask(treePath,clipNodeBackup);
        if (recursiveTaskFlag) {
            String name = lcBackup.getName();
            
            MessageDialog.errorDialog(MainFrame.mainFrame,"Error - Paste recursively",
                "The task name(s) of the cut/copy component ("+name+") and \n"+
                "its successor is the same as the task name(s) of its ancestor.\n\n"+
                "Currently recursive tasks are not supported yet.\n\n");
            
            result = true;
        }
        
        return result;
    }
    
    private static Link getPastedLink(Integer oldID, int linkIndex, String parentName) {

        Link linkBackup = TMClipboard.getLink(oldID);

        LinkableComponent newlc1 = findLinkableComponent(linkBackup.lc1);
        LinkableComponent newlc2 = findLinkableComponent(linkBackup.lc2);
        
        Link result = new Link(linkBackup,linkIndex,newlc1,newlc2,parentName);
        result.setID();
        
        return result;
    }

    private static LinkableComponent getPastedLinkableComponent(int posx, int posy, boolean auto, Integer id2) {
        LinkableComponent lcBackup = TMClipboard.getLinkableComponent(id2);

        if (!auto) lcBackup.setLocation(posx,posy);

        LinkableComponent lc = pasteComponentWithNewID(lcBackup);
        
        return lc;
    }

    private static Node getPastedNode(Integer id2, LinkableComponent lc) {
        //TMUtility.display("getPastedNode","1");
        //Manager.skeleton.printRegister();
        
        Node clipNodeBackup = TMClipboard.getNode(id2);
        
        Node clipNode = new Node();
        
        // key (parentName), value (clipNode)
        // used to store the pasted clipNode before it has chance to be added to Manager.skeleton
        TreeMap pastedNodeTreeMap = new TreeMap();
        
        // key (Integer), value (null)
        // used to store the pasted linkName before it has chance to be added to Manager.skeleton
        TreeMap linkNameTreeMap = new TreeMap();
        
        duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton(lc.getName(),clipNode,clipNodeBackup,
            pastedNodeTreeMap,linkNameTreeMap);
        
        //TMUtility.display("getPastedNode","2");
        //Manager.skeleton.printRegister();
        //clipNode.printNode();
        //clipNode.print2ndNode();
        //clipNode.print3rdNode();
        
        return clipNode;
    }

    // if parentName exists in skeleton, duplicateNode to clipNode using the same IDs
    // else duplicateNode to clipNode using new IDs
    // --- continue the process for sub-levels
    private static void duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton(String parentName, Node clipNode, 
        Node parentNode, TreeMap pastedNodeTreeMap, TreeMap linkNameTreeMap) {
        
        if (parentNode == null) return;
        
        if (Manager.skeleton.isInTree(parentName)) {
            Node tempNode = Manager.skeleton.toChildNode(parentName);
            clipNode.duplicateNode(tempNode);

            /*
            TMUtility.display("duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton : parentName",parentName);
            TMUtility.display("            ","tempNode");
            tempNode.printNode();
            tempNode.print2ndNode();
            tempNode.print3rdNode();
            TMUtility.display("            ","clipNode");
            clipNode.printNode();
            clipNode.print2ndNode();
            clipNode.print3rdNode();
            */
            
            return;
        }
        
        if (pastedNodeTreeMap.containsKey(parentName)) {
            Node tempNode = (Node) pastedNodeTreeMap.get(parentName);
            clipNode.duplicateNode(tempNode);
            return;
        }
        
        //TMUtility.display("duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton : parentName",parentName);
        
        // treemap to store (oldID2, newID2) of linkable component for links to find
        //   its corresponding components later
        TreeMap idTreeMap = new TreeMap();
        Integer oldID2, newID2;
        
        String name;
        TreeMap treeMap;
        Integer id2;
        Couple couple;
        Node newNode;
        GenericComponent newGC = null;

        // create a duplicated set of tasks and / or boolean connectors first
        for (Iterator i=(parentNode.keySet()).iterator();i.hasNext();) {
            name = (String) i.next();
            treeMap = (TreeMap) parentNode.get(name);
            
            for (Iterator i2=(treeMap.keySet()).iterator();i2.hasNext();) {
                id2 = (Integer) i2.next();
                couple = (Couple) treeMap.get(id2);

                if (couple.object instanceof Task) {
                    newGC = new Task((Task) couple.object);
                    newGC.setID();
                    
                    idTreeMap.put(id2,new Integer(newGC.ID));

                    newNode = new Node();
                    duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton(name,newNode,couple.node,
                        pastedNodeTreeMap,linkNameTreeMap);
    
                    clipNode.add(newGC,newNode);
                }
                
                if (couple.object instanceof BooleanConnector) {
                    newGC = new BooleanConnector((BooleanConnector) couple.object);
                    newGC.setID();

                    idTreeMap.put(id2,new Integer(newGC.ID));

                    newNode = new Node();
                    duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton(name,newNode,couple.node,
                        pastedNodeTreeMap,linkNameTreeMap);
    
                    clipNode.add(newGC,newNode);
                }
            }
        }
        
        // then create a duplicated set of links
        LinkableComponent newlc1,newlc2;

        int linkIndex = GenericComponent.getIndex(Link.REF_STRING);

        //TMUtility.display("                linkIndex for "+parentName,linkIndex);
                    
        for (Iterator i=(parentNode.keySet()).iterator();i.hasNext();) {
            name = (String) i.next();
            treeMap = (TreeMap) parentNode.get(name);
            
            for (Iterator i2=(treeMap.keySet()).iterator();i2.hasNext();) {
                id2 = (Integer) i2.next();
                couple = (Couple) treeMap.get(id2);

                if (couple.object instanceof Link) {
                    Link link = (Link) couple.object;
                    
                    newlc1 = clipNode.findLinkableComponent(link.lc1,idTreeMap);
                    newlc2 = clipNode.findLinkableComponent(link.lc2,idTreeMap);
                    
                    Link newLink = new Link(link,linkIndex++,newlc1,newlc2,link.parentName);
                    newLink.setID();
                    checkLinkName(newLink,linkNameTreeMap);

                    newNode = new Node();
                    duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton(name,newNode,couple.node,
                        pastedNodeTreeMap,linkNameTreeMap);
    
                    //TMUtility.displayLink("duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton : link",newLink);
                    
                    clipNode.add(newLink,newNode);
                }
            }
        }

        //TMUtility.display("duplicateNode_WithNewIDs_OnlyIf_NotExistInSkeleton : parentName",parentName);
        //clipNode.printNode();
        
        // add to pastedNodeTreeMap
        pastedNodeTreeMap.put(parentName,clipNode);
        //displayPastedNodeTreeMap(pastedNodeTreeMap);
    }
    
    private static void checkLinkName(Link newLink, TreeMap linkNameTreeMap) {
        String name = newLink.getName();
        
        if (linkNameTreeMap.containsKey(name)) {
            int linkindex = 0;
            while (true) {
                name = Link.REF_STRING+linkindex;
                
                if (!Manager.skeleton.isInTree(name)) {
                    if (!linkNameTreeMap.containsKey(name)) {
                        newLink.setName(name);
                        break;
                    }
                }
                
                linkindex++;
            }
        }
        
        linkNameTreeMap.put(name,null);
        
        //TMUtility.display("checkLinkName : name",name);
    }
    
    private static void displayPastedNodeTreeMap(TreeMap pastedNodeTreeMap) {
        System.out.println("---------------- pastedNodeTreeMap ----------------");

        for (Iterator i = (pastedNodeTreeMap.keySet()).iterator();i.hasNext();) {
            String parentName = (String) i.next();
            Node clipNode = (Node) pastedNodeTreeMap.get(parentName);
        
            TMUtility.display("pastedNodeTreeMap : parentName",parentName);
            clipNode.printNode();
        }

        System.out.println("--------------- End pastedNodeTreeMap -------------");
    }
    
    // add the cut couple into nodeToBePastedTo
    private static Node getNodeToBePastedTo(String name, String parentName, 
        LinkableComponent lc, Node clipNode) {

        Node nodeToBePastedTo = null;
        
        if (Manager.skeleton.hasChildNode(name)) {
            nodeToBePastedTo = Manager.skeleton.toChildNode(name);
            nodeToBePastedTo.add(lc,clipNode);
        } else {
            Node parentNode = Manager.skeleton.toParentNode(name,parentName);
            nodeToBePastedTo = new Node();
            nodeToBePastedTo.add(lc,clipNode);
            parentNode.modify(name,nodeToBePastedTo);
        }
        
        return nodeToBePastedTo;
    }

    private static void pasteLink(TreePath treePath, String name, String parentName, Link newLink) {
        
        Node nodeToBePastedTo = Manager.skeleton.toChildNode(name);
        nodeToBePastedTo.add(newLink);
        
        String linkName = newLink.getName();
        Integer linkID = new Integer(newLink.ID);
        
        // add information to nodeRegister
        Manager.skeleton.addInRegister(linkName,linkID,name,nodeToBePastedTo);

        pasteRTFDB(linkName);

        // update the tree to add the link
        int linkIndex = Manager.skeleton.getTreeIndex(linkName,name,linkID);
        Manager.tree.addInTree(treePath,linkName,linkIndex);
        
        // update the frame pointed by the current treePath
        Manager.updateChildFrame(treePath);

        // if not root, set the name frame composite, update its parentName frame
        //   update everything of the same duplicated tasks
        if (!Manager.isRoot(treePath)) {
            Integer currentID = Manager.skeleton.toChildNodeID(name);
            
            //synchronize everything of the same duplicated tasks
            EditManager.restoreChildrenCoherence(name,parentName,currentID,false);
        }
    }
    
    private static LinkableComponent pasteLinkableComponent(int posx, int posy, boolean auto, 
        TreePath treePath, String name, String parentName, Integer oldID) {
        
        //TMUtility.display("pasteLinkableComponent : name",name);
        //TMUtility.display("pasteLinkableComponent : parentName",parentName);
        //Manager.skeleton.printRegister();

        LinkableComponent lc = getPastedLinkableComponent(posx,posy,auto,oldID);
        Node clipNode = getPastedNode(oldID,lc);

        Node nodeToBePastedTo = getNodeToBePastedTo(name,parentName,lc,clipNode);
        
        //TMUtility.displayLinkableComponent("pasteLinkableComponent",lc);
        //clipNode.printNode();
        //clipNode.print2ndNode();
        //clipNode.print3rdNode();
        //TMUtility.displayLine(1);
        //nodeToBePastedTo.printNode();
        //nodeToBePastedTo.print2ndNode();
        //nodeToBePastedTo.print3rdNode();
        //TMUtility.displayLine(3);
        
        Integer id2 = new Integer(lc.ID);
        
        // add information to nodeRegister including all the children
        Manager.skeleton.addRecursivelyInRegister(lc.getName(),id2,name,
            nodeToBePastedTo);

        //Manager.skeleton.printRegister();
        
        // add RTF comment fields if they do not exist yet
        pasteRTFDB(lc.getName());
        pasteRTFDB(clipNode);
        
        // update the tree to add the cut couple & all its children
        Manager.tree.addRecursivelyInTree(treePath,lc.getName(),clipNode);
        
        // update the frame pointed by the current treePath
        Manager.updateChildFrame(treePath);

        // if not root, set the name frame composite, update its parentName frame
        //   update everything of the same duplicated tasks
        if (!Manager.isRoot(treePath)) {
            GenericComponent [] gcList = Manager.skeleton.toParentNode(name,parentName).getComponentList(name);
            for (int i=0; i<gcList.length; i++) {
                GenericComponent gc2 = gcList[i];
                //TMUtility.displayGenericComponent("pasteLinkableComponent",gc2);

                if (gc2 instanceof CompositeComponent) ((CompositeComponent)gc2).setComposite(true);
            }
            
            Manager.updateParentFrame(treePath);

            //synchronize everything of the same duplicated tasks : 
            //to make all duplicated tasks of name point to the same decomposition, 
            //same fields of (name,parentName)
            //update tree to reflect the new structure of duplicated tasks pointing to the same decomposition
            EditManager.restoreChildrenCoherence(name,parentName);
        }
        
        // if auto, place couple automatically
        if (auto) Manager.autoPlace(lc,nodeToBePastedTo);
        
        return lc;
    }

    public static void paste() {
        paste(-1,-1);
    }

    private static void autoAdjustLinkableComponentPlace(int newOffsetX, int newOffsetY,
        LinkableComponent newLC, LinkableComponent oldLC) {

        // adjust to new component coordinates
        int x = oldLC.getX() - TMClipboard.offsetX;
        int y = oldLC.getY() - TMClipboard.offsetY;
        
        newLC.setLocation(newOffsetX+x,newOffsetY+y);
        
        newLC.backupX = newLC.getX();
        newLC.backupY = newLC.getY();
    }
    
    private static GraphicPanel initFrameSize(LinkableComponent newLC) {
        //TMUtility.displayLinkableComponent("initFrameSize : newLC",newLC);
        
        GraphicPanel result = (GraphicPanel) newLC.getParent();

        if (result == null) {
            oldFrameWidth = -1;
            oldFrameHeight = -1;
        } else {
            //TMUtility.display("initFrameSize",result.name);
        
            oldFrameWidth = result.getWidth();
            oldFrameHeight = result.getHeight();
        }
        
        newFrameWidth = oldFrameWidth;
        newFrameHeight = oldFrameHeight;
        
        return result;
    }
    
    // adjust size of the graphic panel if pasted component exceed the panel size
    private static void adjustFrameSize(GraphicPanel gp, LinkableComponent newLC) {
        if (gp == null) return;
        
        //TMUtility.display("adjustFrameSize : name",newLC.getName());
        //TMUtility.display("    newFrameWidth = ",newFrameWidth);
        //TMUtility.display("    newFrameHeight = ",newFrameHeight);
        
        int currentNewFrameWidth = newFrameWidth;
        int currentNewFrameHeight = newFrameHeight;
        
        final int GAP_X = 10;   // x gap to separate the last component with the frame border
        final int GAP_Y = 10;   // the corresponding y gap
        
        int tempWidth = newLC.getX() + newLC.getWidth() + GAP_X;
        if (tempWidth > currentNewFrameWidth) currentNewFrameWidth = tempWidth;
        
        int tempHeight = newLC.getY() + newLC.getHeight() + GAP_Y;
        if (tempHeight > currentNewFrameHeight) currentNewFrameHeight = tempHeight;
        
        if ((currentNewFrameWidth > newFrameWidth) || (currentNewFrameHeight > newFrameHeight)) {
            //TMUtility.display("    currentNewFrameWidth = ",currentNewFrameWidth);
            //TMUtility.display("    currentNewFrameHeight = ",currentNewFrameHeight);
            
            newFrameWidth = currentNewFrameWidth;
            newFrameHeight = currentNewFrameHeight;
        }
    }
    
    private static void setNewFrameSize(GraphicPanel gp) {
        if (gp == null) return;
        
        if ((newFrameWidth > oldFrameWidth) || (newFrameHeight > oldFrameHeight)) {
            gp.setPreferredSize(new Dimension(newFrameWidth, newFrameHeight));
            gp.revalidate();
        }
    }
    
    private static boolean checkIfRecursiveTask(TreePath treePath, String name) {
        String treePathName = Manager.treePathToString(treePath);
        
        //TMUtility.display("checkIfRecursiveTask - "+name,treePathName);
        
        if (treePathName.equals(name)) return true;
        
        if (treePathName.equals(Manager.ROOT_STRING))
            return false;
        else {
            TreePath parentTreePath = Manager.truncTreePath(treePath);
            return checkIfRecursiveTask(parentTreePath,name);
        }
    }
    
    private static boolean checkIfRecursiveTask(TreePath treePath, Node node) {
        if (node == null) return false;
        
        Set keys = node.keySet();

        String childName;
        Node childNode;
        for (Iterator it = keys.iterator();it.hasNext();) {
           childName = (String) it.next();
           
           if (checkIfRecursiveTask(treePath,childName)) return true;
           
           if (node.hasBranch(childName)) {
               childNode = node.getChild(childName);
               
               if (checkIfRecursiveTask(treePath,childNode)) return true;
           }
        }

        return false;
    }
    
    public static LinkableComponent findPastedComponentFromOldID(Integer id2) {
        LinkableComponent result = null;
        
        if (pastedLinkableComponentTreeMap.containsKey(id2))
            result = (LinkableComponent) pastedLinkableComponentTreeMap.get(id2);
        
        return result;
    }

    public static TreeMap getPastedTreeMap() {
        // id2 (key), lc (value)
        TreeMap result = new TreeMap();
        
        // extracted from pastedLinkableComponentTreeMap with old ID (key), new linkableComponent (value)
        Set keys = pastedLinkableComponentTreeMap.keySet();
        for (Iterator it = keys.iterator();it.hasNext();) {
            Integer oldID = (Integer) it.next();
            LinkableComponent lc = (LinkableComponent) pastedLinkableComponentTreeMap.get(oldID);
            
            Integer id2 = new Integer(lc.ID);
            result.put(id2,lc);
        }
        
        return result;
    }
    
    private static LinkableComponent findLinkableComponent(LinkableComponent lc) {
        LinkableComponent result = null;
        
        Integer id2 = new Integer(lc.ID);

        //TMUtility.display("findLinkableComponent : id2",id2);
        
        if (pastedLinkableComponentTreeMap.containsKey(id2))
            result = (LinkableComponent) pastedLinkableComponentTreeMap.get(id2);
        
        //TMUtility.displayLinkableComponent("findLinkableComponent : result",result);
        
        return result;
    }
    
    private static LinkableComponent pasteComponentWithNewID(LinkableComponent gcBackup) {
        LinkableComponent gc = null;
        
        if (gcBackup instanceof Task) {
            gc = new Task((Task) gcBackup);
            gc.setID();
        }
        
        if (gcBackup instanceof BooleanConnector) {
            gc = new BooleanConnector((BooleanConnector) gcBackup);
            findBooleanConnectorNewName(gc);
            gc.setID();
        }
        
        return gc;
    }
    
    private static void findBooleanConnectorNewName(GenericComponent gc) {
        for (int i = 0; ; i++) {
            String newName = BooleanConnector.REF_STRING + i;
            
            if (!Manager.skeleton.isInTree(newName)) {
                if (!booleanConnectorTreeMap.containsKey(newName)) {
                    gc.setName(newName);
                    
                    booleanConnectorTreeMap.put(newName,null);

                    //TMUtility.display("findBooleanConnectorNewName",newName);
                    return;
                }
            }
        }
    }
    
    private static void pasteRTFDB(String name) {
    	//shijian 2001-10-2
    	/*
        if (!Manager.RTFDB.containsKey(name)) {
            //TMUtility.display("pasteRTFDB",name);
            DefaultStyledDocument doc = TMClipboard.getRTFComment(name);
            Manager.RTFDB.add(name,doc);
        }
        */
        if (!Manager.RTFDBM.contains(name)) {
        	System.out.println("no there is no: " + name);
            Manager.RTFDBM.copy(name,TMClipboard.getRTFM());
        }
        else
        {
        	System.out.println("yes there is : " + name);
        }
        
    }
    
    private static void pasteRTFDB(Node node) {
        if (node == null) return;
        
        Set keys = node.keySet();

        String childName;
        Node childNode;
        for (Iterator it = keys.iterator();it.hasNext();) {
           childName = (String) it.next();
           
           pasteRTFDB(childName);
           
           if (node.hasBranch(childName)) {
               childNode = node.getChild(childName);

               pasteRTFDB(childNode);
           }
        }
    }
    
}