  import edu.neu.ccs.demeterf.*;
  import edu.neu.ccs.demeterf.control.Fields;
  import java.io.*;

  // shape.java
  public abstract class shape{
    abstract double area();
    shape add(shape s){ return new pair(s,this); }

      
    public static void main(String[] a){
      shape s = 
          new circle(5)
          .add(new square(5))
          .add(new circle(2))
          .add(new rect(4,9));

       System.err.println("          s == "+s);
       System.err.println("   s.area() == "+s.area());
       System.err.println("    area(s) == "+Area.area(s));
       System.err.println("    area(s) == "+Count.count(s));
       System.err.println("    c->s(s) == "+Circ2sqr.circ2sqr(s));
       System.err.println("   scale(s) == "+Scale.scale(s));
       System.err.println("depthScl(s) == "+DepthScl.scale(s));
       System.err.println(" leftScl(s) == "+LeftScl.scale(s));
       
       shape[] ss = {s,Circ2sqr.circ2sqr(s),Scale.scale(s),
                     DepthScl.scale(s),LeftScl.scale(s)};
       String[] fs = {"shape.svg","circ2sqr.svg","scale.svg",
                      "depth.svg","left.svg"};
       for(int i = 0; i < fs.length; i++){
           System.err.println(" Do["+i+"]: "+fs[i]);
           try{
               PrintStream out = new PrintStream(new FileOutputStream(fs[i]));
               out.println(Display.display(ss[i]));
               out.close();
           }catch(Exception e){
               System.err.println("BAD: "+e);
           }
       }
    }
    public String toString()
     { return new Traversal(new Str()).traverse(this); }
  }

  class circle extends shape{
     int radius;
     circle(int r){ radius = r; }
     double area(){ return Math.PI*radius*radius; }
  }
  class square extends shape{
     int side;
     square(int s){ side = s; }
     double area(){ return side*side; }
  }
  class pair extends shape{
     shape left,
           right;
     pair(shape l, shape r){ left = l; right = r; }
     double area(){ return left.area()+right.area(); }
     public static class left extends Fields.any{}
     public static class right extends Fields.any{}
  }

  class rect extends shape{
     int width,
         height;
     rect(int w, int h){ width = w; height = h; }
     double area(){ return width*height; }
  }

  // area function class
  class Area extends ID{
     double combine(circle c, int r){ return Math.PI*r*r; }
     double combine(square s, int d){ return d*d; }
     double combine(rect r, int w, int h){ return w*h; }
     double combine(pair p, double l, double r){ return l+r; }

     static double area(shape s){
       return new Traversal(new Area()).<Double>traverse(s);
     }
  }

  // count function class
  class Count extends ID{
     int combine(shape c){ return 1; }
     int combine(pair p, int l, int r){ return l+r; }

     static int count(shape s){
       return new Traversal(new Count()).<Integer>traverse(s);
     }
  }

  // circle -> square  function class
  class Circ2sqr extends Bc{
      shape combine(circle c, int r){ return new square(r+r); }

     static shape circ2sqr(shape s){
        return new Traversal(new Circ2sqr()).<shape>traverse(s);
     }
  }


  class Str extends ID{
     String combine(circle c, int r){ return "circle("+r+")"; }
     String combine(square s, int d){ return "square("+d+")"; }
     String combine(rect r, int w, int h)
      { return "rect("+w+", "+h+")"; }
     String combine(pair p, String l, String r)
      { return "pair("+l+", "+r+")"; }
  }

  // scale  function class
  class Scale extends Bc{
     int combine(int i){ return i*2; }

     static shape scale(shape s){
       return new Traversal(new Scale()).<shape>traverse(s);
     }
  }

  // depthScl  function class
  class DepthScl extends Bc{
     int update(pair p, Fields.any f, int d){ return d+1; }
     int combine(int i, int d){ return i*d; }

     static shape scale(shape s){
         return new Traversal(new DepthScl()).<shape>traverse(s,1);
     }
  }


  // leftScl function class
  class LeftScl extends DepthScl{
     // Don't increase the depth for 'right' children
     int update(pair p, pair.right f, int d){ return d; }

     static shape scale(shape s){
       return new Traversal(new LeftScl()).<shape>traverse(s,1);
     }
  }


  class Display extends ID{
      static int y = 50;
      int update(pair p, pair.right f, int x){ return x+45; }
      String combine(pair p, String l, String r){ return l+r; }

      int combine(int i){ return 3*i; }
      String combine(circle c, int r, int x)
       { return svg.circle(x,y,r); }
      String combine(square s, int sd, int x)
       { return svg.rect(x,y,sd,sd); }
      String combine(rect r, int w, int h, int x)
       { return svg.rect(x,y,w,h); }

      static String display(shape s){
          return svg.image(240, 100,
                           new Traversal(new display())
                           .<String>traverse(s,40));
      }
  }

  class svg{
      static String head(int w, int h){
          round = 0;
          return 
              "<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN'\n"+
              "'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'>"+
              "<svg xmlns='http://www.w3.org/2000/svg' version='1.1' "+
              "width='"+w+"' height='"+h+"'>"+
              "<rect x='1' y='1' width='"+(w-2)+"' height='"+(h-2)+"'"+
              " fill-opacity='0' stroke='black'/>\n";
      }
      static String foot(){ return "</svg>\n"; }
      static String end(){ return " fill='"+col()+"' fill-opacity='0.5' />\n"; }
      
      static String[] colors = {"red","green","blue","orange","purple"};
      static int round = 0;
      static String col(){ return colors[round++]; }

      static String circle(int x, int y, int r){
          return ("  <circle cx='"+x+"' cy='"+y+
                  "' r='"+r+"'"+svg.end());
      }
      static String rect(int x, int y, int w, int h){
          return ("  <rect x='"+(x-w/2)+"' y='"+(y-h/2)+
                  "' width='"+w+"' height='"+h+"'"+svg.end());
      }
      static String image(int w, int h, String bdy){
          return head(w,h)+bdy+foot();
      }
  }