import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.geom.*;
import javax.swing.*;

/* <applet code="IlexCornuta.class" width=800 height=600></applet> */

public class IlexCornuta extends Applet {
	private static final int WINDOW_W = 800, WINDOW_H = 600;
	
	private static final Dimension2D D_DEF_LEAF = new Dimension(100, 40);
	private static final Color C_DEF_LEAF = new Color(0.0f, 0.4f, 0.2f);
	private static final Color C_DEF_VEIN = new Color(0.0f, 0.6f, 0.1f);
	private static final Color C_DEF_STALK = new Color(0.2f, 0.5f, 0.0f);
	private static final Color C_DEF_BERRY = new Color(0.75f, 0.2f, 0.0f);
	private static final Color C_DEF_BERRY_STALK = new Color(0.3f, 0.7f, 0.2f);
	private static final Color C_DEF_BG = new Color(0.0f, 0.0f, 0.2f);
	private static final float DEF_STALK_L = 150.0f, DEF_STALK_W = 5.0f;
	private static final float DEF_BERRY_L = 30.0f, DEF_BERRY_W = 2.5f, DEF_BERRY_S = 15.0f;
	private static final int DEF_LEAF_NUM = 3, DEF_BERRY_NUM = 5;
	private static final int DEF_RING_LEAF_NUM = 18;
	private static final double DEF_LEAF_R = 96.0, DEF_RING_R = 300.0;
	private static final boolean IS_DEF_SMOOTH = true, IS_DEF_RANDOM = false;
	
	private ICPanel icPanel;
	private ICLeaf icLeaf;
	
	private int ringLeafNum;
	private double ringR;
	
	public IlexCornuta() {
		icPanel = new ICPanel();
		icLeaf = new ICLeaf();
		
		JToolBar tbMain = new JToolBar();
		final ICTextField tfLeafN = new ICTextField(Integer.toString(DEF_LEAF_NUM));
		final ICTextField tfLeafW = new ICTextField(Double.toString(D_DEF_LEAF.getHeight()));
		final ICTextField tfLeafL = new ICTextField(Double.toString(D_DEF_LEAF.getWidth()));
		final ICTextField tfLeafR = new ICTextField(Double.toString(DEF_LEAF_R));
		final ICTextField tfStalkW = new ICTextField(Float.toString(DEF_STALK_W));
		final ICTextField tfStalkL = new ICTextField(Float.toString(DEF_STALK_L));
		final ICTextField tfBerryN = new ICTextField(Integer.toString(DEF_BERRY_NUM));
		final ICTextField tfBerryS = new ICTextField(Float.toString(DEF_BERRY_S));
		final ICTextField tfBerryW = new ICTextField(Float.toString(DEF_BERRY_W));
		final ICTextField tfBerryL = new ICTextField(Float.toString(DEF_BERRY_L));
		
		tbMain.add(new ICLabel("葉の枚数/幅/長さ/角"));
		tbMain.add(tfLeafN);
		tbMain.add(tfLeafW);
		tbMain.add(tfLeafL);
		tbMain.add(tfLeafR);
		tbMain.addSeparator();
		tbMain.add(new ICLabel("茎の幅/長さ"));
		tbMain.add(tfStalkW);
		tbMain.add(tfStalkL);
		tbMain.addSeparator();
		tbMain.add(new ICLabel("実の数/大きさ/茎の幅/長さ"));
		tbMain.add(tfBerryN);
		tbMain.add(tfBerryS);
		tbMain.add(tfBerryW);
		tbMain.add(tfBerryL);
		
		JToolBar tbSecond = new JToolBar();
		final ICTextField tfRingN = new ICTextField(Integer.toString(DEF_RING_LEAF_NUM));
		final ICTextField tfRingR = new ICTextField(Double.toString(DEF_RING_R));
		final JButton bLeafC = new ICColorButton("葉の色", C_DEF_LEAF);
		final JButton bVeinC = new ICColorButton("脈の色", C_DEF_VEIN);
		final JButton bStalkC = new ICColorButton("茎の色", C_DEF_STALK);
		final JButton bBerryC = new ICColorButton("実の色", C_DEF_BERRY);
		final JButton bBerryStalkC = new ICColorButton("茎の色", C_DEF_BERRY_STALK);
		final JButton bBGC = new ICColorButton("背景色", C_DEF_BG);
		final JCheckBox cbSmooth = new JCheckBox("スムース", IS_DEF_SMOOTH);
		final JCheckBox cbRandom = new JCheckBox("ランダム", IS_DEF_RANDOM);
		
		tbSecond.add(new ICLabel("リースの分割数/半径"));
		tbSecond.add(tfRingN);
		tbSecond.add(tfRingR);
		tbSecond.addSeparator();
		tbSecond.add(bLeafC);
		tbSecond.add(bVeinC);
		tbSecond.add(bStalkC);
		tbSecond.add(bBerryC);
		tbSecond.add(bBerryStalkC);
		tbSecond.add(bBGC);
		tbSecond.addSeparator();
		tbSecond.add(cbSmooth);
		tbSecond.add(cbRandom);
		tbSecond.addSeparator();
		tbSecond.add(new AbstractAction("　更新　") {
			public void actionPerformed(ActionEvent e) {
				icLeaf.setStalk(bStalkC.getBackground(), tfStalkL.getFloat(), tfStalkW.getFloat());
				icLeaf.setLeaf(tfLeafN.getInteger(), bLeafC.getBackground(), bVeinC.getBackground(), new Dimension((int) tfLeafL.getFloat(), (int) tfLeafW.getFloat()), tfLeafR.getDouble());
				icLeaf.setBerry(tfBerryN.getInteger(), bBerryC.getBackground(), bBerryStalkC.getBackground(), tfBerryS.getFloat(), tfBerryL.getFloat(), tfBerryW.getFloat());
				icLeaf.setRandom(cbRandom.isSelected());
				setRing(tfRingN.getInteger(), tfRingR.getDouble());
				icPanel.setBackground(bBGC.getBackground());
				icPanel.drawTexture(bBGC.getBackground(), cbSmooth.isSelected());
			}
		});
		
		Panel pToolBar = new Panel(new GridLayout(2, 1));
		pToolBar.add(tbMain);
		pToolBar.add(tbSecond);
		
		setLayout(new BorderLayout());
		add(icPanel, BorderLayout.CENTER);
		add(pToolBar, BorderLayout.NORTH);
		
		icLeaf.setStalk(C_DEF_STALK, DEF_STALK_L, DEF_STALK_W);
		icLeaf.setLeaf(DEF_LEAF_NUM, C_DEF_LEAF, C_DEF_VEIN, D_DEF_LEAF, DEF_LEAF_R);
		icLeaf.setBerry(DEF_BERRY_NUM, C_DEF_BERRY, C_DEF_BERRY_STALK, DEF_BERRY_S, DEF_BERRY_L, DEF_BERRY_W);
		icLeaf.setRandom(IS_DEF_RANDOM);
		setRing(DEF_RING_LEAF_NUM, DEF_RING_R);
		
		icPanel.drawTexture(C_DEF_BG, IS_DEF_SMOOTH);
	}
	
	private void setRing(int n, double r) {
		ringLeafNum = n;
		ringR = r;
	}
	
	class ICPanel extends Panel {
		private BufferedImage iOff;
		private Graphics2D gOff;
		
		public ICPanel() {
			iOff = new BufferedImage(WINDOW_W, WINDOW_H, BufferedImage.TYPE_INT_RGB);
			gOff = iOff.createGraphics();
		}
		
		protected void drawTexture(Color c, boolean isSmooth) {
			setBackground(c);
			setSmooth(isSmooth);
			drawTexture(gOff);
		}
		
		protected void drawTexture(Graphics2D g) {
			AffineTransform at = g.getTransform();
			
			g.setPaint(getBackground());
			g.fillRect(0, 0, WINDOW_W, WINDOW_H);
			
			double tx = ringR, ty = ringR;
			double w = WINDOW_W + tx * 2.0, h = WINDOW_H + ty * 2.0;
			for (int x = 0; x <= w / tx; x++) {
				for (int y = 0; y <= h / ty; y++) {
					if ((x + y) % 2 != 0) continue;
					
					g.transform(new AffineTransform(1.0, 0.0, 0.0, 1.0, (x - 1) * tx, (y - 1) * ty));
					double r = Math.PI * 2.0 / ringLeafNum;
					for (int n = 0; n < ringLeafNum; n++) {
						double txR = Math.sqrt(
							Math.pow(Math.sin(Math.PI * 2.0 / ringLeafNum) * ringR, 2) + 
							Math.pow(ringR - Math.cos(Math.PI * 2.0 / ringLeafNum) * ringR, 2)
						);
						g.transform(new AffineTransform(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), Math.cos(r) * txR, Math.sin(r) * txR));
						icLeaf.fill(g);
					}
					g.setTransform(at);
				}
			}
			
			g.setTransform(at);
			repaint();
		}
		
		public void paint(Graphics g) {
			g.drawImage(iOff, 0, 0, this);
		}
		
		public void update(Graphics g) {
			paint(g);
		}
		
		protected void setSmooth(boolean isSmooth) {
			gOff.setRenderingHint(RenderingHints.KEY_ANTIALIASING, isSmooth ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF);
		}
	}
	
	class ICLabel extends JLabel {
		public ICLabel(String szText) {
			super(szText, Label.RIGHT);
		}
	}
	
	class ICColorButton extends JButton implements ActionListener {
		public ICColorButton(String szLabel, Color c) {
			super(szLabel);
			setForeground(Color.WHITE);
			setBackground(c);
			addActionListener(this);
		}
		
		public void actionPerformed(ActionEvent e) {
			Color c = JColorChooser.showDialog(null, null, getBackground());
			if (c == null) return;
			setBackground(c);
		}
	}
	
	class ICTextField extends JTextField {
		public ICTextField(String szText) {
			super(szText);
		}
		
		public int getInteger() {
			return Integer.parseInt(getText());
		}
		
		public double getDouble() {
			return Double.parseDouble(getText());
		}
		
		public float getFloat() {
			return Float.parseFloat(getText());
		}
	}
}

class ICLeaf {
	private static final float LEAF_FRAME_W = 1.0f;
	
	private GeneralPath gpLeaf;
	private RectangularShape sBerry;
	private Line2D lStalk, lLeaf, lBerry;
	private Color cLeaf, cVein, cStalk, cBerry, cBerryStalk;
	private float stalkL, stalkW;
	private float berryL, berryW;
	private int leafNum, berryNum;
	private double leafR;
	private boolean isRandom;
	
	public ICLeaf() {
		gpLeaf = new GeneralPath();
		sBerry = new Ellipse2D.Float();
		lStalk = new Line2D.Float();
		lLeaf = new Line2D.Float();
		lBerry = new Line2D.Float();
	}
	
	public void fill(Graphics2D g) {
		AffineTransform at = g.getTransform();
		
		g.setPaint(cStalk);
		g.setStroke(new BasicStroke(stalkW));
		g.draw(lStalk);
		
		for (int n = 0; n < berryNum; n++) {
			AffineTransform atBerry = g.getTransform();
			
			double r = getBerryR(isRandom ? Math.random() * berryNum : n, berryNum);
			g.transform(new AffineTransform(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0.0, 0.0));
			
			g.setPaint(cBerryStalk);
			g.setStroke(new BasicStroke(berryW));
			g.draw(lBerry);
			
			g.setPaint(cBerry);
			g.fill(sBerry);
			g.setTransform(atBerry);
		}
		
		g.setStroke(new BasicStroke(LEAF_FRAME_W));
		for (int n = 0; n < leafNum; n++) {
			AffineTransform atLeaf = g.getTransform();
			
			double r = getLeafR((isRandom ? Math.random() * (leafNum - 1.0) : n), leafNum);
			g.transform(new AffineTransform(Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0.0, 0.0));
			
			g.setPaint(cLeaf);
			g.fill(gpLeaf);
			
			g.setPaint(cVein);
			g.draw(gpLeaf);
			g.draw(lLeaf);
			
			g.setTransform(atLeaf);
		}
		
		g.setTransform(at);
	}
	
	private double getBerryR(double n, int bNum) {
		return Math.PI * 2.0 * ((bNum % 2 == 0 || bNum == 3 ? n + 0.5 : n) / bNum);
	}
	
	private double getLeafR(double n, int lNum) {
		if (lNum == 1) return 0.0;
		return Math.PI * leafR / 180.0 * ((n / (lNum - 1.0)) - 0.5);
	}
	
	public void setStalk(Color c, float l, float w) {
		lStalk.setLine(-l, 0.0f, 0.0f, 0.0f);
		cStalk = c;
		stalkL = l;
		stalkW = w;
	}
	
	public void setLeaf(int n, Color cl, Color cv, Dimension2D d, double r) {
		float w = (float) d.getWidth(), h = (float) d.getHeight();
		gpLeaf.reset();
		gpLeaf.moveTo(0.0f, 0.0f);
		gpLeaf.quadTo(w * 0.25f, h * 0.25f, w * 0.25f, h * 0.50f);
		gpLeaf.quadTo(w * 0.50f, h * 0.25f, w * 0.75f, h * 0.50f);
		gpLeaf.quadTo(w * 0.75f, h * 0.25f, w * 1.00f, h * 0.00f);
		gpLeaf.quadTo(w * 0.75f, h * -0.25f, w * 0.75f, h * -0.5f);
		gpLeaf.quadTo(w * 0.50f, h * -0.25f, w * 0.25f, h * -0.5f);
		gpLeaf.quadTo(w * 0.25f, h * -0.25f, w * 0.00f, h * 0.00f);
		gpLeaf.closePath();
		
		lLeaf.setLine(0.0f, 0.0f, w * 0.75f, 0.0f);
		
		leafNum = n;
		leafR = r;
		cLeaf = cl;
		cVein = cv;
	}
	
	public void setBerry(int n, Color cb, Color cs, float s, float l, float w) {
		lBerry.setLine(-l, 0.0f, 0.0f, 0.0f);
		berryNum = n;
		cBerry = cb;
		cBerryStalk = cs;
		sBerry.setFrame(-s / 2.0f - l, -s / 2.0f, s, s);
		berryL = l;
		berryW = w;
	}
	
	public void setRandom(boolean v) {
		isRandom = v;
	}
	
	public Color getLeafColor() {
		return cLeaf;
	}
	
	public Color getVeinColor() {
		return cVein;
	}
	
	public Color getStalkColor() {
		return cStalk;
	}
	
	public Color getBerryColor() {
		return cBerry;
	}
	
	public Color getBerryStalkColor() {
		return cBerryStalk;
	}
}