/*----------------------------------------------------------------------+
|	Title:	Slate.java						|
|		Java class Slate extends Canvas				|
|									|
|	Author:	David E. Joyce						|
|		Department of Mathematics and Computer Science   	|
|		Clark University					|
|		Worcester, MA 01610-1477				|
|		U.S.A.							|
|									|
|		http://aleph0.clarku.edu/~djoyce/home.html		|
|		djoyce@clarku.edu					|
|									|
|	Date:	February, 1996.  					|
+----------------------------------------------------------------------*/

import java.awt.*;
import java.lang.String;
import java.util.StringTokenizer;

public class Slate extends Canvas {

  int eCount = 0;
  Element element[];
  boolean preexists[];
  PointElement pivot = null;
  PointElement pick = null;

  Slate (int n) {
    element = new Element[n];
    preexists = new boolean[n];
  }

  Slate () {
    element = new Element[100];
    preexists = new boolean[100];
  }

  void extendArrays() {
    int len = element.length;
    Element newelement[] = new Element[2*len];
    boolean newpreexists[] = new boolean[2*len];
    for (int i=0; i<len; ++i) {
      newelement[i] = element[i];
      newpreexists[i] = preexists[i];
    }
    element = newelement;
    preexists = newpreexists;
  }


  static String elementClassName[] = {
	"point", "line", "circle", "polygon", "sector"};

  static int lookupElementClass (String s) {
    for (int i=0; i<elementClassName.length; ++i)
      if (elementClassName[i].equals(s)) return i;
    return -1;
  }

  static String constructionName[][] =
    { { "free",  		"midpoint",		"intersection",	
	"first",		"last",			"center",
	"lineSlider",		"circleSlider",		"circumcenter",
	"vertex",		"foot",			"cutoff",
	"extend",		"parallelogram",	"similar",
	"perpendicular",	"proportion",		"invert",
	"meanProportional"},

      { "connect",		"angleBisector",	"angleDivider",
	"foot",			"chord",		"bichord",
	"perpendicular",	"cutoff",		"extend",
	"parallel",		"similar",		"proportion",
	"meanProportional"},

      { "radius",		"circumcircle",		"invert"},

      { "square", 		"triangle", 		"quadrilateral",
	"pentagon",		"hexagon",		"equilateralTriangle",
	"parallelogram",	"regularPolygon",	"starPolygon",
	"similar",		"application"},

      { "sector",		"arc"},
    };

  public static int lookupConstructionMethod (int eClass, String s) {
    for (int i=0; i<constructionName[eClass].length; ++i)
      if (constructionName[eClass][i].equals(s)) return i;
    return -1;
  }

  public static String constructionDataType[][][][] =
    { { // point constructions
	{ // free point construction
	  {"Integer","Integer"} },		
	{ // midpoint constructions
	  {"PointElement","PointElement"},
	  {"LineElement"} },			
	{ // intersection constructions
	  {"PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement"} },
	{ // first point of a line
	  {"LineElement"} },
	{ // last point of a line
	  {"LineElement"} },
	{ // center of a circle
	  {"CircleElement"} },	
	{ // point sliding along a line
	  {"PointElement","PointElement","Integer","Integer"},
	  {"LineElement","Integer","Integer"} },
	{ // point sliding along a circle
	  {"CircleElement","Integer","Integer"} },
	{ // circumcenter
	  {"PointElement","PointElement","PointElement"} },
	{ // vertex of a polygon
	  {"PolygonElement","Integer"} },
	{ // foot constructions
	  {"PointElement","PointElement","PointElement"},
	  {"PointElement","LineElement"} },
	{ // cutoff constructions
	  {"PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement"} },
	{ // extend constructions
	  {"PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement"} },
	{ // parallelogram constructions
	  {"PointElement","PointElement","PointElement"},
	  {"PointElement","LineElement"} },
	{ // similar triangle constructions
	  {"PointElement","PointElement","PointElement",
		"PointElement","PointElement"},
	  {"LineElement","PointElement","PointElement","PointElement"} },
	{ // perpendicular constructions
	  {"PointElement","PointElement"},
	  {"LineElement"} },
	{ // proportion constructions
	  {"PointElement","PointElement","PointElement","PointElement",
	   "PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement","LineElement","LineElement"} },
	{ // invert in a circle
	  {"PointElement","CircleElement"} },
	{ // meanProportional constructions
	  {"PointElement","PointElement","PointElement","PointElement",
	   "PointElement","PointElement"},
	  {"LineElement","LineElement","LineElement"} },
      },

      { // line constructions
	{ // connect two points
	  {"PointElement","PointElement"} },	
	{ // angle bisector construction
	  {"PointElement","PointElement","PointElement"} }, 
	{ // angle divider construction
	  {"PointElement","PointElement","PointElement","Integer"} },
	{ // foot constructions
	  {"PointElement","PointElement","PointElement"},
	  {"PointElement","LineElement"} },
	{ // chord construction
	  {"PointElement","PointElement","CircleElement"}, 
	  {"LineElement","CircleElement"} },
	{ // bichord construction
	  {"CircleElement","CircleElement"} },
	{ // perpendicular constructions
	  {"PointElement","PointElement"},
	  {"LineElement"} },
	{ // cutoff constructions
	  {"PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement"} },
	{ // extend constructions
	  {"PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement"} },
	{ // parallel constructions
	  {"PointElement","PointElement","PointElement"},
	  {"PointElement","LineElement"} },
	{ // similar triangle (angle) constructions
	  {"PointElement","PointElement","PointElement",
		"PointElement","PointElement"},
	  {"LineElement","PointElement","PointElement","PointElement"} },
	{ // proportion constructions
	  {"PointElement","PointElement","PointElement","PointElement",
	   "PointElement","PointElement","PointElement","PointElement"},
	  {"LineElement","LineElement","LineElement","LineElement"} },
	{ // meanProportional constructions
	  {"PointElement","PointElement","PointElement","PointElement",
	   "PointElement","PointElement"},
	  {"LineElement","LineElement","LineElement"} },
      },

      { // circle constructions
	{ // center and radius constructions
	  {"PointElement","PointElement"},
	  {"LineElement"},
	  {"PointElement","PointElement","PointElement"},
	  {"PointElement","LineElement"} },
	{ // circumcircle construction
	  {"PointElement","PointElement","PointElement"} },
	{ // invert in another circle
	  {"CircleElement","CircleElement"} },
      },

      { // polygon constructions
	{ // square constructions
	  {"PointElement","PointElement"},
	  {"LineElement"} },
	{ // triangle construction
	  {"PointElement","PointElement","PointElement"} },
	{ // quadrilateral construction
	  {"PointElement","PointElement","PointElement","PointElement"} },
	{ // pentagon construction
	  {"PointElement","PointElement","PointElement",
	   "PointElement","PointElement"} },
	{ // hexagon construction
	  {"PointElement","PointElement","PointElement",
	   "PointElement","PointElement","PointElement"} },
	{ // equilateral triangle constructions
	  {"PointElement","PointElement"},
	  {"LineElement"} },
	{ // parallelogram constructions
	  {"PointElement","LineElement"},
	  {"PointElement","PointElement","PointElement"} },
	{ // regular polygon constructions
	  {"PointElement","PointElement","Integer"},
	  {"LineElement","Integer"} },
	{ // star polygon constructions
	  {"PointElement","PointElement","Integer","Integer"},
	  {"LineElement","Integer","Integer"} },
	{ // similar triangle constructions
	  {"PointElement","PointElement","PointElement",
		"PointElement","PointElement"},
	  {"LineElement","PointElement","PointElement","PointElement"} },
	{ // application
	  {"PolygonElement","PointElement","PointElement","PointElement"} },
      },

      { // sector constructions
	{ // center and arc construction
	  {"PointElement","PointElement","PointElement"} },
	{ // arc construction
	  {"PointElement","PointElement","PointElement"} },	
     } };


  Element lookupElement(String name) {
    for (int i=0; i<eCount; ++i)
      if (name.equals(element[i].name))
	return element[i];
    return null;
  }


  int selectDataChoice (String data, String datachoices[][], 
	Element e[], int n[]) {
    // parse the data string to look for a type match among the
    // various datachoices.  Store the resulting elements in the
    // e array and the resulting integers in the n array.
    int i,j;
    for (i=0; i<datachoices.length; ++i) {	// try the i'th choice
      StringTokenizer t = new StringTokenizer(data,",");
      if (datachoices[i].length != t.countTokens()) continue;
      int es=0, ns=0;
      for (j=0; j<datachoices[i].length; ++j) {
        if (!t.hasMoreTokens()) break;
	String next = t.nextToken();
	if (datachoices[i][j].equals("Integer")) {
	  try {
	    n[ns++] = Integer.parseInt(next.toString());
	  } catch (NumberFormatException exc) {
	    break;
	  }
	} else {	// it's some kind of Element
	  e[es] = lookupElement (next);
	  if (e[es] == null) break;
	  if (!e[es++].inClass(datachoices[i][j]))
	    break;
      } }
      if (j == datachoices[i].length) break;
    }
    return (i==datachoices.length) ? -1 : i;
  }

  void createElement(int c, int m, int choice, Element E[], int N[]) {
    switch (c) {
      case 0:	// point constructions
	switch (m) {
	  case 0:	// free point construction
	    element[eCount] = new FreePoint((double)N[0],(double)N[1]);
	    return;
	  case 1:	// midpoint constructions
	    if (choice == 0)
	      element[eCount] = new Midpoint((PointElement)E[0],
		(PointElement)E[1]);
	    else
	      element[eCount] = new Midpoint((LineElement)E[0]);
	    return;
	  case 2:	// intersection constructions
	    if (choice == 0)
	      element[eCount] = new Intersection((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3]);
	    else
	      element[eCount] = new Intersection ((LineElement)E[0],
		(LineElement)E[1]);
	    return;
	  case 3:	// first point of a line
	    element[eCount] = ((LineElement)E[0]).A;
	    preexists[eCount] = true;
	    return;
	  case 4:	// last point of a line
	    element[eCount] = ((LineElement)E[0]).B;
	    preexists[eCount] = true;
	    return;
	  case 5:	// center of a circle
	    element[eCount] = ((CircleElement)E[0]).Center;
	    preexists[eCount] = true;
	    return;
	  case 6:	// point sliding along a line
	    if (choice == 0)
	      element[eCount] = new LineSlider((PointElement)E[0],
		(PointElement)E[1],N[0],N[1]);
	    else
	      element[eCount] = new LineSlider((LineElement)E[0],N[0],N[1]);
	    return;
	  case 7:	// point sliding along a line
	    element[eCount] = new CircleSlider((CircleElement)E[0],N[0],N[1]);
	    return;
	  case 8:	// circumcenter given three points
	    Circumcircle circ = new Circumcircle((PointElement)E[0],
		(PointElement)E[1], (PointElement)E[2]);
	    element[eCount++] = circ;
	    element[eCount] = circ.Center;
	    preexists[eCount] = true;
	    return;
	  case 9:	// vertex of a polygon
	    element[eCount] = ((PolygonElement)E[0]).V[N[0]-1];
	    preexists[eCount] = true;
	    return;
	  case 10:	// foot constructions
	    Foot footline;
	    if (choice == 0)
	      footline = new Foot((PointElement)E[0],(PointElement)E[1],
		(PointElement)E[2]);
	    else
	      footline = new Foot((PointElement)E[0],(LineElement)E[1]);
	    element[eCount] = footline;
	    element[++eCount] = footline.B;
	    preexists[eCount] = true;
	    return;

	  case 11:	// cutoff constructions
	    if (choice == 0) {
	      element[eCount] = new Layoff((PointElement)E[0],
		(PointElement)E[0],(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	      element[eCount+1] = ((LineElement)element[eCount]).B;
	      preexists[++eCount] = true;
	    } else {
	      element[eCount] = new Layoff(((LineElement)E[0]).A,
		((LineElement)E[0]).A,((LineElement)E[0]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	      element[eCount+1] = ((LineElement)element[eCount]).B;
	      preexists[++eCount] = true;
	    }
	    return;
	  case 12:	// extend constructions
	    if (choice == 0) {
	      element[eCount] = new Layoff((PointElement)E[1],
		(PointElement)E[0],(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	      element[eCount+1] = ((LineElement)element[eCount]).B;
	      preexists[++eCount] = true;
	    } else {
	      element[eCount] = new Layoff(((LineElement)E[0]).B,
		((LineElement)E[0]).A,((LineElement)E[0]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	      element[eCount+1] = ((LineElement)element[eCount]).B;
	      preexists[++eCount] = true;
	    }
	    return;
	  case 13:	// parallelogram constructions
	    if (choice == 0)
	      element[eCount] = new Layoff((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[1],
		(PointElement)E[2]);
	    else
	      element[eCount] = new Layoff((PointElement)E[0],
		((LineElement)E[1]).A,((LineElement)E[1]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	    element[eCount+1] = ((LineElement)element[eCount]).B;
	    preexists[++eCount] = true;
	    return;
	  case 14:	// similar triangle constructions
	    if (choice == 0)
	      element[eCount] = new Similar((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4]);
	    else
	      element[eCount] = new Similar(((LineElement)E[0]).A,
		((LineElement)E[0]).B,(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	    element[eCount+1] = ((PolygonElement)element[eCount]).V[2];
	    preexists[++eCount] = true;
	    return;
	  case 15:	// perpendicular constructions
	    if (choice == 0)
	      element[eCount] = new Perpendicular((PointElement)E[0],
		(PointElement)E[1]);
	    else
	      element[eCount] = new Perpendicular((LineElement)E[0]);
	    element[eCount+1] = ((LineElement)element[eCount]).B;
	    preexists[++eCount] = true;
	    return;
	  case 16:	// proportion constructions
	    if (choice == 0)
	      element[eCount] = new Proportion((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4],(PointElement)E[5],(PointElement)E[6],
		(PointElement)E[7]);
	    else
	      element[eCount] = new Proportion((LineElement)E[0],
		(LineElement)E[1],(LineElement)E[2],(LineElement)E[3]);
	    element[eCount+1] = ((LineElement)element[eCount]).B;
	    preexists[++eCount] = true;
	    return;
	  case 17:	// invert in a circle
	    element[eCount] = new InvertPoint((PointElement)E[0],
		(CircleElement)E[1]);
	    return;
	  case 18:	// meanProportional constructions
	    if (choice == 0)
	      element[eCount] = new MeanProportional((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4],(PointElement)E[5]);
	    else
	      element[eCount] = new MeanProportional((LineElement)E[0],
		(LineElement)E[1],(LineElement)E[2]);
	    element[eCount+1] = ((LineElement)element[eCount]).B;
	    preexists[++eCount] = true;
	    return;
	}

      case 1:	// line constructions
	switch (m) {
	  case 0:	// connect construction
	    element[eCount] = new LineElement((PointElement)E[0],
		(PointElement)E[1]); 
	    return;
	  case 1:	// angle bisector construction
	    element[eCount] = new AngleDivider((PointElement)E[0],
		(PointElement)E[1], (PointElement)E[2], 2);
	    return;
	  case 2:	// angle divider construction
	    element[eCount] = new AngleDivider((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2], N[0]);
	    return;
	  case 3:	// foot constructions
	    if (choice == 0)
	      element[eCount] = new Foot((PointElement)E[0],(PointElement)E[1],
		(PointElement)E[2]);
	    else
	      element[eCount] = new Foot((PointElement)E[0],(LineElement)E[1]);
	    return;
	  case 4:	// chord construction
	    if (choice == 0)
	      element[eCount] = new Chord((PointElement)E[0],(PointElement)E[1],
		(CircleElement)E[2]);
	    else
	      element[eCount] = new Chord((LineElement)E[0],(CircleElement)E[1]);
	    return;
	  case 5:	// bichord construction
	    element[eCount] = new Bichord((CircleElement)E[0],
		(CircleElement)E[1]);
	    return;
	  case 6:	// perpendicular constructions
	    if (choice == 0)
	      element[eCount] = new Perpendicular((PointElement)E[0],
		(PointElement)E[1]);
	    else
	      element[eCount] = new Perpendicular((LineElement)E[0]);
	    return;
	  case 7:	// cutoff constructions
	    if (choice == 0)
	      element[eCount] = new Layoff((PointElement)E[0],
		(PointElement)E[0],(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	    else
	      element[eCount] = new Layoff(((LineElement)E[0]).A,
		((LineElement)E[0]).A,((LineElement)E[0]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	    return;
	  case 8:	// extend constructions
	    if (choice == 0)
	      element[eCount] = new Layoff((PointElement)E[1],
		(PointElement)E[0],(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	    else
	      element[eCount] = new Layoff(((LineElement)E[0]).B,
		((LineElement)E[0]).A,((LineElement)E[0]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	    return;
	  case 9:	// parallel constructions
	    if (choice == 0)
	      element[eCount] = new Layoff((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[1],
		(PointElement)E[2]);
	    else
	      element[eCount] = new Layoff((PointElement)E[0],
		((LineElement)E[1]).A,((LineElement)E[1]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	    return;
	  case 10:	// similar triangle (angle) constructions
	    if (choice == 0)
	      element[eCount] = new Similar((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4]);
	    else
	      element[eCount] = new Similar(((LineElement)E[0]).A,
		((LineElement)E[0]).B,(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	    element[eCount+1] = new LineElement 
		(((PolygonElement)element[eCount]).V[0], 
		 ((PolygonElement)element[eCount]).V[2]);
	    preexists[++eCount] = true;
	    return;
	  case 11:	// proportion constructions
	    if (choice == 0)
	      element[eCount] = new Proportion((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4],(PointElement)E[5],(PointElement)E[6],
		(PointElement)E[7]);
	    else
	      element[eCount] = new Proportion((LineElement)E[0],
		(LineElement)E[1],(LineElement)E[2],(LineElement)E[3]);
	    return;
	  case 12:	// meanProportional constructions
	    if (choice == 0)
	      element[eCount] = new MeanProportional((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4],(PointElement)E[5]);
	    else
	      element[eCount] = new MeanProportional((LineElement)E[0],
		(LineElement)E[1],(LineElement)E[2]);
	    return;
	}

      case 2:	// circle constructions
	switch (m) {
	  case 0:	// radius construction
	    switch (choice) {
	      case 0:
	        element[eCount] =  new CircleElement((PointElement)E[0], 
		  (PointElement)E[1]);
		return;
	      case 1:
	        element[eCount] =  new CircleElement((LineElement)E[0]);
	        return;
	      case 2:
	        element[eCount] =  new CircleElement((PointElement)E[0], 
		  (PointElement)E[1],(PointElement)E[2]);
		return;
	      case 3:
		element[eCount] =  new CircleElement((PointElement)E[0], 	
		  (LineElement)E[1]);
	        return;
	    }
	  case 1:	// circumcircle construction
	    element[eCount] = new Circumcircle((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2]);
	    return;
	  case 2:	// invert in another circle
	    element[eCount] = new InvertCircle((CircleElement)E[0],
		(CircleElement)E[1]);
	    return;
	}

      case 3:	// polygon constructions
	switch (m) {
	  case 0:	// square construction
	    if (choice == 0)
	      element[eCount] =  new RegularPolygon((PointElement)E[0],
						(PointElement)E[1],4);
	    else
	      element[eCount] =  new RegularPolygon((LineElement)E[0],4);
	    return;
	  case 1:	// triangle construction
	    element[eCount] = new PolygonElement((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2]);
	    return;
	  case 2:	// quadrilateral construction
	    element[eCount] = new PolygonElement((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3]);
	    return;
	  case 3:	// pentagon construction
	    element[eCount] = new PolygonElement((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4]);
	    return;
	  case 4:	// hexagon construction
	    element[eCount] = new PolygonElement((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4],(PointElement)E[5]);
	    return;
	  case 5:	// equilateral triangle constructions
	    if (choice == 0)
	      element[eCount] =  new RegularPolygon((PointElement)E[0],
		(PointElement)E[1],3);
	    else
	      element[eCount] =  new RegularPolygon((LineElement)E[0],3);
	    return;
	  case 6:	// parallelogram construction
	    Layoff fourth;
	    if (choice == 0) {
	      fourth= new Layoff((PointElement)E[0],
		((LineElement)E[1]).A,((LineElement)E[1]).B,
		((LineElement)E[1]).A,((LineElement)E[1]).B);
	      element[eCount] = fourth;
	      element[++eCount] = new PolygonElement((PointElement)E[0],
		((LineElement)E[1]).A,((LineElement)E[1]).B,fourth.B);
	    } else {
	      fourth = new Layoff((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[1],
		(PointElement)E[2]);
	      element[eCount] = fourth;
	      element[++eCount] = new PolygonElement((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],fourth.B);
	    }
	    return;
	  case 7:	// regular polygon constructions
	    if (choice == 0)
	      element[eCount] =  new RegularPolygon((PointElement)E[0],
		(PointElement)E[1],N[0]);
	    else
	      element[eCount] =  new RegularPolygon((LineElement)E[0],N[0]);
	    return;
	  case 8:	// star polygon constructions
	    if (choice == 0)
	      element[eCount] =  new RegularPolygon((PointElement)E[0],
		(PointElement)E[1],N[0],N[1]);
	    else
	      element[eCount] =  new RegularPolygon((LineElement)E[0],
		N[0],N[1]);
	    return;
	  case 9:	// similar triangle constructions
	    if (choice == 0)
	      element[eCount] = new Similar((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3],
		(PointElement)E[4]);
	    else
	      element[eCount] = new Similar(((LineElement)E[0]).A,
		((LineElement)E[0]).B,(PointElement)E[1],(PointElement)E[2],
		(PointElement)E[3]);
	    return;
	  case 10:	// application construction
	    element[eCount] = new Application((PolygonElement)E[0],
		(PointElement)E[1],(PointElement)E[2],(PointElement)E[3]);
	    return;
    	}

      case 4:	// sector constructions
	switch (m) {
	  case 0:	// sector construction
	    element[eCount] =  new SectorElement((PointElement)E[0], 
		(PointElement)E[1],(PointElement)E[2]);
	    return;
	  case 1:	// arc construction
	    element[eCount] = new Arc((PointElement)E[0],
		(PointElement)E[1],(PointElement)E[2]);
	    return;
    }	}

    return;	// should never reach here, but the compiler complains
  }


  Element constructElement (String name, String elementClass,
	String constructionMethod, String data, StringBuffer message) {
    if (lookupElement(name) != null) {
      message.append("An element with the name " + name 
		     + " has already been created.");
      return null;
    }
    int c = lookupElementClass (elementClass);
    if (c == -1) {
      message.append("Element class " + elementClass + " is not known.");
      return null;
    }
    int m = lookupConstructionMethod (c, constructionMethod);
    if (m == -1) {
      message.append("constructionMethod " + constructionMethod 
	+ " is not known for " + " element class " + elementClass + ".");
      return null;
    } 
    Element E[] = new Element[10];
    int N[] = new int[4];
    int choice = selectDataChoice (data, constructionDataType[c][m], 
				   E, N);
    if (choice == -1) {
      message.append("Construction method " + constructionMethod 
	+ " for " + " element class " + elementClass 
	+ " with data " + data
	+ " requires different data.");
      return null;
    }
    if (element.length < eCount+1)
      extendArrays();
    createElement (c, m, choice, E, N);
    element[eCount].setName(name);
    return element[eCount++];
  }

  void setPivot (String name) {
    Element e = lookupElement(name);
    if (e != null && e.inClass("PointElement"))
      pivot = (PointElement)e;
  }

  void reset() {
    for (int i=0; i<eCount; ++i)
      element[i].reset();
  }

  void computeCoordinates() {
    for (int i=0; i<eCount; ++i) 
      element[i].update();
  }

  void translateCoordinates(double dx, double dy) {
    for (int i=0; i<eCount; ++i)
      if (!preexists[i])
        element[i].translate(dx,dy);
  }

  void rotateCoordinates(double ac, double as) {
    for (int i=0; i<eCount; ++i)
      if (!preexists[i])
        element[i].rotate(pivot,ac,as);
  }

  public void update (Graphics g) {
    g.setColor(getBackground());
    Dimension d = size();
    g.fillRect(0, 0, d.width, d.height);
    for (int i=0; i<eCount; ++i) 
      element[i].drawFace(g);
    for (int i=0; i<eCount; ++i) 
      element[i].drawEdge(g);
    for (int i=0; i<eCount; ++i) 
      element[i].drawVertex(g);
    for (int i=0; i<eCount; ++i) 
      element[i].drawName(g);
  }

  public void paint(Graphics g) {repaint();}

  PointElement Ctemp = new PointElement(); // temporary point used in movePick

  void movePick (int c, int d) {
    if (pick == null) {			// select a nearby point
      double bestdist2 = Double.POSITIVE_INFINITY;
      for (int i=0; i<eCount; ++i)
	if (element[i].inClass("PointElement")) {
	  double dist2 = ((PointElement)element[i]).distance2(c,d);
          if (dist2 < 100.0 && dist2 < bestdist2) {
	    pick = (PointElement)element[i];
	    bestdist2 = dist2;
    }   } }
    // adjust c and d to be on the image so points don't get lost
    int w = size().width;
    if (c < 0) c = 0;
    else if (c > w) c = w;
    int h = size().height;
    if (d < 0) d = 0;
    else if (d > h) d = h;
    // now actually change the slate
    if (pick == null) return;		// no nearby points
    else if (pick == pivot) {		// translate all coordinates
      double dx = c - pivot.x;
      double dy = d - pivot.y;
      translateCoordinates(dx,dy);
      repaint();
    } else if (pick.dragable) {		// drag the point
      pick.drag(c,d);
      computeCoordinates();
      repaint();
    } else if (pivot != null) {		// rotate around the pivot
      Ctemp.x = c;  Ctemp.y = d;
      double a = pivot.distance(Ctemp) / pivot.distance(pick);
      double theta = pivot.angle(pick,Ctemp);
      rotateCoordinates (a*Math.cos(theta), a*Math.sin(theta));
      repaint();
    }					// otherwise do nothing
  }

  public boolean keyDown(Event evt, int key) {
    if (key=='r' || key=='R' || key==' ') {
      reset();				// typing r or space resets the diagram
      repaint();
      return true;
    } else return false;
  }

  public boolean mouseDown(Event evt, int c, int d) {
    // determine which ball is closest to location (c,d).
    pick = null;
    movePick (c,d);
    return true;
  } 

  public boolean mouseDrag(Event evt, int c, int d) {
    movePick (c,d);
    return true;
  }

  public boolean mouseUp(Event evt, int c, int d) {
    if (pick == null) return true;
    movePick(c,d);
    pick = null;
    return true;
} }
