package icsDyn;
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JOptionPane;
import javax.swing.ListCellRenderer;
import javax.swing.ListModel;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 * This class allows the user removing and adding behaviors to an object
 * @author  Rick Rivello
 */
public class AddRemoveBehavior extends JPanel implements ActionListener, Observer{

  private static final long serialVersionUID = 1L;
  private static final Insets EMPTY_INSETS = new Insets(0, 0, 0, 0);
  private static final String ADD_BUTTON_LABEL = "Add >>";
  private static final String REMOVE_BUTTON_LABEL = "<< Remove";
  private static final String DEFAULT_SOURCE_CHOICE_LABEL = "Available Behavior Methods";
  private static final String DEFAULT_DEST_CHOICE_LABEL = "Behavior Methods Selected";
  private JLabel sourceLabel;
  private JList sourceList;
  private SortedListModel sourceListModel;
  private JList destList;
  private SortedListModel destListModel;
  private JLabel destLabel;
  private JButton addButton;
  private JButton removeButton;
  private JButton btnClose;
  private JButton btnAddChanges;
  private JButton btnAddPrivate;
  private JFrame f;
  
  private ICSModel icsModel;
  private Vector<BehaviourNode> vectPrivate;
  private Component parent;
  Vector dynbehav;
  Vector defbehav;
  MOCNode tempmoc;
  MOCNode defmocnode;
  MOCNode dynmocnode;
  DefaultMutableTreeNode cNode;

  String[] selectedDyn;

  public AddRemoveBehavior(Component p) {
	  parent = p;
	  vectPrivate = new Vector<BehaviourNode>();
    init();
  }

  public void setICSModel (ICSModel model) {
    icsModel = model;
    icsModel.addObserver(this);
  }

  public void mn(AddRemoveBehavior behaviors, Vector dynvmoc, Vector defvmoc,DefaultMutableTreeNode currentNode) {

    f = new JFrame("Behavior List ");
    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    f.setLocationRelativeTo(parent);

    cNode = currentNode;

    MOCNode tempmoc = icsModel.getMOCNode();

    dynbehav = null;
    defbehav = null;

    int index = defvmoc.indexOf(tempmoc);
    if (index != -1) {
       defmocnode = (MOCNode) defvmoc.get(index);
       defbehav = defmocnode.getBehaviour(); 
	    for (int i = 0; i < defbehav.size(); i++) {
	       behaviors.addSourceElements(new String[] {((DIMMOC) defbehav.get(i)).getMethodName()});
	    } 
    }

    int mocIdNumber = tempmoc.getMocIdNumber();    
    index = dynvmoc.indexOf(tempmoc);
    MOCNode dynmocnode = (MOCNode) dynvmoc.get(index);
    int tempmocIdNumber = dynmocnode.getMocIdNumber();

    while (tempmocIdNumber != mocIdNumber) {
       index = dynvmoc.indexOf(tempmoc,index+1);
       dynmocnode = (MOCNode) dynvmoc.get(index);
       tempmocIdNumber = dynmocnode.getMocIdNumber();
    }   
    dynbehav = dynmocnode.getBehaviour();
 
    selectedDyn = new String[dynbehav.size()];
    for (int i = 0; i < dynbehav.size(); i++) {
       behaviors.addDestinationElements(new String[] {((DIMMOC) dynbehav.get(i)).getMethodName()});
       if(((DIMMOC) dynbehav.get(i)).isPrivate)
    	   ((MyListRenderer)destList.getCellRenderer()).addPrivate(((DIMMOC) dynbehav.get(i)).method_name);
    	   
       selectedDyn[i] = ((DIMMOC) dynbehav.get(i)).getMethodName();
       sourceListModel.removeElement(selectedDyn[i]);    
    }

    sourceList.getSelectionModel().clearSelection();

    f.getContentPane().add(behaviors, BorderLayout.CENTER);
    f.setSize(400, 300);
    f.setVisible(true);
}

  public String getSourceChoicesTitle() {
    return sourceLabel.getText();
  }

  public void setSourceChoicesTitle(String newValue) {
    sourceLabel.setText(newValue);
  }

  public String getDestinationChoicesTitle() {
    return destLabel.getText();
  }

  public void setDestinationChoicesTitle(String newValue) {
    destLabel.setText(newValue);
  }

  public void clearSourceListModel() {
    sourceListModel.clear();
  }

  public void clearDestinationListModel() {
    destListModel.clear();
  }

  public void addSourceElements(ListModel newValue) {
    fillListModel(sourceListModel, newValue);
  }

  public void setSourceElements(ListModel newValue) {
    clearSourceListModel();
    addSourceElements(newValue);
  }

  public void addDestinationElements(ListModel newValue) {
    fillListModel(destListModel, newValue);
  }

  private void fillListModel(SortedListModel model, ListModel newValues) {
    int size = newValues.getSize();
    for (int i = 0; i < size; i++) {
      model.add(newValues.getElementAt(i));
    }
  }

  public void addSourceElements(Object newValue[]) {
    fillListModel(sourceListModel, newValue);
  }

  public void setSourceElements(Object newValue[]) {
    clearSourceListModel();
    addSourceElements(newValue);
  }

  public void addDestinationElements(Object newValue[]) {
    fillListModel(destListModel, newValue);
  }

  private void fillListModel(SortedListModel model, Object newValues[]) {  
    model.addAll(newValues);
  }

  public Iterator sourceIterator() {
    return sourceListModel.iterator();
  }

  public Iterator destinationIterator() {
    return destListModel.iterator();
  }

  public void setSourceCellRenderer(ListCellRenderer newValue) {
    sourceList.setCellRenderer(newValue);
  }

  public ListCellRenderer getSourceCellRenderer() {
    return sourceList.getCellRenderer();
  }

  public void setDestinationCellRenderer(ListCellRenderer newValue) {
    destList.setCellRenderer(newValue);
  }

  public ListCellRenderer getDestinationCellRenderer() {
    return destList.getCellRenderer();
  }

  public void setVisibleRowCount(int newValue) {
    sourceList.setVisibleRowCount(newValue);
    destList.setVisibleRowCount(newValue);
  }

  public int getVisibleRowCount() {
    return sourceList.getVisibleRowCount();
  }

  public void setSelectionBackground(Color newValue) {
    sourceList.setSelectionBackground(newValue);
    destList.setSelectionBackground(newValue);
  }

  public Color getSelectionBackground() {
    return sourceList.getSelectionBackground();
  }

  public void setSelectionForeground(Color newValue) {
    sourceList.setSelectionForeground(newValue);
    destList.setSelectionForeground(newValue);
  }

  public Color getSelectionForeground() {
    return sourceList.getSelectionForeground();
  }

  private void clearSourceSelected() {
    Object selected[] = sourceList.getSelectedValues();
    for (int i = selected.length - 1; i >= 0; --i) {
      sourceListModel.removeElement(selected[i]);
    }
    sourceList.getSelectionModel().clearSelection();
  }

  private void clearDestinationSelected() {
    Object selected[] = destList.getSelectedValues();
    for (int i = selected.length - 1; i >= 0; --i) {
      destListModel.removeElement(selected[i]);
    }
    destList.getSelectionModel().clearSelection();
  }

  private void init() {

    setLayout(new GridBagLayout());
    
    JPanel p0 = new JPanel();
   
    MyListRenderer listRenderer = new MyListRenderer();
    
    p0.setLayout(new GridBagLayout());
    sourceLabel = new JLabel(DEFAULT_SOURCE_CHOICE_LABEL);
    sourceListModel = new SortedListModel();
    sourceList = new JList(sourceListModel);
    sourceList.setCellRenderer(listRenderer);
    p0.add(sourceLabel, new GridBagConstraints(0, 0, 1, 1, 0, 0,
        GridBagConstraints.CENTER, GridBagConstraints.NONE,
        EMPTY_INSETS, 0, 0));
    p0.add(new JScrollPane(sourceList), new GridBagConstraints(0, 1, 1, 5, .5,
        1, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
        EMPTY_INSETS, 0, 0));

    addButton = new JButton(ADD_BUTTON_LABEL);
    p0.add(addButton, new GridBagConstraints(1, 2, 1, 2, 0, .25,
        GridBagConstraints.CENTER, GridBagConstraints.NONE,
        EMPTY_INSETS, 0, 0));
    addButton.addActionListener(this);
    removeButton = new JButton(REMOVE_BUTTON_LABEL);
    p0.add(removeButton, new GridBagConstraints(1, 4, 1, 2, 0, .25,
        GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(
            0, 5, 0, 5), 0, 0));
    removeButton.addActionListener(this);

    destLabel = new JLabel(DEFAULT_DEST_CHOICE_LABEL);
    destListModel = new SortedListModel();
    destList = new JList(destListModel);
      
    destList.setCellRenderer(listRenderer);
    
    p0.add(destLabel, new GridBagConstraints(2, 0, 1, 1, 0, 0,
        GridBagConstraints.CENTER, GridBagConstraints.NONE,
        EMPTY_INSETS, 0, 0));
    p0.add(new JScrollPane(destList), new GridBagConstraints(2, 1, 1, 5, .5,
        1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
        EMPTY_INSETS, 0, 0));
    
    add(p0, new GridBagConstraints(0,0,GridBagConstraints.REMAINDER, 1,
    		0,1,GridBagConstraints.NORTHEAST, GridBagConstraints.BOTH, new Insets(5,5,5,5),0,0));
    
    JPanel p1 = new JPanel();
    p1.setLayout(new GridBagLayout());
    btnAddChanges = new JButton("Add changes");
    btnClose = new JButton("Close");
    btnAddPrivate = new JButton("<html>Add Private Behavior...</html>");
    btnAddPrivate.setForeground(Color.red);
    btnAddChanges.addActionListener(this);
    btnAddPrivate.addActionListener(this);
    btnClose.addActionListener(this);
    btnAddChanges.setBackground(new Color(204, 204, 255));
    btnAddPrivate.setBackground(new Color(204, 204, 255));
    btnClose.setBackground(new Color(204, 204, 255));
    btnAddPrivate.setPreferredSize(new Dimension(110, 40));
    p1.add(btnAddChanges, new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.WEST,
    		GridBagConstraints.NONE, new Insets(5,5,5,5),0,0));
    p1.add(btnClose, new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.EAST,
    		GridBagConstraints.NONE, new Insets(5,5,5,5),0,0));
    p1.add(btnAddPrivate, new GridBagConstraints(0,0,1,1,1,1,GridBagConstraints.CENTER,
    		GridBagConstraints.NONE, new Insets(5,5,5,5),0,0));
    p1.setBorder(BorderFactory.createEtchedBorder());
    add(p1, new GridBagConstraints(GridBagConstraints.RELATIVE,GridBagConstraints.RELATIVE,1,1,1,0,GridBagConstraints.NORTHWEST,
    		GridBagConstraints.BOTH, new Insets(5,5,5,5),0,0)); 

   }
 
  public void processUpdate() {

     String dynstring;
     String selectedString;

     int compareint;

     int dynlen = dynbehav.size();

     String[] behavSelected = new String[destListModel.getSize() - vectPrivate.size()];
  
     int k = 0;
     for (int i = 0; i < destListModel.getSize(); i++) {
    	 boolean isPrivate = false;
        
        for(int j = 0; j < vectPrivate.size(); j++)
        {
        	BehaviourNode b = (BehaviourNode)vectPrivate.get(j);
        	if(b.method_name.equals((String) destListModel.getElementAt(i)))
        	{
        		isPrivate = true;
        		j = vectPrivate.size();
        	}
        }
        if(!isPrivate && k < behavSelected.length){
        	behavSelected[k] = (String) destListModel.getElementAt(i);
        	k++;
        }
     }

     int selectedlen = behavSelected.length;
    
     int dyncnt = 0;
     int selectedcnt = 0;

     String[] dynbehavArray = new String[dynbehav.size()];
     
     for (int i = 0;i < dynbehav.size();i++) {
         dynbehavArray[i] = dynbehav.get(i).toString();
     }
     Arrays.sort(dynbehavArray);
     Arrays.sort(behavSelected);

     MOCNode mocNode = icsModel.getMOCNode();

     int mocIdNumber = mocNode.getMocIdNumber();
     int inx = icsModel.getcurVMoc().indexOf(mocNode);    		     
     MOCNode vmocNode = (MOCNode)icsModel.getcurVMoc().get(inx);
     int tempmocIdNumber = vmocNode.getMocIdNumber();

     while (tempmocIdNumber != mocIdNumber) {
        inx = icsModel.getcurVMoc().indexOf(mocNode,inx+1);
        vmocNode = (MOCNode)icsModel.getcurVMoc().get(inx);
        tempmocIdNumber = vmocNode.getMocIdNumber();
     }    
    
     while (dyncnt < dynlen && selectedcnt < selectedlen) {

        dynstring = dynbehavArray[dyncnt];
        selectedString = behavSelected[selectedcnt];
        compareint = dynstring.compareTo(selectedString);

        if (compareint < 0) {
           dyncnt = dyncnt + 1;             
           deleteVector(vmocNode,dynstring);
        }
        else if (compareint > 0) {
           // add vector
           addVector(vmocNode,selectedString);
           selectedcnt = selectedcnt +1;      
        }
        else {
           dyncnt = dyncnt + 1;
           selectedcnt = selectedcnt + 1;
        }
     }
     if (dyncnt < dynlen) {
        for (int i = dyncnt; i < dynlen; i++) {
           dynstring = dynbehavArray[dyncnt];
           deleteVector(vmocNode,dynstring);
        }
     }
     else if (selectedcnt < selectedlen) {
        for (int i = selectedcnt; i < selectedlen; i++) {
           selectedString = behavSelected[selectedcnt];
           addVector(vmocNode,selectedString);
           selectedcnt = selectedcnt + 1;
        }
     }
     for(int i = 0; i < vectPrivate.size(); i++){
    	 BehaviourNode b = (BehaviourNode)vectPrivate.get(i);
    	 vmocNode.addBehaviour(b);
     }
     icsModel.fireEvent(new MVCArg("node",vmocNode));
  }

  public void addVector(MOCNode mnode, String vecToBeAdded) {

     Vector vmocDef = icsModel.getVMoc();
     
     MOCNode tempmoc = icsModel.getMOCNode();

     int index = vmocDef.indexOf(tempmoc);

     MOCNode mocNode = (MOCNode) vmocDef.get(index);
     Vector mocBehav = mocNode.getBehaviour();


     int DeleteFlag = 0;
   
     while (DeleteFlag == 0  && mocBehav.size() != 0) {      
        for (int i = 0; i < mocBehav.size(); i++) {
           if (vecToBeAdded.equals(((DIMMOC) mocBehav.get(i)).getMethodName())) {
              BehaviourNode newBehav = new BehaviourNode();
              newBehav.setMethodName(((BehaviourNode) mocBehav.get(i)).getMethodName());
              newBehav.setMethodId(((BehaviourNode) mocBehav.get(i)).getMethodId());
              newBehav.setBehaviourActionParameter(((BehaviourNode) mocBehav.get(i)).getBehaviourActionParameter());
              newBehav.setBehaviourActionResult(((BehaviourNode) mocBehav.get(i)).getBehaviourActionResult());
              newBehav.setBehaviourTermCode(((BehaviourNode) mocBehav.get(i)).getBehaviourTermCode());
              newBehav.setBehaviourReference(((BehaviourNode) mocBehav.get(i)).getBehaviourReference());
              newBehav.setBehaviourQual(((BehaviourNode) mocBehav.get(i)).getBehaviourQual());
              newBehav.setBehaviourRestrictions(((BehaviourNode) mocBehav.get(i)).getBehaviourRestrictions());
              newBehav.setBehaviourComment(((BehaviourNode) mocBehav.get(i)).getBehaviourComment());              
              mnode.addBehaviour(newBehav);
              DeleteFlag = 1;
           } 
        }
     }
  }

  public void deleteVector(MOCNode mnode, String vecToBeDeleted) {

     Vector vNode;
     vNode = mnode.getBehaviour();

     int DeleteFlag = 0;
   
     while (DeleteFlag == 0  && vNode.size() != 0) {      
        for (int i = 0; i < vNode.size(); i++) {
           if (vecToBeDeleted.equals(((DIMMOC) vNode.get(i)).getMethodName())) {
              vNode.remove(i);
              DeleteFlag = 1;
           } 
        }
     }
  }

  public void actionPerformed(ActionEvent arg0) {
     if(arg0.getSource() == btnAddChanges) {
        // save changes
        processUpdate();
        f.dispose();
     }
     else if(arg0.getSource() == btnClose) {
	// exit
        f.dispose();
        icsModel = null;
     }
     else if(arg0.getSource() == removeButton)
     {
    	 Object selected[] = destList.getSelectedValues();
         int [] indices = destList.getSelectedIndices();
         int indices_cnt = 0;
         int Vector_Match_Flag = 0;
         String behaviorNames = null;
         int numOfBehaviors = 0;
         Vector vbehv = defbehav;
         for (int i = 0; i < selected.length; i++) { 
        	//we look for private attributes to delete
          	for(int p = 0; p < vectPrivate.size(); p++){
          		if(selected[i].toString().equals(((DIMMOC) vectPrivate.get(p)).getMethodName())){
          			vectPrivate.remove(p);
          			p = vectPrivate.size();
          		}
          	}
            int Select_Match_Flag = 0;   
            if(vbehv != null){
	            for (int x = 0; x < vbehv.size(); x++) {
	               if (selected[i].toString().equals(((DIMMOC) vbehv.get(x)).getMethodName())) {
	                  destList.removeSelectionInterval(indices[indices_cnt],indices[indices_cnt]);
	                  indices_cnt = indices_cnt + 1;
	                  if (Vector_Match_Flag == 0) {
	                     behaviorNames = selected[i].toString();
	                     numOfBehaviors = numOfBehaviors + 1;
	                  }
	                  else {
	                     behaviorNames = behaviorNames+", "+selected[i].toString();
	                     numOfBehaviors = numOfBehaviors + 1;
	                  }
	                  Vector_Match_Flag = 1;
	                  Select_Match_Flag = 1;
	               }
	            }
	            if (Select_Match_Flag == 0) {
	               indices_cnt = indices_cnt + 1;
	            }
	         }   
         }
         if (Vector_Match_Flag != 0) {
           selected = destList.getSelectedValues();
           String msg = null;
           if (numOfBehaviors == 1 ) {
              msg = "The Behavior "+behaviorNames+" CANNOT BE REMOVED because it is a DEFAULT BEHAVIOR";
           }
           else {
              msg = "The Behaviors "+behaviorNames+" CANNOT BE REMOVED because they are DEFAULT BEHAVIORS";
           }
           String title = "BEHAVIOR WARNING MESSAGE";
           JOptionPane.showConfirmDialog(this, msg, title,JOptionPane.DEFAULT_OPTION,JOptionPane.WARNING_MESSAGE);
         } 
         selected = destList.getSelectedValues();
         addSourceElements(selected);
         clearDestinationSelected();
     }
     else if(arg0.getSource() == addButton)
     {
    	 Object selected[] = sourceList.getSelectedValues();
         addDestinationElements(selected);
         clearSourceSelected();
     }
     else if(arg0.getSource() == btnAddPrivate)
     {
    	 JFrame f = new JFrame("Add private behavior");
    	 
    	 
    	 String[] labels = new String[3];
    	 labels[0] = "Behavior ID:";
    	 labels[1] = "Behavior Name:";
    	 labels[2] = "Term Code:";
    	 AddPrivateDialog dialog = new AddPrivateDialog(this, f,labels, AddPrivateDialog.privateBehav);
    	 dialog.setLocationRelativeTo(this);
    	 dialog.pack();
    	 dialog.setICSModel(icsModel);
    
    	 dialog.setVisible(true);
     }
  }

public void update(Observable o, Object arg) {
	if(o instanceof ICSModel) {
		if(("private/"+AddPrivateDialog.privateBehav).equals(((MVCArg)arg).getName()) && icsModel != null) {
			String[] result = (String[]) ((MVCArg)arg).getOValue();
			BehaviourNode p = new BehaviourNode();
			p.method_id = result[1];
			p.method_name = result[0];
			p.behav_termcode = result[2];
			p.isPrivate = true;
			vectPrivate.add(p);
			destListModel.add(p.method_name);
			MyListRenderer renderer = (MyListRenderer) destList.getCellRenderer();
			renderer.addPrivate(p.method_name);
		}	
}
	
}
}
