import java.applet.*;
import java.awt.*;
import java.awt.event.*;

/*
<applet code="Bezier.class" width=800 height=800>
</applet>
*/

public class m0104229 extends Applet
{
    static int WIDTH=800, HEIGHT=800;        // 画面サイズ
    Point point[][];                 // 制御点
    int point_num = 0;               // 制御点の番号
    int captured_point = -1;         // つかんでいる制御点の番号
                                     //（-1のときつかんでいない）
    boolean capture_mode_FLG;        // 線を制御できるかを表すフラグ
    static final int point_data[][][] =    // 点情報
        {
            { {353, 230}, {310,250}, {290,250}, },
            { {290,250}, {320,250}, {280,270}, },
            { {280,270}, {285,275}, {290,280}, },
            { {290,280}, {260,280}, {240,300}, },
            { {240,300}, {245,290}, {270,300}, },
            { {270,300}, {260,300}, {255,320}, },
            { {255,320}, {260,317}, {265,317}, },
            { {265,317}, {235,340}, {225,370}, },
            { {225,370}, {225,370}, {240,365}, },
            { {240,365}, {230,365}, {230,420}, },
            { {230,420}, {230,420}, {239,415}, },
            { {240,415}, {239,420}, {235,465}, },
            { {235,465}, {235,465}, {243,460}, },
            { {243,460}, {242,465}, {240,490}, },
            { {240,490}, {240,490}, {247,485}, },
            { {247,485}, {240,510}, {220,520}, },

			{ {220,520}, {220,520}, {260,500}, },
			{ {260,500}, {260,500}, {257,507}, },
			{ {257,507}, {285,500}, {287,493}, },
			{ {287,493}, {287,510}, {285,499}, },
			{ {285,499}, {300,495}, {315,480}, },
			{ { 315,480}, {315,480}, {317,490}, },
			{ {317,490}, {340,460}, {343,450}, },
			{ {343,450}, {343,440}, {347,456}, },
			{ {347,456}, {350,465}, {375,410}, },
			{ {375,410}, {375,405}, {380,425}, },
			{ {380,425}, {385,415}, {390,360}, },
			{ {390,360}, {390,350}, {400,367}, },
			{ {400,367}, {400,310}, {395,315}, },
			{ {395,315}, {395,315}, {403,313}, },
            { {403,313}, {400,290}, {388,270}, },
            { {388,270}, {394,280}, {400,263}, },
            { {400,263}, {375,260}, {353,230}, },

            { {353,230}, {350,350}, {230,515}, },

            { {342,299}, {320,290}, {285,304}, },
            { {340,299}, {355,295}, {385,345}, },
            { {325,350}, {290,340}, {255,360}, },
            { {325,350}, {350,370}, {367,400}, },
            { {308,385}, {285,380}, {245,412}, },
            { {308,385}, {320,380}, {343,445}, },

            { {450, 200}, {450,190}, {420,260}, },
            { {420,260}, {420,255}, {435,255}, },
            { {435,255}, {435,285}, {439,315}, },
            { {439,315}, {439,307}, {450,307}, },
            { {450,307}, {453,340}, {455,360}, },
            { {455,360}, {455,350}, {462,350}, },
            { {462,350}, {470,380}, {485,410}, },
            { {485,410}, {485,405}, {493,405}, },
            { {493,405}, {493,445}, {520,465}, },
            { {520,465}, {520,460}, {528,458}, },
            { {528,458}, {528,458}, {535,490}, },
            { {535,490}, {535,485}, {540,485}, },//kubire
            { {540,485}, {540,490}, {545,505}, },
            { {545,505}, {555,490}, {575,530}, },

          	{ {575,530}, {580,490}, {590,495}, },
			{ {590,495}, {590,475}, {585,475}, },
			{ {585,475}, {590,470}, {590,473}, }, //kubire
			{ {590,473}, {585,440}, {575,440}, },
			{ {575,440}, {580,435}, {585,435}, },
			{ {585,435}, {578,400}, {565,375}, },
			{ {565,375}, {565,370}, {575,370}, },
			{ {575,370}, {570,350}, {555,315}, },
			{ {555,315}, {560,312}, {565,318}, },
			{ {565,318}, {545,280}, {530,270}, },
			{ {530,270}, {540,260}, {540,267}, },
			{ {540,267}, {525,240}, {510,230}, },
			{ {510,230}, {515,220}, {520,220}, },
			{ {520,220}, {480,200}, {450,200}, },

            { {450,200}, {520,350}, {575,530}, },

            { {465,235}, {450,260}, {448,288}, },
            { {465,235}, {474,220}, {520,263}, },
            { {483,280}, {468,310}, {462,345}, },
            { {482,280}, {510,270}, {550,310}, },
            { {505,325}, {485,340}, {495,400}, },
            { {505,325}, {530,320}, {560,375}, },
            { {525,380}, {520,420}, {525,450}, },
            { {525,380}, {550,400}, {570,435}, },

            { {450,200}, {430,180}, {400,170}, },
            { {353,230}, {380,200}, {400,170}, },
            { {400,170}, {400,170}, {400,0}, },

            };

    Label tf;

    Graphics offg, backg;
    Image    offi, backi;

    public void initialize()                   // 制御点の設定
    {
        int i;
        point = new Point[point_data.length][];

        for(i = 0; i < point.length; i++)
        {
            point[i] = new Point[point_data[i].length];
            for(int j = 0; j < point_data[i].length; j++)
                point[i][j] = new Point(point_data[i][j][0],
                                        point_data[i][j][1]);
        }
    }

    public void init()
    {
        Dimension d = getSize();
        d.width=WIDTH; d.height=HEIGHT;

        Button increment, decrement, modify;
        increment = new Button("increment");          // 画面設定
        decrement = new Button("decrement");
        modify = new Button("modify");
        tf = new Label(Integer.toString(point_num));
        add(modify);
        add(increment);
        add(decrement);
        add(tf);

        increment.addActionListener(new ActionListener() // 制御点番号を増やす
        {
            public void actionPerformed(ActionEvent ae)
            {
                point_num++;
                if(point_num >= point.length)
                    point_num = 0;
                tf.setText(Integer.toString(point_num));
                repaint();
            }
        });

        decrement.addActionListener(new ActionListener()  // 制御点番号を減らす
        {
            public void actionPerformed(ActionEvent ae)
            {
                point_num--;
                if(point_num < 0) point_num = point.length-1;
                tf.setText(Integer.toString(point_num));
                repaint();
            }
        });

        modify.addActionListener(new ActionListener()  // モード変更
        {
            public void actionPerformed(ActionEvent ae)
            {
                capture_mode_FLG = !capture_mode_FLG;
                repaint();
            }
        });

        addMouseListener(new MouseAdapter()
        {
            public void mousePressed(MouseEvent me)    // 制御点をつかむ
            {
                int i, mx = me.getX(), my = me.getY();
                for(i = 0; i < point[point_num].length; i++)
                {
                    if(point[point_num][i].x-3 <= mx &&
                       point[point_num][i].x+3 >= mx &&
                       point[point_num][i].y-3 <= my &&
                       point[point_num][i].y+3 >= my)
                        break;
                }
                if(i < point[point_num].length) captured_point = i;
            }

            public void mouseReleased(MouseEvent me)
            {
                captured_point = -1;
            }
        });

        addMouseMotionListener(new MouseMotionAdapter() // 制御点を動かす
        {
            public void mouseDragged(MouseEvent me)
            {
                if(captured_point == -1) return;
                point[point_num][captured_point].setLocation(me.getX(), me.getY());
                repaint();
            }
        });

        initialize();

        offi = createImage(WIDTH, HEIGHT);
        offg = offi.getGraphics();
        backi = createImage(WIDTH, HEIGHT);
        backg = backi.getGraphics();
        setBackImage(backg);

     // test!
        addKeyListener(new KeyAdapter()
        {
            public void keyPressed(KeyEvent ke)
            {
                int c = ke.getKeyCode();
                if(c == 'P')
                {
                    System.out.println("{");
                    for(int i = 0; i < point[point_num].length; i++)
                        System.out.println(""+point[point_num][i].x
                                        +", "+point[point_num][i].y);
                    System.out.println("},");
                }
                else if(c == 'B')
                {
                    // BezierCurve(backg, Color.black);
                    repaint();
                }
            }
        });
    }

    public void setBackImage(Graphics g)    // 背景の用意
    {
        g.setColor(Color.white);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.black);
        g.drawRect(0, 0, WIDTH-1, HEIGHT-1);  // 枠描画
    }

    public int kaijyo(int num)            // 階乗を計算
    {
        int total = 1;

        if(num == 0) return 1;

        for(; num > 1; num--)
            total *= num;
        return total;
    }

    public void BezierCurve(Graphics g, Color color, Point point[])  // 曲線描画
    {
        int i, j;
        double x1, x2, y1, y2;
        double bernstein[] = new double[point.length];
        x1 = point[0].x;
        y1 = point[0].y;

        g.setColor(color);

        for(double t = 0; t <= 1; t += 0.01)
        {
            for(i = 0; i < point.length; i++)        // bernstein関数を計算
            {
                bernstein[i] = (double)kaijyo(point.length-1)
                            / (kaijyo(i)*kaijyo(point.length-1-i));

                for(j = 1; j <= i; j++) bernstein[i] *= t;
                for(j = 1; j <= point.length-1-i; j++) bernstein[i] *= (1-t);
            }

            x2 = y2 = 0;
            for(i = 0; i < point.length; i++)
            {
                x2 += point[i].x * bernstein[i];
                y2 += point[i].y * bernstein[i];
            }

            g.drawLine((int)x1, (int)y1, (int)x2, (int)y2);
            x1 = x2;
            y1 = y2;
        }
    }

    public void paint(Graphics g)
    {
        requestFocus();
        offg.drawImage(backi, 0, 0, this);  // 背景の描画

        if(capture_mode_FLG)           // 制御点の描画
        {
            offg.setColor(Color.red);
            for(int i = 0; i < point[point_num].length; i++)
            {
                offg.fillRect(point[point_num][i].x-3,
                              point[point_num][i].y-3, 7, 7);
                offg.drawString(Integer.toString(i+1),
                              point[point_num][i].x-3,
                              point[point_num][i].y-6);
            }
        }

        for(int i = 0; i < point.length; i++)     // 曲線描画
        {
            if(capture_mode_FLG && point_num == i)
                BezierCurve(offg, Color.blue, point[i]);
            else BezierCurve(offg, Color.black, point[i]);
        }

        g.drawImage(offi, 0, 0, this);
    }

    public void update(Graphics g)
    {
        paint(g);
    }
}
