/*
 * Copyright 1997-2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */



import java.awt.*;
import java.util.*;
import java.awt.event.*;
import java.applet.Applet;

class GraphicsPanel extends Panel {
    ActionListener al;
    ItemListener il;
    public GraphicsCards cards;

     GraphicsPanel(EventListener listener) {
         al = (ActionListener)listener;
         il = (ItemListener)listener;

        setLayout(new BorderLayout());

        add("Center", cards = new GraphicsCards());

        Panel p = new Panel();
        //p.setLayout(new BorderLayout());

        Button b = new Button("next");
        b.addActionListener(al);
        p.add(b);

        b = new Button("previous");
        b.addActionListener(al);
        p.add(b);

        p.add(new Label("go to:", Label.RIGHT));

        Choice c = new Choice();
        c.addItemListener(il);
        p.add(c);

        c.addItem("Arc");
        c.addItem("Oval");
        c.addItem("Polygon");
        c.addItem("Rect");
        c.addItem("RoundRect");

        add("North", p);

        setSize(400, 400);
    }

    public Dimension getPreferredSize() {
        return new Dimension(200, 100);
    }
}

public class GraphicsTest extends Applet
implements ActionListener, ItemListener {
    GraphicsPanel mainPanel;

    public void init() {
        setLayout(new BorderLayout());
        add("Center", mainPanel = new GraphicsPanel(this));
    }

    public void destroy() {
        remove(mainPanel);
    }

    public void actionPerformed(ActionEvent e) {
        String arg = e.getActionCommand();

        if ("next".equals(arg)) {
            ((CardLayout)mainPanel.cards.getLayout()).next(mainPanel.cards);
        }
        else if ("previous".equals(arg)) {
            ((CardLayout)mainPanel.cards.getLayout()).previous(mainPanel.cards);
        }
    }

    public void itemStateChanged(ItemEvent e) {
        ((CardLayout)mainPanel.cards.getLayout()).show(mainPanel.cards,(String)e.getItem());
    }

    public static void main(String args[]) {
        AppletFrame.startApplet("GraphicsTest", "Graphics Test", args);
    }

    public String getAppletInfo() {
        return "An interactive demonstration of some graphics.";
    }
}   // end class GraphicsTest


class GraphicsCards extends Panel {
    public GraphicsCards() {
        setLayout(new CardLayout());
        add("Arc", new ArcCard());
        add("Oval", new ShapeTest( new OvalShape() ) );
        add("Polygon", new ShapeTest( new PolygonShape() ) );
        add("Rect", new ShapeTest( new RectShape() ) );
        add("RoundRect", new ShapeTest( new RoundRectShape() ) );
    }
}   // end class GraphicsCards


class ArcCard extends Panel {
    public ArcCard() {
        setLayout(new GridLayout(0, 2));
        add(new ArcPanel(true));
        add(new ArcPanel(false));
        add(new ArcDegreePanel(true));
        add(new ArcDegreePanel(false));
    }
}   // end class ArcCard


class ArcDegreePanel extends Panel {
    boolean filled;

    public ArcDegreePanel(boolean filled) {
        this.filled = filled;
    }

    void arcSteps(Graphics g,
                  int step,
                  int x,
                  int y,
                  int w,
                  int h,
                  Color c1,
                  Color c2) {
    int a1 = 0;
    int a2 = step;
    int progress = 0;
    g.setColor(c1);
    for (; (a1+a2) <= 360; a1 = a1+a2, a2 += 1) {
        if (g.getColor() == c1) {
            g.setColor(c2);
        }
        else {
            g.setColor(c1);
        }

        if (filled) {
            g.fillArc(x, y, w, h, a1, a2);
        }
        else {
            g.drawArc(x, y, w, h, a1, a2);
        }

        progress = a1+a2;
      }  // end for

    if (progress != 360) {
          if (filled) {
            g.fillArc(x, y, w, h, a1, 360 - progress);
          }
        else {
            g.drawArc(x, y, w, h, a1, 360 - progress);
        }
      }  // end if
  }  // end arcSteps()

    public void paint(Graphics g) {
        Rectangle r = getBounds();

        arcSteps(g, 3, 0, 0, r.width, r.height, Color.orange, Color.blue);

        arcSteps(g,
                 2,
                 r.width / 4,
                 r.height / 4,
                 r.width / 2,
                 r.height / 2,
                 Color.yellow,
                 Color.green);

        arcSteps(g,
                 1,
                 (r.width  * 3) / 8,
                 (r.height * 3) / 8,
                 r.width / 4,
                 r.height / 4,
                 Color.magenta,
                 Color.white);

  }  // end paint()
}   // end class ArcDegreePanel


class ArcPanel extends Panel {
    boolean filled;

    public ArcPanel(boolean filled) {
    this.filled = filled;
  }

  public void paint(Graphics g)
  {
    Rectangle r = getBounds();

    g.setColor(Color.yellow);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, 0, 45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, 0, 45);
      }

    g.setColor(Color.green);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, 90, -45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, 90, -45);
      }

    g.setColor(Color.orange);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, 135, -45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, 135, -45);
      }

    g.setColor(Color.magenta);

    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, -225, 45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, -225, 45);
      }

    g.setColor(Color.yellow);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, 225, -45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, 225, -45);
      }

    g.setColor(Color.green);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, -135, 45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, -135, 45);
      }

    g.setColor(Color.orange);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, -45, -45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, -45, -45);
      }

    g.setColor(Color.magenta);
    if (filled)
      {
        g.fillArc(0, 0, r.width, r.height, 315, 45);
      }
    else
      {
        g.drawArc(0, 0, r.width, r.height, 315, 45);
      }

  }  // end paint()

}   // end class ArcPanel


abstract class Shape
{
  abstract void draw(Graphics g, int x, int y, int w, int h);
  abstract void fill(Graphics g, int x, int y, int w, int h);
}


class RectShape extends Shape
{
  void draw(Graphics g, int x, int y, int w, int h)
  {
    g.drawRect(x, y, w, h);
  }

  void fill(Graphics g, int x, int y, int w, int h)
  {
    g.fillRect(x, y, w, h);
  }
}


class OvalShape extends Shape
{
  void draw(Graphics g, int x, int y, int w, int h)
  {
    g.drawOval(x, y, w, h);
  }

  void fill(Graphics g, int x, int y, int w, int h)
  {
    g.fillOval(x, y, w, h);
  }
}


class RoundRectShape extends Shape
{
  void draw(Graphics g, int x, int y, int w, int h)
  {
    g.drawRoundRect(x, y, w, h, 10, 10);
  }

  void fill(Graphics g, int x, int y, int w, int h)
  {
    g.fillRoundRect(x, y, w, h, 10, 10);
  }
}

class PolygonShape extends Shape
{
  // class variables
  Polygon p;
  Polygon pBase;

  public PolygonShape()
  {
    pBase = new Polygon();
    pBase.addPoint(0, 0);
    pBase.addPoint(10, 0);
    pBase.addPoint(5, 15);
    pBase.addPoint(10, 20);
    pBase.addPoint(5, 20);
    pBase.addPoint(0, 10);
    pBase.addPoint(0, 0);
  }

  void scalePolygon(float w, float h)
  {
    p = new Polygon();
    for (int i = 0; i < pBase.npoints; ++i)
      {
        p.addPoint( (int) (pBase.xpoints[i] * w),
                    (int) (pBase.ypoints[i] * h) );
      }

  }

  void draw(Graphics g, int x, int y, int w, int h)
  {
    Graphics ng = g.create();
    try {
        ng.translate(x, y);
        scalePolygon( (float) ( (float) w / (float) 10 ),
                      (float) ( (float) h / (float) 20 ) );
        ng.drawPolygon(p);
    } finally {
        ng.dispose();
    }
  }

  void fill(Graphics g, int x, int y, int w, int h)
  {
    Graphics ng = g.create();
    try {
        ng.translate(x, y);
        scalePolygon( (float) ( (float) w / (float) 10 ),
                      (float) ( (float) h / (float) 20 ) );
        ng.fillPolygon(p);
    } finally {
        ng.dispose();
    }
  }
}


class ShapeTest extends Panel
{
  Shape   shape;
  int       step;

  public ShapeTest(Shape shape, int step)
  {
    this.shape = shape;
    this.step = step;
  }

  public ShapeTest(Shape shape)
  {
    this(shape, 10);
  }

    public void paint(Graphics g) {
        Rectangle bounds = getBounds();

        int cx, cy, cw, ch;

        Color color;

        for (color=Color.red,
                 cx=bounds.x,
                 cy=bounds.y,
                 cw=bounds.width / 2,
                 ch=bounds.height;
             cw > 0 && ch > 0;

             cx+=step,
                 cy += step,
                 cw -= (step * 2),
                 ch -= (step * 2),
                 color=ColorUtils.darker(color, 0.9) ) {
            g.setColor(color);
            shape.draw(g, cx, cy, cw, ch);
        }

        for (cx=bounds.x + bounds.width / 2,
                 cy=bounds.y,
                 cw=bounds.width / 2, ch=bounds.height;
             cw > 0 && ch > 0;

             cx+=step,
                 cy += step,
                 cw -= (step * 2),
                 ch -= (step * 2) ) {
            if (g.getColor() == Color.red) {
                g.setColor(Color.blue);
            }
            else {
                g.setColor(Color.red);
            }

            shape.fill(g, cx, cy, cw, ch);
        }  // end for
    }  // end paint()
}   // end class ShapeTest

class ColorUtils {
    static Color brighter(Color c, double factor) {
        return new Color( Math.min((int)(c.getRed()  *(1/factor)), 255),
                          Math.min((int)(c.getGreen()*(1/factor)), 255),
                          Math.min((int)(c.getBlue() *(1/factor)), 255) );
    }

    static Color darker(Color c, double factor) {
        return new Color( Math.max((int)(c.getRed()  *factor), 0),
                          Math.max((int)(c.getGreen()*factor), 0),
                          Math.max((int)(c.getBlue() *factor), 0) );
    }
}
