import java.applet.*;
import java.awt.*;
import java.awt.event.*;

/*
<applet code="bezierTucan.class" width=480 height=480>
</applet>
*/

public class bezierTucan extends Applet
{
    static int WIDTH, HEIGHT;        // 画面サイズ
    Point point[][];                 // 制御点
    int point_num = 0;               // 制御点の番号
    int captured_point = -1;         // つかんでいる制御点の番号
                                     //（-1のときつかんでいない）
    boolean capture_mode_FLG;        // 線を制御できるかを表すフラグ

    static final int point_data[][][] =    // 点情報
        {
     	
/*--  pico --*/ 
        
		{ {311,58}, {375,52}, {409,96}, {397,145}, },   // pico 1
		//{ {349,61}, {378,70}, {395,99}, {399,140}, },   
		{ {397,145}, {395,167}, {385,186}, {368,198}, },   

                { {311,58}, {299,64}, {286,82}, {281,96}, },  
		{ {281,96}, {307,101}, {336,121}, {354,148}, },

		{ {354,148}, {366,163}, {371,183}, {368,199}, },   
		{ {354,148}, {355,111}, {397,108}, {397,145}, },

		{ {291,143}, {317,142},{357,163},{368,192}, },  
		{ {281,96}, {286,109}, {281,126}, {291,143}},  

		{ {311,57}, {306,57}, {303,62}, {297,63},},  
		{ {297,63}, {289,74}, {283,84}, {277,96}, },
		{ {277,96}, {267,105}, {266,118}, {291,143}, },  

/*-- cabeza  --*/

		{ {311,57}, {304,54}, {297,54}, {292,58}, },  // cabeza
		{ {300,60}, {290,54}, {279,57}, {276,64}, },  
		{ {275,63}, {248,79}, {216,116}, {203,134}, },  


/*-- pecho  --*/

		{ {276,64}, {269,75}, {262,81}, {251,85}, },  // pecho
                { {251,85}, {236,92}, {233,116}, {224,129}, },
                { {224,129},{222,137},{218,136}, {216,146}, },  

                { {216,143},{210,194},{261,216},{291,192}},   
                { {291,192},{294,188},{291,177},{306,146}},     

/*-- ojos --*/

                { {275,72},{281,60},{289,64},{284,76}},     
                { {275,72},{267,84},{275,88},{284,76}},     
                        
                { {276,72}, {280,66}, {285,69}, {282,75} , },                       
                { {276,72}, {272,78},{277,81}, {282,75} , },

/*--  cuello  --*/

                { {203,134}, {196,136},{192,139}, {188,142} , },
                { {188,142}, {177,142} , },

/*--  Ala izq  --*/

                { {181,149}, {179,135},{161,129} ,{150,142}, },
                { {150,142}, {144,143},{132,168}, {133,181} , }, 

/*--  Ala der  --*/

                { {295,171}, {300,176}, {306,178}, {311,178},  },    // alas
        	{ {311,178}, {317,172}, {326,174}, {328,180},  },
		{ {328,180}, {336,193}, {331,209}, {325,213},},
        	{ {325,213}, {315,225}, {310,240}, {297,265}, },

/*-- Ramas --*/

        	{ {53,148}, {109,169},{162,191},{209,220},},
                { {209,220}, {229,229},{249,239},{266,249}, },
                { {291,265}, {305,270}, {321,275}, {334,282}, },
                { {2,208}, {52,230}, {108,251},{150,266}, },
                { {150,266}, {223,304}, {278,328},{314,349}, },

/*  -- patitas --  */

                { {186,205}, {197,197},{201,198},{204,203}, },
                { {204,203}, {204,205},{205,207},{208,211},  }, 
                { {208,211}, {205,212},{197,211},{192,209},  },
                { {204,203}, {211,202}, {214,206},{213,216}, },
                { {206,210}, {209,208},{209,208},{213,216}, },

               
                { {149,265}, {148,280}, {152,280},{158,270}, },
                { {149,274}, {146,278}, {147,284},{155,285}, }, 
                { {155,285}, {151,278}, {152,282},{153,275}, },  


                { {263,248}, {268,245},{270,246},{274,247},  },  
                { {274,247}, {271,248},{270,252},{271,256},  },  
                { {271,256}, {266,256}, {266,252},{266,250}, },

                { {274,248}, {279,251}, {282,254},{280,259},},
                { {271,254}, {276,255}, {279,257},{280,259},},  
                { {284,259}, {288,262}, {288,266},{289,270},},
                { {289,270}, {289,275}, {288,281}, {282,286}, },
                { {283,271}, {283,276}, {283,280}, {282,286}, },
                { {281,262}, {283,271}, },
                { {289,270}, {283,271},},
                { {284,259}, {285,256},{280,256}, {281,262},},

/*--  ala abajo  --*/

                { {126,256}, {129,283}, {133,300}, {140,320}, },
                { {140,320}, {146,328}, {150,328}, {152,323}, },
                { {218,327}, {223,334},{229,333},{250,316}, },

/*-- cola  --*/
                { {154,313}, {151,364}, },
                { {151,364}, {128,432}, },
                { {128,432}, {134,454}, {148,462}, {164,460}, },  
                { {164,460}, {186,468}, {204,458},{207,450}, },
                { {207,450}, {218,439}, {216,412}, {215,333}, },
                { {215,333}, {221,316},},

                { {170,325}, {161,351}, {158,382}, {156,421}, },                
                { {205,342}, {207,378}, {203,404}, {196,437}, },
                { {156,291}, {180,303}, {201,309}, {218,305}, },

                //{ {156,291}, {156,315},},
                
                //{ {156,315}, {171,317}, {177,325}, {186,342}, },                
               // { {218,305}, {218,323}, {219,336}, {201,349}, },

                
           };
    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();
        WIDTH = d.width; HEIGHT = d.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.pink);//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);
    }
}


