/*******************************************************************************
* Copyright (c)                                                                *
*           2005   Tristan Allwood,                                            *
*           2005   Daniel Burke,                                               *
*           2005   Marc Hull,                                                  *
*           2005   Ekaterina Itskova,                                          *
*           2005   Steve Zymler                                                *
*                                                                              *
* Permission is hereby granted, free of charge, to any person obtaining a      *
* copy of this software and associated documentation files (the                *
* "Software"), to deal in the Software without restriction, including          *
* without limitation the rights to use, copy, modify, merge, publish,          *
* distribute, sublicense, and/or sell copies of the Software, and to           *
* permit persons to whom the Software is furnished to do so, subject to        *
* the following conditions:                                                    *
*                                                                              *
* The above copyright notice and this permission notice shall be included      *
* in all copies or substantial portions of the Software.                       *
*                                                                              *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS      *
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF                   *
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.       *
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY         *
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,         *
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE            *
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                       *
*******************************************************************************/
/*
 * Created on 26-Oct-2004
 *
 */
package uk.ac.ic.doc.kevlar.gui.internal.pipeline;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import org.eclipse.swt.graphics.Point;

import uk.ac.ic.doc.kevlar.api.programs.arguments.IBasicArgumentInfo;
import uk.ac.ic.doc.kevlar.gui.internal.ADrawableObject;
import uk.ac.ic.doc.kevlar.gui.internal.keyboard.KeyboardManager;
import uk.ac.ic.doc.kevlar.gui.internal.keyboard.states.TextBoxState;
import uk.ac.ic.doc.kevlar.gui.internal.layout.LayoutManager;
import uk.ac.ic.doc.kevlar.gui.internal.pipeline.arguments.Argument;
import uk.ac.ic.doc.kevlar.gui.internal.popup.PopUpManager;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.IDeselectListener;
import uk.ac.ic.doc.kevlar.gui.internal.widgets.textbox.TextBox;
import uk.ac.ic.doc.kevlar.hial.IArgumentValuePair;
import uk.ac.ic.doc.kevlar.hial.IHialProgram;
import uk.ac.ic.doc.kevlar.publicInterfaces.INode;

/**
 * @author Kate
 *
 */
public class Macro extends Program implements IDeselectListener {
	
    protected List<Program> programs;
    protected TextBox editor;   
    protected String name;
    
    public Macro() {
        
        super(null);
        
        programs = new ArrayList<Program>();
        registered = true;
        name = "Macro";
        
	    editor = new TextBox();
	    editor.setSize(new Point(200, 20));
	    editor.setDeselectListener(this);        
        
    }
    
    public String getName() {
        
        return name;
        
    }

    public void addPrograms(Collection<Program> programs) {
        
        this.programs.addAll(programs);
        update();
        
    }
    
    public List getPrograms() {
        
        return programs;
        
    }
    
    public void update() {

        while (entries.size() > 0) {

            removeChild(entries.get(0));
            entries.remove(0);
            
        }
        
/*        int i=0;
        
        while (i < entries.size()) {
            
            AProgramEntry entry = entries.get(i);
            boolean found = false;
            
	        for (Program p: programs) {

		        List<AIONodeEntry> nodes = p.getNodes();
	            
	            for (AIONodeEntry node: nodes) {

//	                found = found || (!node.hasPipe() && (p.getName()+"."+node.getName()).equals(entry.getName()));
	                found = found || (!node.hasPipe() && (node.getDataNode().getName()).equals(entry.getName()));
	                
	            }
	            
	        }
            
		    if (!found) {
		        
		        entry.dispose();
		        entries.remove(entry);
		        
		    } else {
		        
		        i++;
		        
		    }
	        
        } */

        HashMap<String, Integer> programDuplicates = new HashMap<String, Integer>();
        ArrayList<String> programNames = new ArrayList<String>();
        
        for (Program p: programs) {
            
	        String programName;
	        
	        if (programDuplicates.containsKey(p.getName())) {
	            
	            int temp = programDuplicates.get(p.getName()).intValue()+1;
	            programDuplicates.put(p.getName(), new Integer(temp));
	            programName = p.getName()+"("+temp+")";
	            
	        } else {
	            
	            programName = p.getName();
	            programDuplicates.put(p.getName(), new Integer(0));
	            
	        }
	        
	        programNames.add(programName);
            
        }
        
        int i = 0;
        int positionIndex = 0;
        
	    for (Program p: programs) {

	        List<AIONodeEntry> childnodes = p.getNodes();
	        
	        for (AIONodeEntry node: childnodes) {
	        
	            if (externalNode(node) && node instanceof InputNodeEntry) {
	                
	                InputNodeEntry input = (InputNodeEntry)node;
	                    
                    AProgramEntry nodeEntry = new InputNodeEntry((INode)input.getDataNode(),positionIndex, input.getProgram());
                    nodeEntry.setContainer(this);
                    nodeEntry.setPrefix(programNames.get(i)+"."+input.getPrefix());
                    entries.add(nodeEntry);
                    nodes.add((InputNodeEntry)nodeEntry);
                    addChild(nodeEntry);
	                    	        
                    if (node.hasPipe()) {
                        
                        node.getPipe().setDestination((InputNodeEntry)nodeEntry);
                        
                    }
                    
	                positionIndex++;		        
	                
	            }
	            
	        }
	        
	        i++;
	        
	    }
	    
	    i = 0;
	    
	    for (Program p: programs) {

	        List<AIONodeEntry> childnodes = p.getNodes();
	        
	        for (AIONodeEntry node: childnodes) {
	        
	            if (externalNode(node) && node instanceof OutputNodeEntry) {
	                
	                OutputNodeEntry output = (OutputNodeEntry)node;
	                AProgramEntry nodeEntry = getEntry(p.getName()+"."+output.getName());
	                
	                if (nodeEntry != null) {
	                    
	                    nodeEntry.setIndex(positionIndex);
	                    
	                } else {
	                    
	                    nodeEntry = new OutputNodeEntry((INode)output.getDataNode(),positionIndex, output.getProgram()); 
	                    nodeEntry.setContainer(this);
	                    nodeEntry.setPrefix(programNames.get(i)+"."+output.getPrefix());
	                    nodes.add((OutputNodeEntry)nodeEntry);
	                    entries.add(nodeEntry);
	                    addChild(nodeEntry);
	                    
	                    if (node.hasPipe()) {
	                        
                            node.getPipe().setSource((OutputNodeEntry)nodeEntry);
	                        
	                    }
	                    
	                }
	                
	                positionIndex++;		        
	                
	            }
	            
	        }
	        
	        i++;
	        
	    }
	    
		bringToFront(heading);
		
		setSize(new Point(area.width, ProgramHeading.PROGRAM_HEADING_HEIGHT+entries.size()*AProgramEntry.ENTRY_INTERNAL_HEIGHT));
		LayoutManager.getLayout().forceProgramSize(this, getSize());
	    
	}
	
    public boolean externalNode(AIONodeEntry node) {
        
        if (!node.hasPipe()) {
            
            return true;
            
        } else if (node instanceof InputNodeEntry) {
            
            return (!programs.contains(node.getPipe().getSource()));
                            
        } else if (node instanceof OutputNodeEntry) {
            
            return (!programs.contains(node.getPipe().getDestination()));
            
        }
        
        return false;
        
    }
    
	public void register(IHialProgram programInfo) {
	    
	    // Not the best design practice for a subclass to
	    // be removing functionality from its superclass,
	    // but it's Xmas Eve...
		
	} 
	
	public void applyArgumentChanges() {
	    	    
	}
	
	private Argument createArgumentEntry(IArgumentValuePair pair, int pos) {
	    
	    return null;
	    	    	    
	} 
	
	public void addEntryButtonPressed(Point position) {
	    
	} 

    public void entrySelected(Object entry) {
        
    }
    
    public void addArgument(IBasicArgumentInfo info) {
                        
    } 
    
    public void removeProgram() {
        
        if (PipeLineManager.getSingleton().getSelectedProgram() == this) {
            
            PipeLineManager.getSingleton().deselectProgram();
            
        }
        
        PipeLineManager.getSingleton().deselectNode();
        
        remove();
        
        while (programs.size() > 0) {

            programs.get(0).removeProgram();
            programs.remove(0);
            
        }
        
        LayoutManager.getLayout().removeProgram(this);
        
    }

    public void renameButtonPressed() {
        
        editor.setPosition(localToAbsolute(new Point((area.width-15)/2, 0)));
	    editor.setText(name);
        PopUpManager.getSingleton().showPopUp(editor);
        
        KeyboardManager.getSingleton().setState(new TextBoxState(editor));        
        
    }

    public void onDeselect(ADrawableObject object) {

        if (object == editor) {
            
            name = editor.getText();
            PopUpManager.getSingleton().hidePopUp(editor);
            redraw();
            
        }        
        
    }
    
}
