// Copyright (c) 1995, 1996 Regents of the University of California.
// All rights reserved.
//
// This software was developed by the Arcadia project
// at the University of California, Irvine.
//
// Redistribution and use in source and binary forms are permitted
// provided that the above copyright notice and this paragraph are
// duplicated in all such forms and that any documentation,
// advertising materials, and other materials related to such
// distribution and use acknowledge that the software was developed
// by the University of California, Irvine.  The name of the
// University may not be used to endorse or promote products derived
// from this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
// IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.

// File: SelectionMultiple.java
// Classes: SelectionMultiple
// Original Author: Jason Robbins
// $Id: SelectionMultiple.java,v 1.2 2000/09/19 21:08:34 dougo Exp $

// Modified by : Kedar Patankar

package edu.neu.ccs.demeter.tools.apstudio.graphedit;

import java.util.Vector;
import java.util.Enumeration;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.Event;


/** This class handles multiple selections. It is basically a
 * collection of SelectionSingle instances. Most of its operations
 * just dispatch the same operation to each of the SelectionSingle
 * instances in turn.
 * @see SelectionSingle
 */


public class SelectionMultiple extends Selection {

  /** The collection of SelectionSingle instances */
  protected Vector _contents;

  public SelectionMultiple() {
    _contents = new Vector();
  }

  /** Add a new selection to the collection of selections */
  public void addElement(Selection s) { _contents.addElement(s); }
  public void addElement(DiagramElement de) {
    _contents.addElement(de.selectionObject());
  }
  public void addAllElements(Vector v) {
    Enumeration eles = v.elements();
    while(eles.hasMoreElements()) {
      DiagramElement de = (DiagramElement) eles.nextElement();
      addElement(de);
    }
  }
  
  /** Select some objects if they were not selected already, and
   * deslect others that were already selected. This is normally
   * called from ModeSelect when the shift key is held down.
   * @see ModeSelect
   * @see Editor
   */
  public void toggleAllElements(Vector v) {
    Enumeration eles = ((Vector)v.clone()).elements();
    while(eles.hasMoreElements()) {
      DiagramElement de = (DiagramElement) eles.nextElement();
      if (contains(de)) removeElement(de);
      else addElement(de);
    }
  }

  /** Deselect the given DiagramElement */
  public void removeElement(Selection s) { _contents.removeElement(s); }
  public void removeElement(DiagramElement de) {
    Enumeration eles = ((Vector)_contents.clone()).elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.contains(de)) removeElement(sel);
    }
  }

  /** Deselect everything */
  public void removeAllElements() { _contents.removeAllElements(); }

  /** Reply true if the given selection instance is part of my
   * collection */
  public boolean contains(Selection s) { return _contents.contains(s); }

  /** Reply true if the given DiagramElement is selected by any of my
   * selection objects */
  public boolean contains(DiagramElement de) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.contains(de)) return true;
    }
    return false;
  }

  /** Reply the number of selected DiagramElement's. This assumes that
   * this collection holds only SelectionSingle instances and each of
   * those holds one DiagramElement */
  public int size() { return _contents.size(); }

  /** Reply the collection of all selected DiagramElement's */
  public Vector deContents() {
    Vector des = new Vector(_contents.size());
    Enumeration eachSel = _contents.elements();
    while (eachSel.hasMoreElements()) {
      SelectionSingle sel = (SelectionSingle) eachSel.nextElement();
      des.addElement(sel.content());
    }
    return des;
  }

  /** Reply the collection of all selected DiagramElement's */
  public DiagramElement firstelement(){ 
	  return ((SelectionSingle)_contents.firstElement()).content();
  }
										
  /** Start a transaction that damages all selected DiagramElement's */
  public void startTrans() {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.startTrans();
    }
  }

  /** End a transaction that damages all selected DiagramElement's */
  public void endTrans() {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.endTrans();
    }
  }

  /** Draw all selection objects */
  public void draw(Graphics g) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.draw(g);
    }
  }

  /** Reply the first non-null value of the given graphical attribute */
  public Object getGraphicAttribute(String k) {
    Object obj;
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (null != (obj = sel.getGraphicAttribute(k)))
	return obj;
    }
    return null;
  }

  /** Set the given graphical attribute for all selected objects */
  public void setGraphicAttribute(String k, Object v) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.setGraphicAttribute(k, v);
    }
  }

  /** When the SelectionMultiple is damaged, that implies that each
  * SelectionSingle should be damaged. */
  public void damagedIn(Document ed) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.damagedIn(ed);
    }
  }

  /** Reply true iff the given point is inside one of the selected
   * DiagramElement's */
  boolean inside(int x, int y) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.inside(x, y)) return true;
    }
    return false;
  }

  public Rectangle getBoundingBox() {
    Rectangle r = null;
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (null == r) r = sel.getBoundingBox();
      else r.add(sel.getBoundingBox());
    }
    return r;
  }

  /** Align the selected DiagramElement's relative to each other */
  /* needs-more-work: more of this logic should be in ActionAlign */
  void align(int direction) {
    Rectangle cur_rect;
    Selection sel;
    int dx, dy;
    int size = _contents.size();

    Rectangle bbox = getBoundingBox();

    for (int i=0; i<size; i++) {
      sel = (Selection) _contents.elementAt(i);
      cur_rect = sel.getBoundingBox();
      dx = dy = 0;
      switch(direction) {
      case ActionAlign.ALIGN_TOPS:
	dy = bbox.y - cur_rect.y;
	break;
      case ActionAlign.ALIGN_BOTTOMS:
	dy = bbox.y + bbox.height - (cur_rect.y + cur_rect.height);
	break;
      case ActionAlign.ALIGN_LEFTS:
	dx = bbox.x - cur_rect.x;
	break;
      case ActionAlign.ALIGN_RIGHTS:
	dx = bbox.x + bbox.width - (cur_rect.x + cur_rect.width);
	break;
      }
      sel.translate(dx,dy);
    }
  }

  /** When multiple selections are moved, each of them is moved */
  void translate(int dx,int dy) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.translate(dx, dy);
    }
  }

  /** If only one thing is selected, then it is possible to mouse on
   * one of its handles, but if multiple things are selected, users
   * can only drag the objects around */
  /* needs-more-work: should take on more of this responsibility */
  public int pickHandle(int x, int y) {
    if (size() == 1) {
      int hp = ((Selection) _contents.firstElement()).pickHandle(x, y);
      return hp;
    }
    else {
      return -1;
    }
  }
// Original implementationof drag-handle()
  /** If only one thing is selected, then it is possible to mouse on
   * one of its handles, but if multiple things are selected, users
   * can only drag the objects around */
  public void dragHandle(int mx, int my, int an_x,int an_y, int h) {
    if (size() == 1) {
      Selection sel =  ((Selection) _contents.firstElement());
      sel.dragHandle(mx, my, an_x, an_y, h);
    }
    else {
//       do nothing 
    }
  }

  /** If only one thing is selected, then it is possible to mouse on
   * one of its handles, but if multiple things are selected, users
   * can only drag the objects around */
/*  public void dragHandle(int mx, int my,int h) {
    if (size() == 1) {
      Selection sel =  ((Selection) _contents.firstElement());
      sel.dragHandle(mx, my, h);
    }
    else {
      /* do nothing */
/*    }
  }
*/  
  /** When a multiple selection is removed, each selection is removed */
  public void removeFrom(Document ed) {
    Enumeration eles = ((Vector)_contents.clone()).elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.removeFrom(ed);
    }
  }

  /** When a multiple selection is disposed, each selection is disposed */
  public void dispose(Document ed) {
    Enumeration eles = ((Vector)_contents.clone()).elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      sel.dispose(ed);
    }
  }

  /** When an event is passed to a multiple selection, try to pass it
   * off to the first selection that will handle it. */
  /* needs-more-work: maybe it should pass it to _all_ selections that
     will handle it */
  public boolean keyDown(Event e,int key) {
    Enumeration eles = ((Vector)_contents.clone()).elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.keyDown(e, key)) return true;
    }
    return false;
  }

  public boolean mouseMove(Event e,int x,int y) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.mouseMove(e, x, y)) return true;
    }
    return false;
  }


  public boolean mouseDrag(Event e,int x,int y) {
    Enumeration eles = _contents.elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.mouseDrag(e, x, y)) return true;
    }
    return false;
  }


  public boolean mouseDown(Event e,int x,int y) {
    Enumeration eles = ((Vector)_contents.clone()).elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.mouseDown(e, x, y)) return true;
    }
    return false;
  }


  public boolean mouseUp(Event e,int x,int y) {
    Enumeration eles = ((Vector)_contents.clone()).elements();
    while(eles.hasMoreElements()) {
      Selection sel = (Selection) eles.nextElement();
      if (sel.mouseUp(e, x, y)) return true;
    }
    return false;
  }
} /* end class SelectionMultiple */

