import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import java.util.Vector;
import java.io.*;
import javax.swing.filechooser.*;
import java.awt.Cursor.*;
import java.io.File;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;

public class JavaPaint extends Frame {

    JFileChooser chooser;
    String Fig,Fic;
    Choice lb = new Choice();
    Vector temp = new Vector();
    DrawPanel panel;
    Checkbox check= new Checkbox();
    Button couleur;
    Label X,Y;

    public JavaPaint() {
        super("JavaPaint");
        WindowAdapter wa=new WindowAdapter()
        {
            public void windowClosing(WindowEvent we)
            {
                int reponse = getSortie();
                if(reponse==JOptionPane.YES_OPTION)
                {   int retour = getCloseVal();
                    if(retour == JFileChooser.APPROVE_OPTION)
                    {
                        Fic = chooser.getSelectedFile().getPath();
                        try
                        {
                            FileOutputStream ostream = new FileOutputStream(Fic);
                            ObjectOutputStream objout = new ObjectOutputStream(ostream);
                            objout.writeObject(panel.forme);
                            ostream.close();
                            System.exit(0);
                        }
                        catch(IOException exep)
                        {
                            System.out.println(exep);
                            System.exit(1);
                        }
                    }
                }
                else if(reponse == JOptionPane.NO_OPTION)
                {
                    System.exit(0) ;
                }
            }
        };
	addWindowListener(wa);

        Panel pan1= new Panel();

     /*   JMenuBar jm=new JMenuBar();
        JMenu Fic = new JMenu("Fichier");

        JMenuItem nouveau = new JMenuItem("Nouveau");
        JMenuItem charger = new JMenuItem("Charger");
        JMenuItem sauver = new JMenuItem("Sauver");

        Fic.add(nouveau);
        Fic.addSeparator();
        Fic.add(charger);
        Fic.add(sauver);
        jm.add(Fic);
        pan1.add(jm);*/

	panel = new DrawPanel();
        panel.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        Label coch;
        X= new Label("X:    ");
        Y= new Label("Y:    ");
        coch = new Label("Rempli");
	Button  effacer, quitter,save2file,undo,redo;
        Button charger, sauver;
	charger = new Button("Charger...");
	sauver = new Button("Sauver...");
        couleur = new Button("                          ");
	effacer = new Button("Nouveau");
        quitter = new Button("Quitter");
        save2file = new Button("Fichier");
        undo = new Button("Undo");
        redo = new Button("Redo");
        couleur.setBackground(panel.init);
        add("North",pan1);
        add("Center",panel);
        pan1.setBackground(Color.GRAY);
        pan1.add(charger);
	pan1.add(sauver);
	pan1.add(effacer);
        pan1.add(lb);
        pan1.add(check);
        pan1.add(coch);
        lb.add("Figure...");
        lb.add("Ligne");
        lb.add("Rectangle");
        lb.add("Carré");
        lb.add("Ovale");
        lb.add("Cercle");
        lb.add("HandWriting");
        pan1.add(couleur);
        pan1.add(undo);
        pan1.add(redo);
        pan1.add(quitter);
        pan1.add(X);
        pan1.add(Y);
        this.pack();
        this.setSize(800,600);
        this.setVisible(true);

        Fermer close = new Fermer();
        quitter.addActionListener(close);

        Dessiner draw = new Dessiner();
        lb.addItemListener(draw);

        Colorier color = new Colorier();
        couleur.addActionListener(color);

        Cocher coche = new Cocher();
        coch.addMouseListener(coche);

        Ouvrir open = new Ouvrir();
 	charger.addActionListener(open);

	Effacer delete = new Effacer();
       	effacer.addActionListener(delete);

        Sauver save = new Sauver();
        sauver.addActionListener(save);

        Sauver2 save2 = new Sauver2();
        save2file.addActionListener(save);

        Annuler annul = new Annuler();
        undo.addActionListener(annul);

        Refaire refait = new Refaire();
        redo.addActionListener(refait);

    }


    class DrawPanel extends Panel implements MouseListener, MouseMotionListener
    {
        public static final int RIEN = 0;
        public static final int POINT = 1;
        public static final int RECTANGLE = 2;
        public static final int OVALE = 3;
        public static final int CERCLE = 4;
        public static final int LIGNE = 5;
        public static final int CARRE = 6;
        int x1,y1,x2,y2;
        public int mode=RIEN;
        Color init;
        Vector forme = new Vector();

        DrawPanel()
	{
		setBackground(Color.WHITE);
		addMouseMotionListener(this);
		addMouseListener(this);
                init=Color.BLACK;
	}

        public void setMode(int m)
        {
            switch(m)
            {
                case LIGNE:
                case POINT:
                case RECTANGLE:
                case OVALE:
                case CERCLE:
                case RIEN:
                case CARRE:
                    mode=m;
                    break;
                default:
                    throw new IllegalArgumentException();
            }

        }

        public void mouseClicked(MouseEvent e)
        {

        }

        public void mouseDragged(MouseEvent e)
        {
            Graphics g=getGraphics();
            g.setColor(init);
            switch(mode)
            {
                case POINT:
                    Dessiner(x1,y1,e.getX(),e.getY(),0,0,mode,g,check.getState());
                    x1=e.getX();
                    y1=e.getY();
                    break;
                default:
                    g.setXORMode(Color.WHITE);
                    //Dessiner(x1,y1,x2-x1,y2-y1,mode,g,check.getState());
                    Dessiner(x1,y1,x2,y2,x2-x1,y2-y1,mode,g,check.getState());
                    x2=e.getX();
                    y2=e.getY();
                    //Dessiner(x1,y1,x2-x1,y2-y1,mode,g,check.getState());
                    Dessiner(x1,y1,x2,y2,x2-x1,y2-y1,mode,g,check.getState());
                    break;
            }
        }

        public void mouseEntered(MouseEvent e)
        {

        }

        public void mouseExited(MouseEvent e)
        {

        }

        public void mouseMoved(MouseEvent e)
        {
            X.setText("X: "+e.getX());
            Y.setText("Y: "+e.getY());
        }

        public void mousePressed(MouseEvent e)
        {
            x1=e.getX();
            y1=e.getY();
            x2=e.getX();
            y2=e.getY();
        }

        public void mouseReleased(MouseEvent e)
        {
            Graphics g= getGraphics();
            g.setColor(init);
            x2=e.getX();
            y2=e.getY();
            switch(mode)
            {
                case POINT:
                    break;
                default:
                    Dessiner(x1,y1,x2,y2,x2-x1,y2-y1,mode,g,check.getState());
                    Ajouter(min(x1,x2),min(y1,y2),abs(x2-x1),abs(y2-y1),mode,g);
                    System.out.println("x1:"+x1+" y1:"+y1+" x2:"+x2+" y2:"+y2+ "abs:"+abs(x2-x1));
                    break;
            }
        }

        public void paint(Graphics g)
        {
            super.paint(g);
            for(int i=0;i<forme.size();i++)
            {
                Figure f=(Figure)forme.elementAt(i);
		g.setColor(f.Couleur);
		Dessiner(f.x,f.y,abs(f.largeur+f.x),abs(f.hauteur+f.y),f.largeur,f.hauteur,f.forme,g,f.plein);
            }
         }

        public void Dessiner(int x,int y,int x2,int y2,int largeur,int hauteur,int type,Graphics g,boolean plein)
        {
            Figure f;
            if(!plein)
            {
                switch(type)
                {
                    case RECTANGLE:
                        if(x<x2)
                        {
                            if(y<y2)
                            {
                                g.drawRect(x,y,largeur,hauteur);
                            }
                            else
                            {
                                g.drawRect(x,y2,largeur,-hauteur);
                            }
                        }
                        else
                        {
                            if(y<y2)
                            {
                                g.drawRect(x2,y,-largeur,hauteur);
                            }
                            else
                            {
                                g.drawRect(x2,y2,-largeur,-hauteur);
                            }
                        }
                        break;
                    case LIGNE:
                        g.drawLine(x,y,largeur+x,hauteur+y);
                        break;
                    case OVALE:
                        if(x<x2)
                        {
                            if(y<y2)
                            {
                                g.drawOval(x,y,largeur,hauteur);
                            }
                            else
                            {
                                g.drawOval(x,y2,largeur,-hauteur);
                            }
                        }
                        else
                        {
                            if(y<y2)
                            {
                                g.drawOval(x2,y,-largeur,hauteur);
                            }
                            else
                            {
                                g.drawOval(x2,y2,-largeur,-hauteur);
                            }
                        }

                        break;
                    case POINT:
                        g.drawLine(x,y,x2,y2);
                        Ajouter(x,y,x2,y2,POINT,g);
                        break;
                    case CARRE:
                        if(abs(largeur)>abs(hauteur))
                        {
                            g.drawRect(x,y,largeur,largeur);
                        }
                        else
                        {
                            g.drawRect(x,y,hauteur,hauteur);
                        }
                        break;
                    case CERCLE:
                        if(abs(largeur)>abs(hauteur))
                        {
                            g.drawOval(x,y,largeur,largeur);
                        }
                        else
                        {
                            g.drawOval(x,y,hauteur,hauteur);
                        }
                        break;
                    default:
                        break;
                }
            }
            else
            {
                switch(type)
                {
                    case RECTANGLE:
                        if(x<x2)
                        {
                            if(y<y2)
                            {
                                g.fillRect(x,y,largeur,hauteur);
                            }
                            else
                            {
                                g.fillRect(x,y2,largeur,-hauteur);
                            }
                        }
                        else
                        {
                            if(y<y2)
                            {
                                g.fillRect(x2,y,-largeur,hauteur);
                            }
                            else
                            {
                                g.fillRect(x2,y2,-largeur,-hauteur);
                            }
                        }
                        break;
                    case LIGNE:
                        g.drawLine(x,y,largeur+x,hauteur+y);
                        break;
                    case OVALE:
                        if(x<x2)
                        {
                            if(y<y2)
                            {
                                g.fillOval(x,y,largeur,hauteur);
                            }
                            else
                            {
                                g.fillOval(x,y2,largeur,-hauteur);
                            }
                        }
                        else
                        {
                            if(y<y2)
                            {
                                g.fillOval(x2,y,-largeur,hauteur);
                            }
                            else
                            {
                                g.fillOval(x2,y2,-largeur,-hauteur);
                            }
                        }
                        break;
                    case CARRE:
                        if(abs(largeur)>abs(hauteur))
                        {
                            g.fillRect(x,y,largeur,largeur);
                        }
                        else
                        {
                            g.fillRect(x,y,hauteur,hauteur);
                        }
                        break;
                    case CERCLE:
                        if(abs(largeur)>abs(hauteur))
                        {
                            g.fillOval(x,y,largeur,largeur);
                        }
                        else
                        {
                            g.fillOval(x,y,hauteur,hauteur);
                        }
                        break;
                    case POINT:
                        g.drawLine(x,y,x,y);
                        Ajouter(x,y,x,y,POINT,g);
                        break;
                    default:
                        break;
                }
            }

        }
        public void Ajouter(int x,int y,int largeur,int hauteur,int type,Graphics g)
        {
            Figure f;
            switch(type)
            {
                case OVALE:
                case CERCLE:
                    g.setColor(panel.getBackground());
                    g.drawLine(x,y,x,y);
                    g.setColor(panel.init);
                             /*
                             CA MARCHE MAIS COMME ON LE SAUVE PAS, C OPERANT QUE SUR LE PANEL EN COURS.
                             */
                case LIGNE:
                case RECTANGLE:
                case POINT:
                case CARRE:
                    forme.addElement(f=new Figure(x,y,largeur,hauteur,type,panel.init,check.getState()));
                    break;
                default:
                    //Graphics2D graph=(Graphics2D)g;
                    break;
            }
            System.out.println(forme.size());
        }

    }

    class Figure implements Serializable
    {
        int x,y,largeur,hauteur,forme;
        Color Couleur;
        boolean plein;
        Figure(int x,int y,int largeur,int hauteur,int forme,Color Couleur,boolean plein)
        {
            this.x=x;
            this.y=y;
            this.largeur=largeur;
            this.hauteur=hauteur;
            this.forme=forme;
            this.Couleur=Couleur;
            this.plein=plein;
        }

        Figure(Figure f)
        {
            this.x=f.x;
            this.y=f.y;
            this.largeur=f.largeur;
            this.hauteur=f.hauteur;
            this.forme=f.forme;
            this.Couleur=f.Couleur;
            this.plein=f.plein;
        }
    }

    class Fermer implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            int reponse = getSortie();
                if(reponse==JOptionPane.YES_OPTION)
                {
                    int retour = getCloseVal();
                    if(retour == JFileChooser.APPROVE_OPTION)
                    {
                        Fic = chooser.getSelectedFile().getPath();
                        try
                        {
                            FileOutputStream ostream = new FileOutputStream(Fic);
                            ObjectOutputStream objout = new ObjectOutputStream(ostream);
                            objout.writeObject(panel.forme);
                            ostream.close();
                            System.exit(0);
                        }
                            catch(IOException exep)
                            {
                                System.out.println(exep);
                                System.exit(1);
                            }
                    }
                }
                else if(reponse == JOptionPane.NO_OPTION)
                {
                    System.exit(0) ;
                }
        }
    }

    class Dessiner implements ItemListener
    {
        public void itemStateChanged(ItemEvent e)
        {
            Fig = lb.getSelectedItem();
            if("Figure...".equals(Fig))
            {
                panel.setMode(panel.RIEN);
            }
            else if("Ligne".equals(Fig))
            {
                panel.setMode(panel.LIGNE);
            }
            else if("Rectangle".equals(Fig))
            {
                panel.setMode(panel.RECTANGLE);
            }
            else if("Ovale".equals(Fig))
            {
                panel.setMode(panel.OVALE);
            }
            else if("Cercle".equals(Fig))
            {
                panel.setMode(panel.CERCLE);
            }
            else if("HandWriting".equals(Fig))
            {
                panel.setMode(panel.POINT);
            }
            else
            {
                panel.setMode(panel.CARRE);
            }


        }
    }
    class Colorier implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            Color temp;
            temp=getCouleur();
            if(temp !=null)
            {
                panel.init= temp;
                couleur.setBackground(temp);
            }
        }
    }
    public Color getCouleur()
    {
        return(JColorChooser.showDialog(this,"selection couleur",getBackground()));
    }

    class Effacer implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            int rep = getReponse("Cela effacera le dessin actuel, Voulez-vous continuer?");
            if(rep == JOptionPane.YES_OPTION)
            {
                panel.forme.removeAllElements();
                temp.removeAllElements();
                remove(panel);
                add("Center",panel);
            }
        }
    }

    class Ouvrir implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            int retour = getLoadVal();
            if(retour == JFileChooser.APPROVE_OPTION)
            {
                int rep=getReponse("Attention, en chargeant ce fichier, vous effacerez le dessin actuel.\nVoulez vous continuer??");
                if(rep == JOptionPane.YES_OPTION)
                {
                    Fic = chooser.getSelectedFile().getPath();
                    boolean loaded=true;
                    try
                    {
                        FileInputStream istream = new FileInputStream(Fic);
                        ObjectInputStream objin = new ObjectInputStream(istream);
                        panel.forme=((Vector)objin.readObject());
                        istream.close();
                    }
                    catch(IOException exep){
                        loaded=false;
                        showError();
                    }
                    catch(ClassNotFoundException exep)
                    {
                        System.out.println(exep);
                        System.exit(3);
                    }

                    if(loaded)
                    {
                        panel.forme.removeAllElements();
                        temp.removeAllElements();
                        remove(panel);
                        add("Center",panel);
                        setTitre(Fic);
                    }
                }
            }
            Graphics g = getGraphics();
        }
    }
    class Sauver implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            int returnVal = getCloseVal();
            if (returnVal == JFileChooser.APPROVE_OPTION)
            {
                Fic = chooser.getSelectedFile().getPath();
                try
                {
                    FileOutputStream ostream = new FileOutputStream(Fic);
                    ObjectOutputStream objout = new ObjectOutputStream(ostream);
                    objout.writeObject(panel.forme);
                    ostream.close();
                    setTitre(Fic);
                }
                catch(IOException exep)
                {
                    System.out.println(exep);
                    System.exit(1);
                }
            }
        }
    }

    class Cocher implements MouseListener
    {

        public void mouseClicked(MouseEvent e) {
            check.setState(!check.getState());
        }

        public void mouseEntered(MouseEvent e) {
        }

        public void mouseExited(MouseEvent e) {
        }

        public void mousePressed(MouseEvent e) {
        }

        public void mouseReleased(MouseEvent e) {
        }

    }
    class Sauver2 implements ActionListener
    {

        public void actionPerformed(ActionEvent e) {
            int returnVal = getCloseVal();
            if (returnVal == JFileChooser.APPROVE_OPTION)
            {
                File file = chooser.getSelectedFile();
                //String ext = file.getPath().substring(file.getPath().indexOf(".") + 1);
                //BufferedImage image = getImage();
                try
                {
                    BufferedImage img = new BufferedImage(panel.getWidth(),panel.getHeight(),BufferedImage.TYPE_INT_RGB);
                    BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file));
                    Graphics2D g2d = img.createGraphics();
                    g2d.drawRect(4,5,150,150);

                /*JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img);
                param.setQuality(1f, true);
                encoder.setJPEGEncodeParam(param);
                encoder.encode(img);
                System.out.println("It worked");*/

                    //ImageIO.write(image,ext,file);
                }
                catch(IOException io)
                {
                    System.exit(3);
                }
            }
        }

    }

    class Annuler implements ActionListener
    { Graphics g = getGraphics();
        public void actionPerformed(ActionEvent e)
        {
            if(panel.forme.size()>0)
            {
                temp.addElement(panel.forme.elementAt(panel.forme.size()-1));
                panel.forme.remove(panel.forme.size()-1);
                remove(panel);
                add("Center",panel);
            }
        }

    }

    class Refaire implements ActionListener
    {Graphics g = getGraphics();
        public void actionPerformed(ActionEvent e)
        {
            if(temp.size()>0)
            {
                panel.forme.addElement(temp.elementAt(temp.size()-1));
                temp.remove(temp.size()-1);
                remove(panel);
                add("Center",panel);
            }
        }

    }

    public int getSortie()
    {
        return(JOptionPane.showConfirmDialog(this,"Voulez-vous sauvegarder votre dessin avant de quitter?","Choix",JOptionPane.YES_NO_CANCEL_OPTION));
    }
    public int getCloseVal()
    {
        chooser = new JFileChooser();
        return(chooser.showSaveDialog(this));
    }

    public int getLoadVal()
    {
        chooser = new JFileChooser();
        return(chooser.showOpenDialog(this));
    }
    public int getReponse(String message)
    {
        return(JOptionPane.showConfirmDialog(this,message,"Choix",JOptionPane.YES_NO_OPTION));
    }

    public void showError()
    {
        JOptionPane.showMessageDialog(this,"Fichier Introuvable","ERREUR",JOptionPane.YES_OPTION);
    }
    public int abs(int i)
    {
        if(i>0) return i;
        else return -i;
    }

    public void setTitre(String s)
    {
        super.setTitle(s);
    }
    public int min(int k,int l)
    {
        if(k<l) return k;
        else return l;
    }

    public static void main(String []args)
    {
        JavaPaint fen = new JavaPaint();
    }

}