/*
   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.lang.reflect.*;


public class EditManager {

    public static boolean abort;
    
    public synchronized static void edit(boolean duplicatedTaskNameAllowed) {
        abort = false;

        if (Manager.currentComponent == null) return;
        
        final GenericComponent comp = Manager.currentComponent;
        
        final String oldName = comp.getName();
        
        //TreePath treePath = Manager.fetchTreePath(oldName,Manager.tree);
        Integer id2 = new Integer(comp.ID);
        String parentName = Manager.skeleton.toParentName(oldName,id2);
        //System.out.println("edit : "+parentName);
        TreePath treePath = Manager.fetchTreePath(oldName,parentName,Manager.tree,id2);
        
        boolean modifyItselfFromOtherComponents = true;
        
        MainFrame.mainFrame.repaint();
        EditionDialog dialog = new EditionDialog(comp,duplicatedTaskNameAllowed);

        abort = dialog.isAborted();
        
        //System.out.println("abort = "+abort);
        
        modifyItselfFromOtherComponents = dialog.willModifyItself();

        if (abort) return;
        
        String newName = comp.getName();
        
        id2 = new Integer(comp.ID);
        
        //During the edition if the name has changed,
        //an incoherence has appeared since the component
        //is still registered to the old name.
        //updateName will restore the coherence.
        
        //step1: update the tree --- remove oldName from tree, append newName to tree
        //(If do it later, we won't be able to spot the nodes to update)
        
        //get all parent task names of oldName into modif[]
        /*String [] parentNames = skeleton.toUpdate(oldName);
        TreePath t;
        Node n;
        for (int i=0;i<parentNames.length;i++) {
            //t contains all nodes from its parent modif[i] to oldName
            t=fetchTreePath(oldName,parentNames[i],tree);
            
            //remove oldName from tree
            tree.removeInTree(t);
            
            //get node corresponding to oldName in skeleton
            n=skeleton.toChildNode(oldName,parentNames[i]);
            
            tree.addRecursivelyInTree(truncTreePath(t),newName,n);
        }*/
           
        //System.out.println("oldName = "+oldName);
        //System.out.println("modifyItselfFromOtherComponents = "+modifyItselfFromOtherComponents);
        
        int numDuplicatedTasks = Manager.skeleton.getNumDuplicatedTasks(oldName);
        //TMUtility.display("edit : numDuplicatedTasks",numDuplicatedTasks);

        if (!oldName.equals(newName)) {
            if (modifyItselfFromOtherComponents && (numDuplicatedTasks > 1))
                editModifyItself(oldName,id2,newName);
            else
                editModifyOthers(oldName,id2,newName);
        }
            
        TreePath parentTreePath = Manager.truncTreePath(treePath);
        
        //step3: restore the coherence of the components
        parentName = Manager.treePathToString(parentTreePath);
        //System.out.println("edit : "+parentName);

        if (modifyItselfFromOtherComponents) 
            restoreChildrenCoherenceFromExisting(comp.getName(),parentName,id2);
        else {
            // modify others
            if (oldName.equals(newName)) {
                synchronizeCoreFields(comp.getName(),parentName,id2);
            }
            else {
                restoreChildrenCoherence(comp.getName(),parentName,id2,true);
                
                checkIfCloseFrame(comp);
            }
        }
        
        //synchronize tree structure with that of skeleton
        if (parentName.equals(Manager.ROOT_STRING))
            synchronizeTree(newName);
        else
            synchronizeTree(parentName);

        //select the corresponding node in tree
        Manager.selectNode(Manager.fetchTreePath(comp.getName(),parentName,Manager.tree,id2));
        
        //display attributes of current task selected
        if (Manager.currentComponent == comp) Manager.attributesPanel.displayAttributes(comp);
            
        // set Task.dirty = true
        if (comp instanceof Task) ((Task)comp).dirty =true;
    }
    
    private static void checkIfCloseFrame(GenericComponent comp) {
        if (comp instanceof Task) {
            Task task = (Task) comp;
            
            if (!task.composite) {
                // remove name frame if it exists
                Manager.desktop.deleteFrame(task.name);
            }
        }
    }

    // modify itself for a duplicated task among a group of the same duplicated tasks
    private static void editModifyItself(String oldName, Integer id2, String newName) {
        //correct only the oldName with ID = id2 in tree to newName
        TreeMap parentTreeMap = (TreeMap) Manager.skeleton.nodeRegister.get(oldName);
        Set keys = parentTreeMap.keySet();
        TreePath t;

        for (Iterator it=keys.iterator(); it.hasNext();) {
            String tmpParentName = (String) it.next();
            Node tmpParentNode = (Node) parentTreeMap.get(tmpParentName);

            for (Iterator itID = tmpParentNode.getIDIterator(oldName); itID.hasNext();) {
                Integer currentID = (Integer) itID.next();
                
                if (currentID.equals(id2)) {
                    //t contains all nodes from its parent to oldName
                    t = Manager.fetchTreePath(oldName,tmpParentName,Manager.tree,currentID);
                
                    //remove oldName from tree
                    Manager.tree.removeInTree(t);
                
                    //get node corresponding to oldName in skeleton
                    Node tmpCurrentNode = Manager.skeleton.toChildNode(oldName,tmpParentName,currentID);
                    int index = Manager.skeleton.getPositionForDuplicatedTasks(oldName,tmpParentName,currentID);
                
                    Manager.tree.addRecursivelyInTree(Manager.truncTreePath(t),newName,tmpCurrentNode,index-1);
                }
            }
        }
        
        //step2: update the frames
        /*ComponentInternalFrame frame = (ComponentInternalFrame)desktop.fetchFrame(oldName);
        if (frame!=null) {
            frame.name=newName;
            frame.setTitle(newName);
            if (frame.gpanel!=null) frame.gpanel.name = newName;
        }*/
            
        //step3: update the names.
        Manager.skeleton.modifyItself_UpdateName(oldName,id2,newName);
        
        //RTFDB.put(newName,RTFDB.remove(oldName));
        //Manager.RTFDB.put(newName,Manager.RTFDB.get(oldName));
        //shijian 25-9-2001
        Manager.RTFDBM.changeName(newName,oldName);
    }

    private static void editModifyOthers(String oldName, Integer id2, String newName) {
        //TMUtility.display("editModifyOthers --- oldName",oldName);
        //TMUtility.display("editModifyOthers --- id2",id2);
        //TMUtility.display("editModifyOthers --- newName",newName);

        //correct all oldName in tree to newName
        TreeMap parentTreeMap = (TreeMap) Manager.skeleton.nodeRegister.get(oldName);
        Set keys = parentTreeMap.keySet();
        TreePath t;

        for (Iterator it=keys.iterator(); it.hasNext();) {
            String tmpParentName = (String) it.next();
            Node tmpParentNode = (Node) parentTreeMap.get(tmpParentName);

            for (Iterator itID = tmpParentNode.getIDIterator(oldName); itID.hasNext();) {
                Integer currentID = (Integer) itID.next();
                
                //TMUtility.display("editModifyOthers --- currentID",currentID);
                
                //t contains all nodes from its parent to oldName
                // need to omit currentID as the tree is changing in this process and the index position
                //   for duplicated tasks is incorrect
                //t = fetchTreePath(oldName,tmpParentName,tree,currentID);
                t = Manager.fetchTreePath(oldName,tmpParentName,Manager.tree);
            
                //remove oldName from tree
                Manager.tree.removeInTree(t);
            
                //get node corresponding to oldName in skeleton
                Node tmpCurrentNode = Manager.skeleton.toChildNode(oldName,tmpParentName,currentID);
                int index = Manager.skeleton.getPositionForDuplicatedTasks(oldName,tmpParentName,currentID);
            
                Manager.tree.addRecursivelyInTree(Manager.truncTreePath(t),newName,tmpCurrentNode,index-1);
            }
        }
        
        //step2: update the frames
        //TMUtility.display("editModifyOthers","step2");
        ComponentInternalFrame frame = (ComponentInternalFrame) Manager.desktop.fetchFrame(oldName);
        if (frame != null) {
            frame.name = newName;
            frame.setTitle(newName);
            if (frame.gpanel != null) frame.gpanel.name = newName;
        }
        
        //TMUtility.display("editModifyOthers","before step3");
        //skeleton.printRegister();

        //step3: update the names.
        //TMUtility.display("editModifyOthers","before");
        //Manager.skeleton.printRegister();
        Manager.skeleton.updateName(oldName,newName);
        //TMUtility.display("editModifyOthers","after");
        //Manager.skeleton.printRegister();
        
        //Manager.RTFDB.put(newName,Manager.RTFDB.remove(oldName));
        //shijian 25-9-2001
        Manager.RTFDBM.changeName(newName,oldName);
        Manager.RTFDBM.remove(oldName);

        //TMUtility.display("editModifyOthers","after step3");
        //skeleton.printRegister();
    }
    
    private static void restoreChildrenCoherenceFromExisting(String name,String parentName,Integer id2) {
        TreeMap t = (TreeMap) Manager.skeleton.nodeRegister.get(name);
        if (t != null) {
            // get parentNames array & parentNodes array
            Set keys = t.keySet();
            
            Node [] parentNodes = new Node[keys.size()];
            String [] parentNames = new String[keys.size()];
            
            int i = 0;
            int index = 0;
            for (Iterator it=keys.iterator();it.hasNext();i++) {
                String s = (String) it.next();
                
                parentNames[i] = s;
                parentNodes[i] = (Node)t.get(s);
                
                if (s.equals(parentName))
                    index=i;
            }

            for (i=0;i<parentNodes.length;i++) {
                for (Iterator itCurrentID = parentNodes[i].getIDIterator(name);itCurrentID.hasNext();) {
                    Integer currentID = (Integer)(itCurrentID.next());

                    if (!currentID.equals(id2)) {
                        Node currentNode = parentNodes[index].getChild(name,id2);
                        
                        //get decomposition of other duplicated task to copy from
                        Node otherNode = parentNodes[i].getChild(name,currentID);
                    
                        //update current duplicated task to point to the same decomposition tree
                        parentNodes[index].modify(name,otherNode,id2);
        
                        TreePath treePath = Manager.fetchTreePath(name,parentNames[index],Manager.tree,id2);
                        
                        //remove name within names[index] in tree
                        Manager.tree.removeInTree(treePath);
                        
                        //n = node of name within names[index]
                        Node n = Manager.skeleton.toChildNode(name,parentNames[index],id2);
                        int index1 = Manager.skeleton.getPositionForDuplicatedTasks(name,parentNames[index],id2);
                        
                        //add name to parentTreePath as well as its tree structure similar to currentNode
                        Manager.tree.addRecursivelyInTree(Manager.truncTreePath(treePath),name,n,index1-1);

                        //close the frame if it is open
                        closeFrame(name);

                        //skeleton.printRegister();
                        
                        //remove unreferenced names in nodeRegister
                        TreeMap validNames = new TreeMap();
                        getAllValidNames(Manager.skeleton.root,validNames);
                        
                        deleteUnreferencedNames(currentNode,validNames);

                        //skeleton.printRegister();
                        
                        //to get out of for-loop
                        i = parentNodes.length;
                        
                        break;
                    }
                }
            }
            
            // copy all fields of the same duplicated task of other parent to that of the task of (name,parentName)
            restoreAttributesCoherenceFromExisting(name,parentName,id2);
        }    
    }
    
    private static void getAllValidNames(Node node,TreeMap validNames) {
        for (Iterator i=(node.keySet()).iterator();i.hasNext();) {
            String name = (String) i.next();
            
            addName_to_ValidNames(name,validNames);

            for (Iterator itID = node.getIDIterator(name);itID.hasNext();) {
                Integer id2 = (Integer) itID.next();
                
                Node child = (node.getCouple(name,id2)).node;
                if (child!=null) getAllValidNames(child,validNames);
            }
        }
    }

    private static void addName_to_ValidNames(String name,TreeMap validNames) {
        if (validNames.containsKey(name)) return;

        validNames.put(name,null);
    }
    
    private static void deleteUnreferencedNames(Node node,TreeMap validNames) {
        Set keys = node.keySet();
        
        if (keys.isEmpty()) return;
        
        for (Iterator it=keys.iterator();it.hasNext();) {
            String name = (String) it.next();
            
            deleteUnreferencedNames(name,validNames);
            
            for (Iterator itID = node.getIDIterator(name);itID.hasNext();) {
                Integer id2 = (Integer) itID.next();
                
                Node childNode = node.getChild(name,id2);
                
                if (childNode.size() > 0) deleteUnreferencedNames(childNode,validNames);
            }
        }
    }
    
    private static void deleteUnreferencedNames(String name,TreeMap validNames) {
        if (validNames.containsKey(name)) return;
        
        Manager.skeleton.nodeRegister.remove(name);
    }

    private static void restoreAttributesCoherenceFromExisting(String name,String parentName,Integer id2) {
        Object o = Manager.skeleton.nodeRegister.get(name);
        
        if (o instanceof TreeMap) {
            TreeMap t = (TreeMap) o;
            
            //get all parent nodes of name
            Set keys = t.keySet();
            Node [] tmpParentNodes = new Node[keys.size()];
            
            int i=0;
            int index=0;
            for (Iterator it=keys.iterator();it.hasNext();i++) {
                String tmpParentName = (String) it.next();
                
                tmpParentNodes[i] = (Node) t.get(tmpParentName);
                
                if (tmpParentName.equals(parentName))
                    index=i;
            }
            
            Field [] fields;
            TreePath treePath;
            
            for (i=0; i<tmpParentNodes.length; i++) {
                for (Iterator itCurrentID = tmpParentNodes[i].getIDIterator(name);itCurrentID.hasNext();) {
                    Integer currentID = (Integer) itCurrentID.next();

                    if (!currentID.equals(id2)) {
                        // get fields of other duplicated component to clone from
                        GenericComponent otherComponent = tmpParentNodes[i].getComponent(name,currentID);
                        Field [] otherFields = getFieldsToClone(otherComponent);
                        
                        // clone fields to the current duplicated task
                        GenericComponent tmpCurrentComponent = tmpParentNodes[index].getComponent(name,id2);
                        fields = getFieldsToClone(tmpCurrentComponent);
                        
                        String type;
                        for (int j=0;j<fields.length;j++) {
                            try {
                                if (tmpCurrentComponent instanceof CompositeComponent) {
                                    type = fields[j].getType().getName();
                                    
                                    if (type.equals("java.lang.String")) {
                                           fields[j].set(tmpCurrentComponent,otherFields[j].get(otherComponent));
                                    }
                                    else if (type.equals("int")) {
                                           fields[j].setInt(tmpCurrentComponent,otherFields[j].getInt(otherComponent));
                                    }
                                    else if (type.equals("boolean")) {
                                           fields[j].setBoolean(tmpCurrentComponent,otherFields[j].getBoolean(otherComponent));
                                       }
                                   }
                            }
                            catch (Exception e) {
                                System.err.println("getField error");
                            }
                        }
                                        
                        tmpCurrentComponent.repaint();
                        
                        i = tmpParentNodes.length;
                        
                        break;
                    }
                }
            }
        }
    }

    //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
    public static void restoreChildrenCoherence(String name,String parentName) {
        TreeMap t = (TreeMap) Manager.skeleton.nodeRegister.get(name);
        
        if (t != null) {
            Set keys = t.keySet();
            
            //current components of name
            //GenericComponent [] currentComponents=new GenericComponent[keys.size()];
            
            Node [] parentNodes = new Node[keys.size()];
            String [] parentNames = new String[keys.size()];
            
            int i = 0;
            int index = 0;
            for (Iterator it=keys.iterator();it.hasNext();i++) {
                String s = (String) it.next();
                parentNames[i] = s;
                parentNodes[i] = (Node) t.get(s);
                //currentComponents[i]=parentNodes[i].getComponent(name);
                if (s.equals(parentName)) {
                     index = i;
                }
            }
            
            TreePath treePath;
            Node n;
            
            //current decomposition of name
            Node currentNode = parentNodes[index].getChild(name);
            
            for (i=0;i<parentNodes.length;i++) if (i!=index) {
                //update all other duplicated tasks to point to the same decomposition tree
                parentNodes[i].modify(name,currentNode);

                treePath = Manager.fetchTreePath(name,parentNames[i],Manager.tree);
                
                //remove name within names[i] in tree
                Manager.tree.removeInTree(treePath);
                
                //n = node of name within names[i]
                n = Manager.skeleton.toChildNode(name,parentNames[i]);
                
                //add name to parentTreePath as well as its tree structure similar to currentNode
                Manager.tree.addRecursivelyInTree(Manager.truncTreePath(treePath),name,n);
            }
            
            // copy all fields of task of (name,parentName) to the fields of the same duplicated tasks of the other parents
            restoreAttributesCoherence(name,parentName);
        }
    }

    //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
    public static void restoreChildrenCoherence(String name,String parentName,Integer id2,boolean changeAttributeFlag) {
        TreeMap t = (TreeMap) Manager.skeleton.nodeRegister.get(name);
        //System.out.println("restoreChildrenCoherence : name = "+name+", id2 = "+id2);
        
        if (t != null) {
            // get parentNames array & parentNodes array
            Set keys = t.keySet();
            
            Node [] parentNodes = new Node[keys.size()];
            String [] parentNames = new String[keys.size()];
            
            int i = 0;
            int index = 0;
            for (Iterator it=keys.iterator();it.hasNext();i++) {
                String s = (String) it.next();
                parentNames[i] = s;
                parentNodes[i] = (Node) t.get(s);
                if (s.equals(parentName)) {
                     index = i;
                }
            }
            
            TreePath treePath;
            Node n,currentNode;
            
            if (!parentNodes[index].hasChild(name,id2)) return;    //for deleted node
            
            //get current decomposition of name for other duplicated task to match with
            currentNode = parentNodes[index].getChild(name,id2);
            //TMUtility.display("restoreChildrenCoherence","currentNode");
            //currentNode.printNode();
            
            Node oldNode = null;

            for (i=0;i<parentNodes.length;i++) {
                for (Iterator itCurrentID = parentNodes[i].getIDIterator(name);itCurrentID.hasNext();) {
                    Integer currentID = (Integer)(itCurrentID.next());
                    //System.out.println("restoreChildrenCoherence : currentID = "+currentID);

                    if (!currentID.equals(id2)) {
                        //get the old node to be deleted
                        oldNode = parentNodes[i].getChild(name,currentID);
                        
                        //update all other duplicated tasks to point to the same decomposition tree
                        parentNodes[i].modify(name,currentNode,currentID);
        
                        treePath = Manager.fetchTreePath(name,parentNames[i],Manager.tree,currentID);
                        
                        //remove name within names[i] in tree
                        Manager.tree.removeInTree(treePath);
                        
                        //n = node of name within names[i]
                        n = Manager.skeleton.toChildNode(name,parentNames[i],currentID);
                        int index1 = Manager.skeleton.getPositionForDuplicatedTasks(name,parentNames[i],currentID);
                        
                        //add name to parentTreePath as well as its tree structure similar to currentNode
                        Manager.tree.addRecursivelyInTree(Manager.truncTreePath(treePath),name,n,index1-1);
                    }
                }
            }
            
            deleteOldNodeIfNotReferenced(oldNode);
            
            // copy all fields of task of (name,parentName) to the fields of the same duplicated tasks of the other parents
            if (changeAttributeFlag) restoreAttributesCoherence(name,parentName,id2);
        }
    }
    
    private static void deleteOldNodeIfNotReferenced(Node oldNode) {
        if (oldNode == null) return;
        
        //TMUtility.display("deleteOldNodeIfNotReferenced","oldNode");
        //oldNode.printNode();
        
        //Manager.skeleton.printRegister();
        
        for (Iterator i=(oldNode.keySet()).iterator();i.hasNext();) {
            String name = (String) i.next();
            TreeMap treeMap = (TreeMap) oldNode.get(name);
            
            Manager.skeleton.deleteNameIfNotReferenced(name);
            
            //TMUtility.display("deleteOldNodeIfNotReferenced : name",name);
            //Manager.skeleton.printRegister();

            Integer id2 = (Integer) treeMap.firstKey();
            Node node = oldNode.getChild(name,id2);
            deleteOldNodeIfNotReferenced(node);
        }
    }
    
    // copy all fields of task of (name,parentName) to the fields of the same duplicated tasks of the other parents
    public static void restoreAttributesCoherence(String name,String parentName) {
        Object o = Manager.skeleton.nodeRegister.get(name);
        
        if (o instanceof TreeMap) {
            TreeMap t = (TreeMap) o;
            
            Set keys = t.keySet();
            GenericComponent [] tmpCurrentComponents = new GenericComponent[keys.size()];
            Node [] tmpParentNodes = new Node[keys.size()];
            
            int i = 0;
            int index = 0;
            for (Iterator it=keys.iterator();it.hasNext();i++) {
                String tmpParentName = (String) it.next();
                
                tmpParentNodes[i] = (Node) t.get(tmpParentName);
                
                tmpCurrentComponents[i] = tmpParentNodes[i].getComponent(name);
                
                if (tmpParentName.equals(parentName)) {
                     index = i;
                }
            }
            
            Field [] originalFields = getFieldsToClone(tmpCurrentComponents[index]);
            Field [] fields;
            TreePath treePath;
            
            for (i=0; i<tmpParentNodes.length; i++) if (i!=index) {
                // field coherence            
                fields = getFieldsToClone(tmpCurrentComponents[i]);
                String type;
                
                for (int j=0; j<fields.length; j++) {
                    try {
                        if (tmpCurrentComponents[i] instanceof CompositeComponent) {
                            type = fields[j].getType().getName();
                            
                            if (type.equals("java.lang.String")) {
                                   fields[j].set(tmpCurrentComponents[i],originalFields[j].get(tmpCurrentComponents[index]));
                            }
                            else if (type.equals("int")) {
                                   fields[j].setInt(tmpCurrentComponents[i],originalFields[j].getInt(tmpCurrentComponents[index]));
                            }
                            else if (type.equals("boolean")) {
                                   fields[j].setBoolean(tmpCurrentComponents[i],originalFields[j].getBoolean(tmpCurrentComponents[index]));
                               }
                           }
                    }
                    catch (Exception e) {
                        System.err.println("getField error");
                    }
                }
                                
                tmpCurrentComponents[i].repaint();
            }
        }
    }

    public static void restoreAttributesCoherence(String name,String parentName,Integer id2) {
        Object o = Manager.skeleton.nodeRegister.get(name);
        
        if (o instanceof TreeMap) {
            TreeMap t = (TreeMap)o;

            //get all parent nodes of name
            Set keys = t.keySet();
            Node [] tmpParentNodes = new Node[keys.size()];
            
            int i = 0;
            int index = 0;
            for (Iterator it=keys.iterator();it.hasNext();i++) {
                String tmpParentName = (String) it.next();
                
                tmpParentNodes[i] = (Node) t.get(tmpParentName);
                
                if (tmpParentName.equals(parentName))
                    index = i;
            }
            
            // get fields of current component to clone from
            GenericComponent currentComponent = tmpParentNodes[index].getComponent(name,id2);
            Field [] originalFields = getFieldsToClone(currentComponent);

            Field [] fields;
            TreePath treePath;
            
            for (i=0; i<tmpParentNodes.length; i++) {
                for (Iterator itCurrentID = tmpParentNodes[i].getIDIterator(name);itCurrentID.hasNext();) {
                    Integer currentID = (Integer) itCurrentID.next();

                    if (!currentID.equals(id2)) {
                        // clone fields of the other duplicated tasks
                        GenericComponent tmpCurrentComponent = tmpParentNodes[i].getComponent(name,currentID);
                        fields = getFieldsToClone(tmpCurrentComponent);
                        
                        String type;
                        
                        for (int j=0; j<fields.length; j++) {
                            try {
                                if (tmpCurrentComponent instanceof CompositeComponent) {
                                    type = fields[j].getType().getName();
                                    
                                    if (type.equals("java.lang.String")) {
                                           fields[j].set(tmpCurrentComponent,originalFields[j].get(currentComponent));
                                    }
                                    else if (type.equals("int")) {
                                           fields[j].setInt(tmpCurrentComponent,originalFields[j].getInt(currentComponent));
                                    }
                                    else if (type.equals("boolean")) {
                                           fields[j].setBoolean(tmpCurrentComponent,originalFields[j].getBoolean(currentComponent));
                                       }
                                   }
                            }
                            catch (Exception e) {
                                System.err.println("getField error");
                            }
                        }
                                        
                        tmpCurrentComponent.repaint();
                    }
                }
            }
        }
    }

    public static void synchronizeTree(String name) {
        //TMUtility.display("synchronizeTree --- name",name);
        
           /*TreeMap parentTreeMap = (TreeMap)skeleton.nodeRegister.get(name);
           
        if (parentTreeMap == null) return;
           
           Set keys = parentTreeMap.keySet();
        TreePath t;

        for (Iterator it=keys.iterator();it.hasNext();) {
            String tmpParentName = (String)(it.next());
            Node tmpParentNode = (Node)parentTreeMap.get(tmpParentName);

            for (Iterator itID = tmpParentNode.getIDIterator(name);itID.hasNext();) {
                Integer currentID = (Integer)(itID.next());
                
                //TMUtility.display("synchronizeTree --- currentID",currentID);
                
                //t contains all nodes from its parent to name
                t = fetchTreePath(name,tmpParentName,tree,currentID);
            
                //remove name from tree
                tree.removeInTree(t);
            
                //get node corresponding to name in skeleton
                Node tmpCurrentNode = skeleton.toChildNode(name,tmpParentName,currentID);
                int index = skeleton.getPositionForDuplicatedTasks(name,tmpParentName,currentID);
                
                //if (tmpCurrentNode != null) tmpCurrentNode.printNode();
            
                tree.addRecursivelyInTree(truncTreePath(t),name,tmpCurrentNode,index-1);
            }
        }*/
        
        Node currentNode = Manager.skeleton.toChildNode(name);
        Manager.tree.synchronizeTree(name,currentNode);
    }
    
    /**
     * close a frame.
     */    
    //tape_recorder
    private static void closeFrame(String name) {
        if (!Manager.guiEnableFlag) return;
        
        if (Manager.skeleton.isInTree(name)) {
            Manager.desktop.closeFrame(name);
        }
    }
    
    public static void synchronizeCoreFields(String name,String parentName,Integer id2) {
        TreeMap t = (TreeMap) Manager.skeleton.nodeRegister.get(name);
        
        if (t == null) return;
        
        //get all parent nodes of name
        Set keys = t.keySet();
        Node [] tmpParentNodes = new Node[keys.size()];
        
        int i=0;
        int index=0;
        for (Iterator it=keys.iterator();it.hasNext();i++) {
            String tmpParentName = (String) it.next();
            
            tmpParentNodes[i] = (Node) t.get(tmpParentName);
            
            if (tmpParentName.equals(parentName))
                index = i;
        }
        
        // get fields of current component to clone from
        GenericComponent currentComponent = tmpParentNodes[index].getComponent(name,id2);
        Field [] originalFields = getFieldsToClone(currentComponent);

        Field [] fields;
        TreePath treePath;
        
        for (i=0; i<tmpParentNodes.length; i++) {
            for (Iterator itCurrentID = tmpParentNodes[i].getIDIterator(name);itCurrentID.hasNext();) {
                Integer currentID = (Integer) itCurrentID.next();

                if (!currentID.equals(id2)) {
                    // clone fields of the other duplicated tasks
                    GenericComponent tmpCurrentComponent = tmpParentNodes[i].getComponent(name,currentID);
                    fields = getFieldsToClone(tmpCurrentComponent);
                    
                    String type;
                    
                    for (int j=0; j<fields.length; j++) {
                        try {
                            if (tmpCurrentComponent instanceof CompositeComponent) {
                                String fieldName = fields[j].getName();
                                //String fieldValue = fields[j].get(currentComponent).toString();
                                //System.out.println("j = "+j+" --- field : "+fieldName+", value = "+fieldValue);
                                
                                if (isCoreField(fieldName)) {
                                    type = fields[j].getType().getName();
                                    
                                    if (type.equals("java.lang.String")) {
                                           fields[j].set(tmpCurrentComponent,originalFields[j].get(currentComponent));
                                    }
                                    else if (type.equals("int")) {
                                           fields[j].setInt(tmpCurrentComponent,originalFields[j].getInt(currentComponent));
                                    }
                                    else if (type.equals("boolean")) {
                                           fields[j].setBoolean(tmpCurrentComponent,originalFields[j].getBoolean(currentComponent));
                                    }
                                }
                            }
                        }
                        catch (Exception e) {
                            System.err.println("getField error");
                        }
                    }
                                    
                    tmpCurrentComponent.repaint();
                }
            }
        }
    }
    
    /*
        possible fields : 
        
        semantics, composite, mandatory, style, minCard, maxCard
        precondition, postcondition, feedback, terminal, dirty
    */
    private static boolean isCoreField(String fieldName) {
        boolean result = false;
        
        if (fieldName.equals("semantics")) result = true;
        if (fieldName.equals("style")) result = true;
        if (fieldName.equals("composite")) result = true;
        
        return result;
    }
    
    private static Field [] getFieldsToClone(GenericComponent gc) {
        Class cl = gc.getClass();
        
        Object [] obj = gc.getCloneFields();
        
        Field [] fields = new Field[obj.length];
        
        for (int i=0; i<obj.length; i++) {
            try {
                fields[i] = cl.getField((String)obj[i]);
            }
            catch (Exception e) {
                System.err.println("getField error");
            }
        }
        
        return fields;        
    }
    
}