import java.awt.*;
import java.applet.*;
import java.lang.Math.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;



public class denkirikisen extends JApplet{
    int hankei=10;
    int q1=3;
    int q2=2;
    double x1=150;
    double x2=200;
    double y1=180;
    double y2=180;
    double N=5.0;
    boolean drawOuterLineFlg;

    int xmin,xmax,ymin,ymax,xv,yv;

    int nowDrag=0;

    GraphPanel canvas;
    JSlider sbQ1,sbQ2;
    JSlider sbN;

    JCheckBox cbShowPotential;
    JCheckBox cbShowField;
  

    JLabel l1;

    int w,h;
    int pw=-1,ph=-1;
    double delta;
    
    public void resetAll()
    {
	sbQ1.setValue(3);
	sbQ2.setValue(-2);
        sbN.setValue(5);
        q1=3;
        q2=-2;
        N=5.0;
    }
    
    public void init(){
	canvas=new GraphPanel();

	Container cont=getContentPane();
	cont.setLayout(new BorderLayout());
	
	sbQ1=new JSlider();
	sbQ1.setMaximum(5);
	sbQ1.setMinimum(-5);
        sbQ1.setMajorTickSpacing(5);
        sbQ1.setMinorTickSpacing(1);
        sbQ1.setPaintLabels(true);
        sbQ1.setPaintTicks(true);
        sbQ1.setSnapToTicks(true);

	sbQ2=new JSlider();
	sbQ2.setMaximum(5);
	sbQ2.setMinimum(-5);
        sbQ2.setMajorTickSpacing(5);
        sbQ2.setMinorTickSpacing(1);
        sbQ2.setPaintLabels(true);
        sbQ2.setPaintTicks(true);
        sbQ2.setSnapToTicks(true);
    
	sbN=new JSlider();
	sbN.setMaximum(8);
	sbN.setMinimum(1);
        sbN.setMajorTickSpacing(1);
        sbN.setMinorTickSpacing(1);
        sbN.setPaintLabels(true);
        sbN.setPaintTicks(true);
        sbN.setSnapToTicks(true);    


	sbN.addChangeListener(new ChangeListener() {
		public void stateChanged(ChangeEvent evt) {
		    setN(sbN.getValue());
		}
	    });

	sbQ1.addChangeListener(new ChangeListener() {
		public void stateChanged(ChangeEvent evt) {
		    setQ1(sbQ1.getValue());
		}
	    });

	sbQ2.addChangeListener(new ChangeListener() {
		public void stateChanged(ChangeEvent evt) {
		    setQ2(sbQ2.getValue());
		}
	    });
    
        canvas.addMouseListener(new MouseAdapter() {
            public void mousePressed(MouseEvent e) {
                mPressed(e);
            }
            public void mouseReleased(MouseEvent e) {
                mReleased(e);
            }
        });
        canvas.addMouseMotionListener(new MouseMotionAdapter() {
            public void mouseDragged(MouseEvent e) {
                mDragged(e);
            }
        });


	JPanel p=new JPanel();
	p.setLayout( new GridLayout(2,2));
    
	JPanel p11=new JPanel();
	p11.setLayout(new BorderLayout());
	
	l1=new JLabel("電荷１：");
        l1.setForeground(Color.BLUE);
    
	p11.add(l1,BorderLayout.WEST);
	p11.add(sbQ1,BorderLayout.CENTER);


	JPanel p12=new JPanel();
	p12.setLayout(new BorderLayout());

	JLabel l2=new JLabel("電荷２：");
        l2.setForeground(Color.GREEN);
    
	p12.add(l2,BorderLayout.WEST);
	p12.add(sbQ2,BorderLayout.CENTER);



	JPanel p13=new JPanel();
	p13.setLayout(new BorderLayout());
	JLabel l3=new JLabel("電気力線の本数");
	p13.add(l3,BorderLayout.WEST);
	p13.add(sbN,BorderLayout.CENTER);

	p.add(p11);
	p.add(p12);
	p.add(p13);

        resetAll();
    	
	cont.add("South",p);
	cont.add("Center",canvas);

	start();
    }

    class GraphPanel extends JPanel {
	public void paintComponent(Graphics g){
            if ( g != null ) {
                writeCanvas(g);
            }
	}
    }
    
    

    public void mPressed(MouseEvent e) {
        int mx=e.getX();
        int my=e.getY();
        int xx=(int)x1;
        int yy=(int)y1;
        if( mx > xx-hankei && mx < xx+hankei && my > yy-hankei && my < yy+hankei ) {
            nowDrag=1;
        }

        xx=(int)x2;
        yy=(int)y2;
        if( mx > xx-hankei && mx < xx+hankei && my > yy-hankei && my < yy+hankei ) {
            nowDrag=2;
        }
    }

    public void mReleased(MouseEvent e) {
        nowDrag = 0;
    }

    public void mDragged(MouseEvent e) {
        if( nowDrag == 0 ) {
            return;
        } else if( nowDrag == 1 ) {
            x1=(double)e.getX();
            y1=(double)e.getY();
            if( x1 < hankei ) {
                x1=hankei;
            }
            if( x1 > w-hankei ) {
                x1= w-hankei;
            }
            if( y1 < hankei ) {
                y1=hankei;
            }
            if( y1 > h-hankei ) {
                y1= h-hankei;
            }
        } else if( nowDrag == 2 ) {
            x2=(double)e.getX();
            y2=(double)e.getY();
            if( x2 < hankei ) {
                x2=hankei;
            }
            if( x2 > w-hankei ) {
                x2= w-hankei;
            }
            if( y2 < hankei ) {
                y2=hankei;
            }
            if( y2 > h-hankei ) {
                y2= h-hankei;
            }
        }
        repaint();
    }

    public void setQ1(int n) {
	q1=n;
	repaint();
    }

    public void setN(int n) {
	N=n;
	repaint();
    }

    public void setQ2(int n) {
	q2=n;
	repaint();
    }

    boolean SameSegment(double xx,double yy,double xxx,double yyy)
    {
        double angle1,angle2,angle3,angle4;
        if( Math.abs(xx-x1)< 2.0 && y1>yy) {
            // 角度がπや-πになる可能性のある、危険なところ。
            angle1=Math.atan2(x1-xx,y1-yy)+Math.PI;
            angle3=Math.atan2(x1-xxx,y1-yyy)+Math.PI;
        } else {
            angle1=Math.atan2(xx-x1,yy-y1);
            angle3=Math.atan2(xxx-x1,yyy-y1);
        }
        if( Math.abs(xx-x2) < 2.0 && y2>yy) {
            angle2=Math.atan2(x2-xx,y2-yy)+Math.PI;
            angle4=Math.atan2(x2-xxx,y2-yyy)+Math.PI;
        } else {
            angle2=Math.atan2(xx-x2,yy-y2);
            angle4=Math.atan2(xxx-x2,yyy-y2);
        }
        int inte = (int)Math.floor((q1*angle1+q2*angle2)/(2.0*Math.PI)*N);
        int inte2 = (int)Math.floor((q1*angle3+q2*angle4)/(2.0*Math.PI)*N);
        return(inte == inte2);
    } 

    void writeRikisenFromTop(int x,int y,Graphics gc)
    {
        double xs=(double)x;
        double xe=(double)(x+1);
        double ys=(double)y;
        double ye=(double)(y+1);

        if( SameSegment(xs,ys,xe,ys) ) {
            // 上から電気力線は通ってこなかった。
            return;
        }

        
        gc.setColor(Color.RED);
        gc.fillRect(x,y,1,1);
        if( (q1 != 0 &&(x-x1)*(x-x1)+(y-y1)*(y-y1) < hankei*hankei )
            ||(q2 !=0 && (x-x2)*(x-x2)+(y-y2)*(y-y2) < hankei*hankei )
            ) {
            // 電荷から近いところに来たら終了。
            return;
        }
        if( !SameSegment(xs,ye,xe,ye) ) {
            // 下に通った。
            if( y < h-1 ) {
                writeRikisenFromTop(x,y+1,gc);
            }
        }
        if( !SameSegment(xs,ys,xs,ye) ) {
            // 左に通った。
            if( x > 0 ) {
                writeRikisenFromRight(x-1,y,gc);
            }
        }
        if( !SameSegment(xe,ys,xe,ye) ) {
            if( x < w-1 ) {
                writeRikisenFromLeft(x+1,y,gc);
            }
        }
    }

    void writeRikisenFromBottom(int x,int y,Graphics gc)
    {
        double xs=(double)x;
        double xe=(double)(x+1);
        double ys=(double)y;
        double ye=(double)(y+1);

        if( SameSegment(xs,ye,xe,ye) ) {
            // 下から電気力線は通ってこなかった。
            return;
        }

        
        gc.setColor(Color.RED);
        gc.fillRect(x,y,1,1);
        if( (q1!=0 &&(x-x1)*(x-x1)+(y-y1)*(y-y1) < hankei*hankei )
            ||
            (q2!=0 && (x-x2)*(x-x2)+(y-y2)*(y-y2) < hankei*hankei )
            ) {
            // 電荷から近いところに来たら終了。
            return;
        }
        if( !SameSegment(xs,ys,xe,ys) ) {
            // 上に通った。
            if( y > 0  ) {
                writeRikisenFromBottom(x,y-1,gc);
            }
        }
        if( !SameSegment(xs,ys,xs,ye) ) {
            // 左に通った。
            if( x > 0 ) {
                writeRikisenFromRight(x-1,y,gc);
            }
        }
        if( !SameSegment(xe,ys,xe,ye) ) {
            // 右に通った。
            if( x < w-1 ) {
                writeRikisenFromLeft(x+1,y,gc);
            }
        }
    }

    void writeRikisenFromRight(int x,int y,Graphics gc)
    {
        double xs=(double)x;
        double xe=(double)(x+1);
        double ys=(double)y;
        double ye=(double)(y+1);

        if( SameSegment(xe,ys,xe,ye) ) {
            // 右から電気力線は通ってこなかった。
            return;
        }

        
        gc.setColor(Color.RED);
        gc.fillRect(x,y,1,1);

        if( (q1 != 0 &&(x-x1)*(x-x1)+(y-y1)*(y-y1) < hankei*hankei ) 
            ||(q2 !=0 &&(x-x2)*(x-x2)+(y-y2)*(y-y2) < hankei*hankei )) {
            // 電荷から近いところに来たら終了。
            return;
        }

        if( !SameSegment(xs,ye,xe,ye) ) {
            // 下に通った。
            if( y < h-1 ) {
                writeRikisenFromTop(x,y+1,gc);
            }
        }

        if( !SameSegment(xs,ys,xs,ye) ) {
            // 左に通った。
            if( x > 0 ) {
                writeRikisenFromRight(x-1,y,gc);
            }
        }
        if( !SameSegment(xs,ys,xe,ys) ) {
            // 上に通った。
            if( y > 0 ) {
                writeRikisenFromBottom(x,y-1,gc);
            }
        }
    }

    void writeRikisenFromLeft(int x,int y,Graphics gc)
    {
        double xs=(double)x;
        double xe=(double)(x+1);
        double ys=(double)y;
        double ye=(double)(y+1);

        if( SameSegment(xs,ys,xs,ye) ) {
            // 左から電気力線は通ってこなかった。
            return;
        }

        
        gc.setColor(Color.RED);
        gc.fillRect(x,y,1,1);

        if( (q1!=0 && (x-x1)*(x-x1)+(y-y1)*(y-y1) < hankei*hankei )
            ||(q2 !=0 && (x-x2)*(x-x2)+(y-y2)*(y-y2) < hankei*hankei )
            ) {
            // 電荷から近いところに来たら終了。
            return;
       }


        if( !SameSegment(xs,ye,xe,ye) ) {
            // 下に通った。
            if( y < h-1 ) {
                writeRikisenFromTop(x,y+1,gc);
            }
        }
        if( !SameSegment(xs,ys,xe,ys) ) {
            // 上に通った。
            if( y > 0  ) {
                writeRikisenFromBottom(x,y-1,gc);
            }
        }

        if( !SameSegment(xe,ys,xe,ye) ) {
            // 右に通った。
            if( x < w-1 ) {
                writeRikisenFromLeft(x+1,y,gc);
            }
        }
    }

    public void writeCanvas(Graphics gc){
        if( gc == null ) {
            return;
        }

	w=canvas.getWidth();
	h=canvas.getHeight();

        int x,y;

	if( w !=pw ) { pw=w;}
	if( h !=ph ) { ph=h;}


        ymin=0;
        ymax=h;
        xmin=0;
        xmax=w;

	gc.setColor(Color.WHITE);
	gc.fillRect(0,0,w,h);

        double mitudo=1.0/N;
        double gauge=mitudo*0.5;
        double gaugev=0.0;

        int x1i=(int)x1;
        int x2i=(int)x2;
        int y1i=(int)y1;
        int y2i=(int)y2;

        xv= ((int)(x1+x2))/2;
        yv= ((int)(y1+y2))/2;
        

        if( q1*q2 < 0 ) {
            if( Math.abs(x1-x2)>Math.abs(y1-y2) ) {
                if( xv == x1i || xv == x2i ) {
                    // 二つの電荷が同じ場所にあるなら何もしなくていい。
                    xv =-1;
                    yv =-1;
                } else {
                    yv =-1;
                }
            } else {
                if( yv == y1i || yv == y2i ) {
                    xv =-1;
                    yv =-1;
                } else {
                    xv=-1;
                }
            }
        } else {
            xv =-1;
            yv =-1;
        }


        drawOuterLineFlg =true;

        for( x=0 ; x<w ; x++ ) {
            writeRikisenFromTop(x,0,gc);
        }
        for( y=0 ; y<h ; y++ ) {
            writeRikisenFromRight(w-1,y,gc);
        }
        for( x=w-1 ; x>=0 ; x-- ) {
            writeRikisenFromBottom(x,h-1,gc);
        }
        for( y=h-1 ; y>1 ; y-- ) {
            writeRikisenFromLeft(0,y,gc);
        }


        drawOuterLineFlg =false;

        if( xv > 0 ) {
            for( y=0 ; y<h-1 ; y++ ) {
                writeRikisenFromLeft(xv,y,gc);
                writeRikisenFromRight(xv,y,gc);
            }
        }

        if( yv > 0 ) {
            for( x=w-1 ; x > 0 ; x-- ) {
                writeRikisenFromTop(x,yv,gc);
                writeRikisenFromBottom(x,yv,gc);
            }
        }


        gc.setColor(Color.BLUE);

        gc.fillOval((int)x1-hankei,(int)y1-hankei,hankei*2,hankei*2);

        gc.setColor(Color.GREEN);

        gc.fillOval((int)x2-hankei,(int)y2-hankei,hankei*2,hankei*2);

        gc.setColor(Color.WHITE);
        if( q1 != 0 ) {
            gc.drawLine((int)x1-hankei+3,(int)y1,(int)x1+hankei-2,(int)y1);
            if( q1 > 0 ) {
                gc.drawLine((int)x1,(int)y1-hankei+2,(int)x1,(int)y1+hankei-2);
            }
        }
        if( q2 != 0 ) {
            gc.drawLine((int)x2-hankei+2,(int)y2,(int)x2+hankei-2,(int)y2);
            if( q2 > 0 ) {
                gc.drawLine((int)x2,(int)y2-hankei+2,(int)x2,(int)y2+hankei-2);
            }
        }
    }
}
