import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;


public class PlaneWaveCanvas2 extends Canvas  implements MouseListener{
    private static final Color bgcolor = Color.white;
    //private static final Color bgcolor = new Color(250,250,250);
        
    private double zmax, zmin, ymax, ymin, xmax, xmin, pmax, pmin;
    private int down2;
    int yshift;
    private int LeftMargin, RightMargin, TopMargin, TopMargin2, 
                BottomMargin, BottomMargin2;
    
    private double alpha, beta, frequency, wavelength, skin_depth, skin_depth_wavelength, afactor;
    private double test_conductor;
    private double total_length = 1.0;
    private int L_wavelength, L_skin_depth, L_total_length;
    private double alphaT;
    private int WIDTH, HEIGHT;
    private Image im;
    private Graphics buf;
    private int VPos = 0;
   
    private static final Font TitleFont = new Font("SanSerif",Font.BOLD,11);
    private static final Font LabelFont = new Font("SanSerif",Font.PLAIN,11);
    private boolean IsTraceOn, IsCleanUpOn, IsDynamic, IsEon, IsHon; // IsEquivalent = false;
    public boolean IsEquivalent = false;
    
    PlaneWave_State state;
    
    public PlaneWaveCanvas2(PlaneWave_State state){
	super();
        this.state = state;
        
        down2 = state.s100;
        yshift = state.s250;
        LeftMargin = state.s90;
        RightMargin = state.s85;
        TopMargin = state.s60;
        TopMargin2 = TopMargin+yshift;
        BottomMargin = state.s200+state.s10;
        BottomMargin2 = -state.s40;
    
	setBackground(bgcolor);
        this.addMouseListener(this);
    }
    
    public void paint(Graphics g){
	if(im == null){
	    im = createImage(getSize().width,getSize().height);
	    buf = im.getGraphics();
	    drawGraph(buf);
	}
	else{
	 drawGraph(buf);
	}
	g.drawImage(im,0,0,null);
    }
    
    public void drawGraph(Graphics g){
	
	g.setColor(Color.black);	
	g.draw3DRect(0,0,getSize().width-1,getSize().height-1,false);
        drawPict(g);
    }
    
    private synchronized void drawPict(Graphics g){
        
        g.clearRect(0,0,getSize().width,getSize().height);
        g.setColor(Color.black);
	g.draw3DRect(0,0,getSize().width-1,getSize().height-1,false);
        
	int xA, xB, xC, xD, yA, yB, xseg, yseg;
        Graphics2D g2d = (Graphics2D)g;
        int rule; 
        float alphaG;
        rule = AlphaComposite.SRC_OVER;
        alphaG = 0.3f;  
           
           xseg = state.s10;
           yseg = state.s50;
           xA = xseg + state.s60;
           xB = getSize().width - xseg;
           xC = xseg;
           xD = xB - state.s60;
           yA = yseg;
           yB = yseg + state.s60;
        
        skin_depth = 1.0/alpha;  
        L_total_length = (4*getSize().height/5 - yB);
        L_wavelength = (int)((4*getSize().height/5 - yB)/total_length);
        L_skin_depth = (int)(skin_depth/wavelength*L_wavelength);
        alphaT = 1.0/L_skin_depth;
        skin_depth_wavelength = skin_depth/wavelength;
        
        float[] dashPattern2 = {10,10};
         
        g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern2,0));
        
        g.setColor(Color.gray);
        g.drawLine(xC,yB,xC,4*getSize().height/5);
        g.drawLine(xD,yB,xD,4*getSize().height/5);
        g.setColor(Color.lightGray);
        g.drawLine(xA,yA,xA,4*getSize().height/5 - (yB-yA));
        g.drawLine(xB,yA,xB,4*getSize().height/5 - (yB-yA));
        g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
         
        // Electric Field
        g.setColor(Color.red.darker());
        MaestroG.subscripterSansItalic3("E","0","",g,state.font16,xA+state.s50,yA+state.s30);
        ArrowRIGHT(g, xA+state.s10, yA+state.s10, (double)state.s60, (double)state.s10, Color.red, 2);   
        // Magnetic Field
        g.setColor(Color.blue.darker());
        MaestroG.subscripterSansItalic3("H","0","",g,state.font16,xA-state.s10,yA+state.s50);
        ArrowANGLE(g, (double)(xA+state.s10), (double)(yA+state.s10), (double)(state.s50), (double)(state.s10), 225.0, Color.blue, 2);
         
        // Current Vectors on Surface
        g.setColor(Color.magenta.darker());
        //g.setColor(Color.black);
        if(!IsEquivalent){
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
            MaestroG.subscripterSansItalic("J","x ","( z )",g,state.font16,xA+state.s150,yA-state.s10);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        }
        
        else{
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            afactor = 1.0/Math.sqrt(1+(beta*beta/(alpha*alpha)));
            
            //MaestroG.subsubSansItalic3("J","0"," = \u03c3 E","0",g,state.font16,xA+state.s130,yA-state.s10);
            //MaestroG.subsubSansItalic4("< J","0"," > = \u03c3 < E","0"," >",g,state.font16,xA+state.s80,yA-state.s10);
            MaestroG.subsubSansItalic4("< J",""," > = \u03c3 < E",""," >",g,state.font16,xA+state.s90,yA-state.s10);
        }
        
        ArrowRIGHT(g, xA+state.s140, yB-state.s60, (double)state.s80, (double)state.s10, Color.magenta.darker(), 2);
        ArrowRIGHT(g, xA+state.s120, yB-state.s40, (double)state.s80, (double)state.s10, Color.magenta.darker(), 2);
        ArrowRIGHT(g, xA+state.s100, yB-state.s20, (double)state.s80, (double)state.s10, Color.magenta.darker(), 2);
        ArrowRIGHT(g, xA+state.s80, yB, (double)state.s80, (double)state.s10, Color.magenta.darker(), 2);
        
        double factor; double Delta = (double)state.s15; double stem; double arrow;
        if(!IsEquivalent){
            for(int i = 1; i < 20; i++){
                factor = Math.exp(-alphaT*i*Delta);
                stem = factor*(double)state.s80;
                arrow = (double)state.s10;
                if(stem < 2*arrow){
                    arrow = stem/2.0;
                }
                ArrowRIGHT(g, xA+state.s80+(state.s80-stem)/2.0, yB+i*Delta, stem, arrow, Color.magenta.darker(), 2);
            }
        }
        else{
            for(int i = 1; i < 20; i++){
                stem = (double)state.s80;
                arrow = (double)state.s10;
                if((i*Delta) < L_skin_depth){
                    ArrowRIGHT(g, xA+state.s80+(state.s80-stem)/2.0, yB+i*Delta, stem, arrow, Color.magenta.darker(), 2);
                }
            }
        }
                
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setComposite(AlphaComposite.getInstance(rule, alphaG));
        // Draw the Box
        g.setColor(new Color(240,240,240));
        g.fillRect(xA, yA, xD-xC, 4*getSize().height/5 - yB);
         
        g.setColor(new Color(210,210,210));
        Polygon pH3 = new Polygon();
                    pH3.addPoint(xC, yB);
                    pH3.addPoint(xA, yA);
                    pH3.addPoint(xA,yA+4*getSize().height/5-yB);
                    pH3.addPoint(xC,4*getSize().height/5);
                    g.drawPolygon(pH3);
                    g.fillPolygon(pH3);
        
        g.setColor(new Color(220,220,220));
        Polygon pH = new Polygon();
                    pH.addPoint(xA, yA);
                    pH.addPoint(xB, yA);
                    pH.addPoint(xD,yB);
                    pH.addPoint(xC,yB);
                    g.drawPolygon(pH);
                    g.fillPolygon(pH);
                    
        g.setColor(new Color(190,190,190));
        Polygon pH2 = new Polygon();
                    pH2.addPoint(xD, yB);
                    pH2.addPoint(xB, yA);
                    pH2.addPoint(xB,yA+4*getSize().height/5-yB);
                    pH2.addPoint(xD,4*getSize().height/5);
                    g.drawPolygon(pH2);
                    g.fillPolygon(pH2);
         
         g.setColor(new Color(250,250,250));
         g.fillRect(xC, yB, xD-xC, 4*getSize().height/5 - yB);
        
         g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f));
         
         float[] dashPattern3 = {10,10};
         g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern2,0));
            if(skin_depth_wavelength <= total_length){
                g.setColor(Color.green.darker());
                g.drawLine(xC,yB+L_skin_depth,xD,yB+L_skin_depth);
                if(IsEquivalent){
                    g.setColor(new Color(210,210,210));
                    g.drawLine(xC,yB+L_skin_depth,xA,yA+L_skin_depth);
                    g.drawLine(xA,yA+L_skin_depth,xB,yA+L_skin_depth);
                    g.setColor(new Color(180,180,180));
                    g.drawLine(xD,yB+L_skin_depth,xB,yA+L_skin_depth);
                }
            }
            g.setColor(Color.orange);
            g.drawLine(xC,yB+L_total_length,xD,yB+L_total_length);
         g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
         
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
         g.setColor(Color.black);
         // x axis
         MaestroG.subscripterSansItalic3("x","","",g,state.font18,xD+state.s20,yB-state.s5);
         g.drawLine(xD,yB,xD+state.s23,yB);
         //MaestroG.drawArrowtip(xD+20, yB, 7, g);
         MaestroG.drawArrowScaled(xD+state.s20, yB, 3, 1.2*state.sfactor, g);
         
         // z axis
         MaestroG.subscripterSansItalic3("z","","",g,state.font18,xD+state.s10,4*getSize().height/5+state.s40);
         g.drawLine(xD,4*getSize().height/5,xD,4*getSize().height/5+state.s33);
         //MaestroG.drawArrowtip(xD, 4*getSize().height/5+state.s30, 6, g);
         MaestroG.drawArrowScaled(xD, 4*getSize().height/5+state.s30, 2, 1.2*state.sfactor,g);
         // "w"
         g.drawLine(xC,yB-state.s20,xC,yB-state.s40);
         g.drawLine(xA,yA-state.s20,xA,yA-state.s40);
         g.drawLine(xC,yB-state.s30,xA,yA-state.s30);
         //MaestroG.drawArrow(xA-state.s7, yA-state.s23, 9, g);
         //MaestroG.drawArrow(xC+state.s7, yB-state.s37, 10, g);
         MaestroG.drawArrowScaled(xA-state.s7, yA-state.s23, 5, state.sfactor, g);
         MaestroG.drawArrowScaled(xC+state.s7, yB-state.s37, 6, state.sfactor, g);
         
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
         MaestroG.subscripterSansItalic3("w","","",g,state.font18,xC+(xA-xC)/2-state.s10,yA-state.s10);
         
         // "l"
         g.drawLine(xB,yA-state.s20,xB,yA-state.s40);
         g.drawLine(xA,yA-state.s30,xB,yA-state.s30);
         //MaestroG.drawArrowtip(xB-state.s10, yA-state.s30, 7, g);
         //MaestroG.drawArrowtip(xA+state.s10, yA-state.s30, 8, g);
         MaestroG.drawArrowScaled(xB-state.s10, yA-state.s30, 3, 1.2*state.sfactor, g);
         MaestroG.drawArrowScaled(xA+state.s10, yA-state.s30, 4, 1.2*state.sfactor, g);
         
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
         MaestroG.subscripterSansItalic3("l","","",g,state.font18,xB-(xB-xA)/2,yA-state.s33);
                         
         g.setColor(Color.green.darker());
         if(skin_depth_wavelength <= total_length){
             //g.drawLine(xD,yB+L_skin_depth,xD+15,yB+L_skin_depth);
             drawLineThick(g,(double)xD,(double)(yB+L_skin_depth), (double)(xD+state.s10), (double)(yB+L_skin_depth), 2, Color.green.darker());
         }
         
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
         if(skin_depth_wavelength <= total_length){
             MaestroG.subscripterSansFrontBack("\u03b4","s","","",g,state.font16,xD+state.s20,yB+L_skin_depth+state.s5);
             g.setColor(Color.black);
             MaestroG.subscripter("skin depth","","",g,state.font14,state.s20,yB+L_skin_depth-state.s3);
         }
         g.setColor(Color.orange);
         //g.drawLine(xD,yB+L_total_length,xD+15,yB+L_total_length);
         drawLineThick(g,(double)xD,(double)(yB+L_total_length), (double)(xD+state.s10), (double)(yB+L_total_length), 2, Color.orange);
         g.setColor(Color.black);
         MaestroG.subscripterSansItalic3("h","","",g,state.font18,xD+state.s20,yB+L_total_length+state.s8);
         
         g.setColor(Color.black);
         MaestroG.subscripterSansItalic5("Equivalent  ","J","0","",g,state.font16,state.s125,state.s400+state.s75);
         
         // Make checkbox with graphics - We are in canvas, not in panel - EquivalentOn.java does not work with Application
         g.setColor(Color.gray);
         g.drawRect(state.s105, state.s400+state.s65, state.s11, state.s11);
         drawLineThick(g,state.s104,state.s400+state.s64,state.s115,state.s400+state.s64,state.s1,Color.black);
         drawLineThick(g,state.s104,state.s400+state.s64,state.s104,state.s400+state.s75,state.s1,Color.black);
         if(IsEquivalent){
             //drawLineThick(g,115,475,105,465,1,Color.black); // Cross the box
             //drawLineThick(g,105,475,115,465,1,Color.black);
             
             drawLineThick(g,state.s110,state.s400+state.s73,state.s114,state.s400+state.s68,state.s2,Color.black);  // Check the box
             drawLineThick(g,state.s110,state.s400+state.s73,state.s107,state.s400+state.s69,state.s1,Color.black);
         }
         
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
         
         if(test_conductor < 100.0){
            g.setColor(Color.red);
            MaestroG.subscripterB("WARNING","","", g, state.font14, state.s15, getSize().height-state.s120);
            if(test_conductor >= 1.0E-6){
                MaestroG.subscripterB("\u03c3 / \u03c9\u03b5 = "+MaestroA.rounder(test_conductor,6),"","", g, state.font12, state.s15, getSize().height-state.s105);
            }
            else{
                MaestroG.subscripterB("\u03c3 / \u03c9\u03b5 ~ 0.0 ","","", g, state.font12, state.s15, getSize().height-state.s105);
            }
            MaestroG.subscripterB("For good conductor condition","","", g, state.font14, state.s15, getSize().height-state.s84);
            MaestroG.subscripterB("increase conductivity or ","","", g, state.font14,state.s15, getSize().height-state.s68);
            MaestroG.subscripterB("decrease frequency","","", g, state.font14, state.s15, getSize().height-state.s52);
         }
    }
    
    private void ArrowUP(Graphics g, double xstart, double ystart, double xlength, double LenR, Color colore, int thickness){
            //double LenR = 15.0;
            
            drawLineThick(g,xstart,ystart, xstart, ystart-xlength, thickness, colore);
    
            drawLineThick(g,xstart, ystart - xlength, xstart - LenR * Math.sin(Math.PI/9.0),
                      ystart - xlength + LenR*Math.cos(Math.PI/9.0),thickness,colore);
            drawLineThick(g,xstart, ystart - xlength, xstart + LenR * Math.sin(Math.PI/9.0),
                      ystart - xlength + LenR*Math.cos(Math.PI/9.0),thickness,colore);
        }
        
        private void ArrowDOWN(Graphics g, double xstart, double ystart, double xlength, double LenR, Color colore, int thickness){
            //double LenR = 15.0;
            
            drawLineThick(g,xstart,ystart, xstart, ystart-xlength, thickness, colore);
    
            drawLineThick(g,xstart, ystart, xstart - LenR * Math.sin(Math.PI/9.0),
                      ystart - LenR*Math.cos(Math.PI/9.0),thickness,colore);
            drawLineThick(g,xstart, ystart, xstart + LenR * Math.sin(Math.PI/9.0),
                      ystart - LenR*Math.cos(Math.PI/9.0),thickness,colore);
        }
        
        private void ArrowLEFT(Graphics g, double xstart, double ystart, double xlength, double LenR, Color colore, int thickness){
            //double LenR = 15.0;
            
            drawLineThick(g,xstart,ystart, xstart + xlength, ystart, thickness, colore);
    
            drawLineThick(g,xstart, ystart,xstart + LenR * Math.cos(Math.PI/9.0),
                      ystart - LenR*Math.sin(Math.PI/9.0),thickness,colore);
            drawLineThick(g,xstart, ystart ,xstart + LenR * Math.cos(Math.PI/9.0),
                      ystart + LenR*Math.sin(Math.PI/9.0),thickness,colore);
             
        }
        
        private void ArrowRIGHT(Graphics g, double xstart, double ystart, double xlength, double LenR, Color colore, int thickness){
            //double LenR = 15.0;
            
            drawLineThick(g,xstart,ystart, xstart + xlength, ystart, thickness, colore);
    
            drawLineThick(g,xstart + xlength, ystart ,xstart + xlength - LenR * Math.cos(Math.PI/9.0),
                      ystart - LenR*Math.sin(Math.PI/9.0),thickness,colore);
            drawLineThick(g,xstart + xlength, ystart ,xstart + xlength - LenR * Math.cos(Math.PI/9.0),
                      ystart + LenR*Math.sin(Math.PI/9.0)+1,thickness,colore);
             
        }
        
        private void ArrowANGLE(Graphics g, double xstart, double ystart, double xlength, double LenR, double angle, Color colore, int thickness){
            //double LenR = 15.0;
            double xtip, ytip;
            
            xtip = xstart + xlength*Math.cos(Math.PI*angle/180.0);
            ytip = ystart - xlength*Math.sin(Math.PI*angle/180.0);
            drawLineThick(g,xstart,ystart, xtip, ytip, thickness, colore);
            drawLineThick(g,xtip, ytip ,xtip - LenR * Math.cos(Math.PI*angle/180.0+Math.PI/9.0),
                      ytip + LenR*Math.sin(Math.PI*angle/180.0+Math.PI/9.0),thickness,colore);
            drawLineThick(g,xtip, ytip ,xtip - LenR * Math.cos(Math.PI*angle/180.0-Math.PI/9.0),
                      ytip + LenR*Math.sin(Math.PI*angle/180.0-Math.PI/9.0),thickness,colore);
             
        }
        
    
    private void drawLineThick(Graphics g, double x1, double y1, double x2, double y2, int thick, Color color){
	
        Graphics2D g2d = (Graphics2D)g;
        g2d.setPaint(color);
        g2d.setStroke(new BasicStroke(thick,BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
        
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
        Line2D.Double line = new Line2D.Double(x1,y1,x2,y2);
        g2d.draw(line);
  
        g2d.setStroke(new BasicStroke(1));
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    }

    public synchronized void cleanUp(){
	IsCleanUpOn=true;
    }
    
    public void update(Graphics g){
	if(!IsDynamic){
	    paint(g);
	    return;
	}
	if(IsDynamic && IsTraceOn){g.clipRect(LeftMargin+1,TopMargin+1,WIDTH-1,HEIGHT-1);}
	if(IsCleanUpOn){
	    g.clearRect(0,0,getSize().width,getSize().height);
	    IsCleanUpOn = false;
	    drawPict(g);
	}
	drawPict(g);
    }
    
    //----------------  mouse routines
    @Override
	public void mouseClicked(MouseEvent evt){
	    if(IsEquivalent){
		IsEquivalent = false;
                repaint();
	    }
	    else{
		IsEquivalent = true;
                repaint();
	    }
	}
    
    @Override
	public void mouseEntered(MouseEvent evt){}
    @Override
	public void mouseExited(MouseEvent evt){}
    @Override
	public void mousePressed(MouseEvent evt){}
    @Override
	public void mouseReleased(MouseEvent evt){} 
	 
	//----------------------------------------
	 
    
    public synchronized void setAlpha(double alpha, double beta, double frequency, double test_conductor){
	this.alpha = alpha;
        this.beta = beta;
        this.frequency = frequency;
        this.test_conductor = test_conductor;
    }
    
    public synchronized void setSkinDepth(double skin_depth){
	this.skin_depth = skin_depth;
    }
    
    public synchronized void setWavelength(double wavelength){
	this.wavelength = wavelength;
    }
    
    public synchronized void setLength(double total_length){
	this.total_length = total_length;
    }
    
    public synchronized void setEquivalent(boolean IsEquivalent){
	this.IsEquivalent = IsEquivalent;
    }
}
