package mapper;

import java.awt.*;               // PopupMenu, MenuShortcut, etc.
import java.awt.event.*;         // New event model.
import java.util.*;

import ec.*;
import misc.*;

public class MapperPanel extends ElementContainer implements MouseListener, MouseMotionListener
{
   protected short last_x, last_y;                // Coordinates of last click.
   private final int MAXWIDTH = 1024, MAXHEIGHT = 760;
   protected int width, height;                   // The preferred size.
   private Image[] images;
   private Dimension[] imageSizes;
   private Point[] locations;

   private Graphics offg = null;
   private Image offImage = null;

   private Image bgImage = null;
   private Color bgColor = new Color(175,200,240);
   private Vector layers = new Vector();

   private boolean gridLines = true;
   private float gridUnit = 1;
   private Color GRIDCOLOR = Color.black;

   private Hashtable elementLocs = new Hashtable();
   private Hashtable scalables = new Hashtable();

   protected ProtoElement pick;
   protected int MAXPICKDIST = 20*20;
   private Vector linkListeners = new Vector();
   int n;

   private float minLat = -90, minLon = -180, maxLat = 90, maxLon = 180;
   private int ppd = 1;  // Pixels per Degree
   private int xOffset = 0, yOffset = 0;
   
   private float centerLat, centerLon;

   private Scale scale;
   private int scaleLocX = 50, scaleLocY = 50;
   
   MouseAdapter recenterer;
   

   public MapperPanel(float centerLatitude, float centerLongitude, int pixelsPerDegree)
   {
      super();
      setDoubleBuffered(false);
      setOpaque(true);
      this.setBackground(Color.lightGray);
      this.setForeground(Color.lightGray);
      setLayout(null);

      this.enableEvents(AWTEvent.MOUSE_EVENT_MASK);
      this.enableEvents(AWTEvent.MOUSE_MOTION_EVENT_MASK);
      this.enableEvents(AWTEvent.KEY_EVENT_MASK);
      
      addMouseListener(this);
      addMouseMotionListener(this);
      
      centerLat = centerLatitude;   centerLon = centerLongitude;
      ppd = pixelsPerDegree;
   }

   public void paint(Graphics g)
   {
      // See if we've been resized. 
      // If so, adjust() and thereby null out offImage:
      Rectangle r = getBounds();
      try { if((r.width != width) || (r.height != height))  adjust(); }
      catch(NullPointerException npe) { adjust(); }
      
      //try { offg = offImage.getGraphics(); }
      //catch(NullPointerException e)
      //{
      //   offImage = createImage(width, height);
      //   offg = offImage.getGraphics();
      //}

      //try { offg.drawImage(bgImage, 0, 0, null); }
      //catch(NullPointerException e) { offg.clearRect(0, 0, width, height); }

      //paintComponents(offg);
      //super.paint(offg);
      //g.drawImage(offImage, 0, 0, null);
      g.drawImage(bgImage, 0, 0, null);   
      super.paint(g);
   
      paintComponents(g);
   }
/*
   public void update(Graphics g)
   {
      paint(g);
   }
*/
   public void setZoom(int pixelsPerDegree)
   {
      ppd = pixelsPerDegree;
      adjust();
   }
   
   public final int getZoom()
   {
      return ppd;
   }
   
   public void setCenter(float cLat, float cLon)
   {
      centerLat = cLat;   centerLon = cLon;
      adjust();
   }
   
   public void translateCenter(float deltaLat, float deltaLon)
   {
      centerLat += deltaLat;  centerLon += deltaLon;
      adjust();
   }
   
  /* public void translateCenter(int deltaX, int deltaY)
   {
      centerLat += deltaY / ppd;   centerLon = deltaX / ppd;
      adjust();
   }*/
   
   public void setZoomAndCenter(int pixelsPerDegree, float cLat, float cLon)
   {
      ppd = pixelsPerDegree;
      centerLat = cLat;   centerLon = cLon;
      adjust();
   }
   
   public void zoomIn(int multiplier)
   {
      if(ppd*multiplier > 0)
      {
         ppd = ppd*multiplier;
         adjust();
      }
   }
   
   public void zoomOut(int divisor)
   {
      if(ppd/divisor > 0)
      {
         ppd = ppd/divisor;
         adjust();
      }
   }
   
   void zoomToBox(int initialX, int initialY, int width, int height)
   {
      float[] upper = xy2LatLon(initialX, initialY);
      float[] lower = xy2LatLon(initialX + width, initialY + height);
      // lower[0]=minLat;  upper[1]=minLon;  upper[0]=maxLat;  lower[1]=maxLon
      float cLattemp = lower[0] + (upper[0] - lower[0])/2;
      float cLontemp = upper[1] + (lower[1] - upper[1])/2;
      int ppdtemp;
      if((width/height) > (this.width/this.height))  // if box is 'wider' than panel
      {
         ppdtemp = (int) (this.width/(lower[1] - upper[1]));
      }
      else  // box is taller than panel (or same aspect ratio)
      {
         ppdtemp = (int) (this.height/(upper[0] - lower[0]));
      }
      setZoomAndCenter(ppdtemp, cLattemp, cLontemp);
   }
   
   public float[] getCenter()
   {
      float[] c = new float[2];
      c[0] = centerLat;  c[1] = centerLon;
      return c;
   }
   
   public int getZoomLevel()
   {
      return ppd;
   }
   
   public void recentering(boolean active)
   {
      if(active)
      {
         Graphics bgg = bgImage.getGraphics();
         int centerX = width>>1;  int centerY = height>>1;
         bgg.setColor(Color.red);
         bgg.drawLine(centerX, centerY-15, centerX, centerY+15);
         bgg.drawLine(centerX-15, centerY, centerX+15, centerY);
         repaint();
         recenterer = new MouseAdapter() {
            public void mouseReleased(MouseEvent e)
            {
               float[] coords = xy2LatLon(e.getX(), e.getY());
               setCenter(coords[0], coords[1]);
               removeMouseListener(this);
            }
         };
         addMouseListener(recenterer);
      }
      else
      {
         removeMouseListener(recenterer);
         createBackground();
         repaint();
      }
   }

   private void adjust()
   {
      Rectangle r = getBounds();
      width = r.width;
      height = r.height;
      float ppd2 = (float)2*ppd;
      float halfLonWidth = (float) width/ppd2;
      minLon = centerLon - halfLonWidth;
      maxLon = centerLon + halfLonWidth;
      float halfLatHeight = (float) height/ppd2;
      minLat = centerLat - halfLatHeight;
      maxLat = centerLat + halfLatHeight;
      xOffset = (int)((minLon +180.0) * ppd);
      yOffset = (int)(((-1*maxLat) + 90.0) * ppd);
      setLocations();
      adjustScalableSubElements();
      createBackground();
      offImage = null;
      setSize(width, height);
      if(scale!=null) showScale();
      repaint();
   }
   
   public void showScale()
   {
      if(!isShowing()) return;
      try { remove(scale); }  catch(Exception e) { } // no problem
      scale = new Scale(ppd, centerLat);
      //scale.addNotify();
      java.awt.peer.ComponentPeer cp = scale.getPeer();
      add(scale);
      scale.setLocation(scaleLocX, scaleLocY);
      scale.addMouseListener(this);
      scale.addMouseMotionListener(this);
      repaint();
   }
   
   public void toggleScale()
   {
      if(scale != null)
      {
         remove(scale);
         scale = null;
         repaint();
      }
      else
      {
         showScale();
      }
   }

   private int[][][] double2IntArrays(double[][][] coords)
   {
      int[][][] facePixels = new int[coords.length][][];
      for(int i = 0; i < coords.length; i++)
      {
        facePixels[i] = new int[2][];
        facePixels[i][0] = new int[coords[i].length];
        facePixels[i][1] = new int[coords[i].length];
        for(int j = 0; j < coords[i].length; j++)
        {
           facePixels[i][0][j] = (int)((coords[i][j][0] + 180.0) * ppd) - xOffset;
           facePixels[i][1][j] = (int)(((coords[i][j][1] * -1) + 90.0) * ppd) - yOffset;
        }
      }
      return facePixels;
   }

   private int[][][] float2IntArrays(float[][][] coords)
   {
      int[][][] facePixels = new int[coords.length][][];
      for(int i = 0; i < coords.length; i++)
      {
        facePixels[i] = new int[2][];
        facePixels[i][0] = new int[coords[i].length];
        facePixels[i][1] = new int[coords[i].length];
        for(int j = 0; j < coords[i].length; j++)
        {
           facePixels[i][0][j] = (int)((coords[i][j][0] + 180) * ppd) - xOffset;
           facePixels[i][1][j] = (int)(((coords[i][j][1] * -1) + 90) * ppd) - yOffset;
        }
      }
      return facePixels;
   }

   private int[][] toAWTCoords2(float[][] coords)
   {
      int total = coords.length;
      int[][] awtCoords = new int[2][];
      awtCoords[0] = new int[total];
      awtCoords[1] = new int[total];
      for(int i = 0; i < total; i++)
      {
         awtCoords[0][i] = (int)((coords[i][1] + 180) * ppd) - xOffset;
         awtCoords[1][i] = (int)(((coords[i][0] * -1) + 90) * ppd) - yOffset;
      }
      return awtCoords;
   }

   private int[][] toAWTCoords(float[][] coords)
   {
      int total = coords.length;
      int[][] awtCoords = new int[2][];
      awtCoords[0] = new int[total];
      awtCoords[1] = new int[total];
      for(int i = 0; i < total; i++)
      {
         awtCoords[0][i] = (int)((coords[i][0] + 180) * ppd) - xOffset;
         awtCoords[1][i] = (int)(((coords[i][1] * -1) + 90) * ppd) - yOffset;
      }
      return awtCoords;
   }
   
   /**
    * Returns level at which Layer l was inserted.
    */
   public int addLayer(Layer l)
   {
      layers.addElement(l);
      createBackground();
      repaint();
      return layers.indexOf(l);
   }
   
   public void insertLayer(Layer l, int index)
   {
      if(layers.size() <= index) layers.setSize(index + 1);
      layers.insertElementAt(l, index);
      createBackground();
      repaint();
   }
   
   public void setLayerAt(Layer l, int index)
   {
      if(layers.size() <= index) layers.setSize(index + 1);
      layers.setElementAt(l, index);
      createBackground();
      repaint();
   }
   
   public void removeLayerAt(int index)
   {
      layers.removeElementAt(index);
      createBackground();
      repaint();
   }
   
   public void removeLayer(Layer l)
   {
      layers.removeElement(l);
      createBackground();
      repaint();
   }

   private void createBackground()
   {
     if(!isShowing()) return;
     bgImage = createImage(width, height);
     Graphics bgg = bgImage.getGraphics();
     for(int l = 0; l < layers.size(); l++)
     {
        Layer layer = (Layer)layers.elementAt(l);
        if(layer == null) continue;
        bgg.setColor(bgColor);
        bgg.fillRect(0, 0, width, height);
        float[][][] faces = layer.getFaceArray();
        Color[] faceColors = layer.getFaceColorArray();
        for(int i = 0; i < faces.length; i++)
        {
           int[][] facePixels = toAWTCoords(faces[i]);
           Color c = faceColors[i];
           bgg.setColor(c);
           bgg.fillPolygon(facePixels[0], facePixels[1], facePixels[0].length);
        }
        float[][][][] linesets = layer.getLinesetArray();
        Color[] linesetColors = layer.getLinesetColorArray();
        for(int i = 0; i < linesets.length; i++)
        {
           bgg.setColor(linesetColors[i]);
           for(int j = 0; j < linesets[i].length; j++)
           {
              int[][] linePixels = toAWTCoords(linesets[i][j]);
              bgg.drawPolyline(linePixels[0], linePixels[1], linePixels[0].length);
           }
        }
        float[][][] pointsets = layer.getPointsetArray();
        Image[] ptIcons = layer.getPointsetIconArray();
        for(int i = 0; i < pointsets.length; i++)
        {
           int[][] pixels = toAWTCoords(pointsets[i]);
           for(int j = 0; j < pointsets[i].length; j++)
           {
              bgg.drawImage(ptIcons[i], pixels[0][j], pixels[1][j], null);
           }
        }
     }
     if(gridLines)
     {
        Font theFont = getFont();
        FontMetrics metrics = getFontMetrics(theFont);
        int ascent = metrics.getAscent() + 2;
        bgg.setColor(GRIDCOLOR);
        float increment;
        if(ppd > 850) increment = (float)0.1;
        else if(ppd > 200) increment = (float)0.5;
        else if(ppd > 50) increment = 1;
        else if(ppd > 20) increment = 5;
        else increment = 10;
        int lon0 = (int)minLon;
        lon0 -= lon0%increment;
        int lon1 = (int)maxLon + 1;
        for(float i = lon0; i <= lon1; i+=increment)
        {
           int[] awts = LatLon2xy(0, i);
           bgg.drawLine(awts[0], 0, awts[0], height);
           bgg.drawString(Float.toString(i), awts[0], ascent);
        }
        int lat0 = (int)minLat;
        lat0 -= lat0%increment;
        int lat1 = (int)maxLat + 1;
        for(float i = lat0; i <= lat1; i+=increment)
        {
           int[] awts = LatLon2xy(i, 0);
           bgg.drawLine(0, awts[1], width, awts[1]);
           bgg.drawString(Float.toString(i), 2, awts[1]);
        }
     }
     //showScale();
   }
   
   /**
    * Returns float array containing latitude (index=0) and longitude (index=1)
    */
   public float[] xy2LatLon(int x, int y)
   {
      float[] result = new float[2];
      int noOffset = y + yOffset;
      float descaled = (float)noOffset / (float)ppd;
      float hipassed = descaled - 90;
      float flipped = hipassed * -1;
      result[0] = flipped;
      noOffset = x + xOffset;
      descaled = (float)noOffset / (float)ppd;
      hipassed = descaled - 180;
      result[1] = hipassed;
      return result;
   }

   public int[] LatLon2xy(float lat, float lon)
   {
      int[] result = new int[2];
      result[0] = (int)((lon + 180) * ppd) - xOffset;
      result[1] = (int)(((lat * -1) + 90) * ppd) - yOffset;
      return result;
   }
   


 // Implement MouseListener:
   public void mouseClicked(MouseEvent e){}
   public void mouseEntered(MouseEvent e)
   {
   }
   
   public void mouseExited(MouseEvent e){}
   
   public void mousePressed(MouseEvent e)
   {
      lastPressedEvent = e;
   }
   
   public void mouseReleased(MouseEvent e)
   {
      //if(e.getComponent() == rbo)  { remove(rbo); }
      if(e.getComponent() == scale) { e.consume();  return; }
      float[] newPosition = xy2LatLon(e.getX(), e.getY());
      if (getSelectedElement() != null) {
         ECEvent ece = new ECEvent(ECEvent.ELEMENT_MOVED, getSelectedElement(), newPosition[0], newPosition[1]);
         processECEvent(ece);
      }
   }

   public void mouseMoved(MouseEvent e){}
   
   public void mouseDragged(MouseEvent e)
   {
      if(e.getComponent() == scale)
      {
         scaleLocX += e.getX();  
         scaleLocY += e.getY();
         scale.setLocation(scaleLocX, scaleLocY);
         e.consume();
         repaint();
         return;
      }
      //rbAdd();
      //rbo.dispatchEvent(lastPressedEvent);
      ////rbo.dispatchEvent(e);
   }
   private int lastX, lastY;
   private int firstX, firstY;
   private int currentX, currentY;
   private boolean rbInProgress = false;
   private MouseEvent lastPressedEvent;
   
   
   /*
   private RubberBandOverlay rbo;
   
   public void rbAdd()
   {
      try{remove(rbo);} catch(Exception e){} // no problem
      rbo = new RubberBandOverlay();
      add(rbo, -1);     // -1 adds at end of list.
      rbo.setBounds(0, 0, width, height);
      rbo.addMouseListener(this);
   }
   */


   public Vec getLocationLatLon(ProtoElement e)
   {
      return (Vec)elementLocs.get(e);
   }

   public void setLocation(ProtoElement e, Vec v)
   {
      elementLocs.put(e, v);
      setLocation(e, (float)v.x, (float)v.y);
   }


   public void setLocation(ProtoElement e, float lat, float lon)
   {
      // Convert lat,lon to x,y
      int x = (int)((lon + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*lat) + 90.0) * ppd) - yOffset;
      super.setLocation(e, x, y);
   }

   public void setLocation(ProtoElement e, float lat, float lon, float dx, float dy, boolean drawable)
   {
      // Convert lat,lon to x,y
      int x = (int)((lon + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*lat) + 90.0) * ppd) - yOffset;
      super.setLocation(e, x, y, dx, dy, drawable);
   }

   public void setLocation(ProtoElement e, float lat, float lon, float dx, float dy)
   {
      // Convert lat,lon to x,y
      int x = (int)((lon + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*lat) + 90.0) * ppd) - yOffset;
      super.setLocation(e, x, y, dx, dy);
   }

   public void setLocation(ProtoElement e, Vec p, Vec v, boolean drawable)
   {
      elementLocs.put(e, p);
      setLocation(e, (float)p.x, (float)p.y, (float)v.x, (float)v.y, drawable);
   }

   public void setLocation(ProtoElement e, Vec p, Vec v)
   {
      elementLocs.put(e, p);
      setLocation(e, (float)p.x, (float)p.y, (float)v.x, (float)v.y);
   }

   private void setLocations()
   {
      Enumeration enu = elementLocs.keys();
      while(enu.hasMoreElements())
      {
         ProtoElement e = (ProtoElement)enu.nextElement();
         setLocation(e, (Vec)elementLocs.get(e));
      }
   }


   public ProtoElement addElement(String name, Vec v)
   {
      ProtoElement e = addElement(name, (float)v.x, (float)v.y);
      elementLocs.put(e, v);
      return e;
   }


   public ProtoElement addElement(String name, float lat, float lon)
   {
      int x = (int)((lon + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*lat) + 90.0) * ppd) - yOffset;
      return addElement(name, x, y);
   }

   public ProtoElement addElement(String name, int x, int y)
   {
      ProtoElement e = super.addElement(name, x, y);
      scalables.put(e, new Hashtable());
      return e;
   }

   public ProtoElement addElement(String name, Vec v, Image icon)
   {
      ProtoElement e = addElement(name, (float)v.x, (float)v.y, icon);
      elementLocs.put(e, v);
      return e;
   }

   public ProtoElement addElement(String name, float lat, float lon, Image icon)
   {
      int x = (int)((lon + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*lat) + 90.0) * ppd) - yOffset;
      return addElement(name, x, y, icon);
   }

   public ProtoElement addElement(String name, float lat, float lon, Image icon, boolean drawable)
   {
      int x = (int)((lon + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*lat) + 90.0) * ppd) - yOffset;
      return addElement(name, x, y, icon, drawable);
   }

   public ProtoElement addElement(String name, int x, int y, Image icon, boolean drawable)
   {
      ProtoElement e = super.addElement(name, x, y, icon, drawable);
      scalables.put(e, new Hashtable());
      double lat = ((double)y + (double)yOffset)/(double)ppd - 90.0;
      double lon = ((double)x + (double)xOffset)/(double)ppd - 180.0;
      Vec v = new Vec(-lat, lon, 0);
      elementLocs.put(e, v);
      return e;
   }

   public ProtoElement addElement(String name, int x, int y, Image icon)
   {
      ProtoElement e = super.addElement(name, x, y, icon);
      scalables.put(e, new Hashtable());
      double lat = ((double)y + (double)yOffset)/(double)ppd - 90.0;
      double lon = ((double)x + (double)xOffset)/(double)ppd - 180.0;
      Vec v = new Vec(-lat, lon, 0);
      elementLocs.put(e, v);
      return e;
   }

   private void adjustScalableSubElements()
   {
      Enumeration elements = scalables.keys();
      while(elements.hasMoreElements())
      {
         ProtoElement pe = (ProtoElement)elements.nextElement();
         Hashtable ht = (Hashtable)scalables.get(pe);
         Enumeration subs = ht.keys();
         while(subs.hasMoreElements())
         {
           Object sub = subs.nextElement();

              if(sub instanceof CircleSubElement)
             {
                  float[] f = (float[])ht.get(sub);
                  subElementUpdate(pe, (CircleSubElement)sub, f[0], f[1], f[2], f[3]);
              }
              else if(sub instanceof AbsoluteCircleSubElement)
             {
                  float[] f = (float[])ht.get(sub);
                  subElementUpdate(pe, (AbsoluteCircleSubElement)sub, f[0], f[1], f[2], f[3]);
              }
              else if(sub instanceof PolygonSubElement)
              {
                  subElementUpdate(pe, (PolygonSubElement)sub, (float[][])ht.get(sub));
              }
              else if(sub instanceof CrossHairSubElement)
              {
                  subElementUpdate(pe, (SubElement)sub, (float[])ht.get(sub));
              }
               else if(sub instanceof IconSubElement){
                  subElementUpdate(pe, (SubElement)sub, (float[])ht.get(sub));

               }

            
         }
      }
   }

   public AbsoluteCircleSubElement addAbsoluteCircleSubElement(ProtoElement element)
   {

      AbsoluteCircleSubElement sub = super.addAbsoluteCircleSubElement(element);
      Hashtable ht = (Hashtable)scalables.get(element);
      float[] f = new float[4];
        ht.put(sub, f);
        return sub;
   }

   public IconSubElement addIconSubElement(ProtoElement element, Image icon, boolean absolute){


        float[] coords2 = new float[] { 0,0 };
        Hashtable ht = (Hashtable)scalables.get(element);
        ht.put(icon, coords2);
        return super.addIconSubElement(element, icon, absolute);

   }


   public void subElementUpdate(ProtoElement p, AbsoluteCircleSubElement sub, float xPos, float yPos, float width, float height)
   {
      int x = (int)((yPos + 180.0) * ppd) - xOffset;
      int y = (int)(((-1*xPos) + 90.0) * ppd) - yOffset;
      int w = (int)(width * ppd); int h = (int)(height * ppd);

      Hashtable ht = (Hashtable)scalables.get(p);
      float[] f = new float[4];
      f[0] = xPos;
      f[1] = yPos;
      f[2] = width;
      f[3] = height;
      ht.put(sub, f);

      super.subElementUpdate(p, sub, x, y, w, h);
   }


// CircleSubElement stuff:
   public CircleSubElement addCircleSubElement(ProtoElement element, float xPos, float yPos, float width, float height)
   {
      int x = (int)(xPos * ppd);
      int y = (int)(yPos * ppd);
      //int w = (int)(width + 180.0 * ppd);  // ? Huh?  What?
      //int h = (int)(height + 90.0* ppd);
      int w = (int)(width * ppd);
      int h = (int)(height * ppd);
      CircleSubElement subE = super.addCircleSubElement(element, x, y, w, h);
      Hashtable ht = (Hashtable)scalables.get(element);
      float[] f = new float[4];
      f[0] = xPos;
      f[1] = yPos;
      f[2] = width;
      f[3] = height;
      ht.put(subE, f);
      return subE;
   }

   public void subElementUpdate(ProtoElement p, CircleSubElement sub, float xPos, float yPos, float width, float height)
   {
      int x = (int)(xPos * ppd);  int y = (int)(yPos * ppd);
      int w = (int)(width * ppd); int h = (int)(height * ppd);
      super.subElementUpdate(p, sub, x, y, w, h);
   }


// End CircleSubElement stuff.

// PolygonSubElement stuff:
   public PolygonSubElement addPolygonSubElement(ProtoElement element, int status)
   {
      return super.addPolygonSubElement(element, status);
   }

   public PolygonSubElement addPolylineSubElement(ProtoElement element, int status)
   {
      return super.addPolylineSubElement(element, status);
   }

   public CrossHairSubElement addCrossHairSubElement(ProtoElement element, int status)
   {
      return super.addCrossHairSubElement(element, status);
   }

   public void subElementUpdate(ProtoElement p, PolygonSubElement sub, Vec[] vertices)
   {
      float[][] coords = new float[vertices.length][];
      for(int j = 0; j < vertices.length; j++)
      {
         coords[j] = new float[2];
         coords[j][0] = (float)vertices[j].x;
         coords[j][1] = (float)vertices[j].y;
      }


//      System.out.println("mp: "+vertices.length+" "+coords.length);
      subElementUpdate(p, sub, coords);
   }

/*   public void subElementUpdate(ProtoElement p, IconSubElement sub, Vec vertices)
   {
      int x = (int)(vertices.x * ppd);
      int y = (int)(vertices.y * ppd);
      super.subElementUpdate(p, sub, x ,y );
   }
*/   

   public void subElementUpdate(ProtoElement p, PolygonSubElement sub, Vec[] vertices, int status)
   {
      float[][] coords = new float[vertices.length][];
      for(int j = 0; j < vertices.length; j++)
      {
         coords[j] = new float[2];
         coords[j][0] = (float)vertices[j].x;
         coords[j][1] = (float)vertices[j].y;
      }
//      System.out.println("mp: "+vertices.length+" "+coords.length);
      subElementUpdate(p, sub, coords, status);
   }

   public void subElementUpdate(ProtoElement p, SubElement sub, Vec vertices)
   {
      Hashtable ht = (Hashtable)scalables.get(p);
      float[] f = {(float)vertices.x, (float)vertices.y};
      ht.put(sub, f);
      int[] coords = new int[2];
      coords[0] = (int)((vertices.y + 180.0) * ppd) - xOffset;
      coords[1] = (int)(((-1*vertices.x) + 90.0) * ppd) - yOffset;
//      System.out.println("mp: "+coords[0]+" "+coords[1]);
      super.subElementUpdate(p, sub, coords);
   }

   public void subElementUpdate(ProtoElement p, SubElement sub, float[] vertices)
   {
      Hashtable ht = (Hashtable)scalables.get(p);
      ht.put(sub, vertices);
      int[] coords = new int[2];
      coords[0] = (int)((vertices[1] + 180.0) * ppd) - xOffset;
      coords[1] = (int)(((-1*vertices[0]) + 90.0) * ppd) - yOffset;
//      System.out.println("mp: "+coords[0]+" "+coords[1]);
      super.subElementUpdate(p, sub, coords);
   }

   public void subElementUpdate(ProtoElement p, PolygonSubElement sub, float[][] vertices, int status)
   {
      Hashtable ht = (Hashtable)scalables.get(p);
      ht.put(sub, vertices);
//      Polygon poly = new Polygon();
      int [] xpoints = new int [vertices.length];
      int [] ypoints = new int [vertices.length];
      for (int i = 0; i < vertices.length; i++) {
         xpoints[i] = (int)((vertices[i][1] + 180.0) * ppd) - xOffset;
         ypoints[i] = (int)(((-1*vertices[i][0]) + 90.0) * ppd) - yOffset;
      }
      Polygon poly = new Polygon(xpoints, ypoints, xpoints.length);
//      System.out.println("mp: "+poly.npoints);
      super.subElementUpdate(p, sub, poly, status);
   }


   public void subElementUpdate(ProtoElement p, PolygonSubElement sub, float[][] vertices)
   {
      Hashtable ht = (Hashtable)scalables.get(p);
      ht.put(sub, vertices);
//      Polygon poly = new Polygon();
      int [] xpoints = new int [vertices.length];
      int [] ypoints = new int [vertices.length];
      for (int i = 0; i < vertices.length; i++) {
         xpoints[i] = (int)((vertices[i][1] + 180.0) * ppd) - xOffset;
         ypoints[i] = (int)(((-1*vertices[i][0]) + 90.0) * ppd) - yOffset;
      }
      Polygon poly = new Polygon(xpoints, ypoints, xpoints.length);
//      System.out.println("mp: "+poly.npoints);
      super.subElementUpdate(p, sub, poly);
   }

// End PolygonSubElement stuff.

   public void removeElement(ProtoElement e) {
      super.removeElement(e);
      scalables.remove(e);
   }

   public void removeListeners() {
      this.removeMouseListener(this);
      this.removeMouseMotionListener(this);
   }

   public void restoreListeners() {
      this.addMouseListener(this);
      this.addMouseMotionListener(this);
   }
/*

   public Dimension getPreferredSize()
   {
      return new Dimension(width, height);
   }

*/
   public void processECEvent(ECEvent le) {
      int n = linkListeners.size();
      for (int i = 0; i < n; i++) {
         ((ECEListener)linkListeners.elementAt(i)).eceAction(le);
      }
   }


   public void addECEListener(ECEListener l){
      linkListeners.addElement(l);
   }


   public void removeECEListener(ECEListener l){
      linkListeners.removeElement(l);
   }

   public void toggleGridLines()
   {
      gridLines = !gridLines;
      createBackground();
      repaint();
   }

   public void setEditMode(boolean mode) {
      if (mode == true) {
         addMouseMotionListener(editDragListener);
         addMouseListener(this);
         addMouseListener(editPressedListener);
         addMouseListener(editClickedListener);
         addKeyListener(editKeyListener);
      }
      else if (mode == false) {
         removeMouseMotionListener(editDragListener);
         removeMouseListener(editPressedListener);
         removeMouseListener(editClickedListener);
      }
   }
}
