import java.applet.*;
import java.lang.*;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.net.*;
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 = 100;
    int yshift = 250;
    private int LeftMargin=90, RightMargin=85, TopMargin=60, TopMargin2=TopMargin+yshift, 
                BottomMargin=210, BottomMargin2=-40;
    
    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;
    
    public PlaneWaveCanvas2(){
	super();
	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 = 10; yseg = 50;
           xA = xseg+60;
           xB = getSize().width - xseg;
           xC = xseg;
           xD = xB - 60;
           yA = yseg;
           yB = yseg+60;
        
        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,16,xA+50,yA+30);
        ArrowRIGHT(g, xA+10, yA+10, 60.0, 10.0, Color.red, 2);   
        // Magnetic Field
        g.setColor(Color.blue.darker());
        MaestroG.subscripterSansItalic3("H","0","",g,16,xA-10,yA+50);
        ArrowANGLE(g, xA+10, yA+10, 50.0, 10.0, 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,16,xA+150,yA-10);
            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)));
            
            // CHECKPOINT 1
            //MaestroG.subscripterSansItalic3(MaestroA.rounder(afactor, 3)+" \u00d7 J","0","",g,16,xA+120,yA-10);
            //MaestroG.subscripterSansItalic3("J","0","",g,16,xA+150,yA-10);
            MaestroG.subsubSansItalic3("J","0"," = \u03c3 E","0",g,16,xA+130,yA-10);
        }
        
        ArrowRIGHT(g, xA+140, yB-60, 80.0, 10.0, Color.magenta.darker(), 2);
        ArrowRIGHT(g, xA+120, yB-40, 80.0, 10.0, Color.magenta.darker(), 2);
        ArrowRIGHT(g, xA+100, yB-20, 80.0, 10.0, Color.magenta.darker(), 2);
        ArrowRIGHT(g, xA+80, yB, 80.0, 10.0, Color.magenta.darker(), 2);
        
        double factor; double Delta = 15.0; double stem; double arrow;
        if(!IsEquivalent){
            for(int i = 1; i < 20; i++){
                factor = Math.exp(-alphaT*i*Delta);
                stem = factor*80.0;
                arrow = 10.0;
                if(stem < 2*arrow){
                    arrow = stem/2.0;
                }
                ArrowRIGHT(g, xA+80+(80-stem)/2.0, yB+i*Delta, stem, arrow, Color.magenta.darker(), 2);
            }
        }
        else{
            for(int i = 1; i < 20; i++){
                stem = 80.0;
                arrow = 10.0;
                if((i*Delta) < L_skin_depth){
                    ArrowRIGHT(g, xA+80+(80-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,18,xD+20,yB-5);
         g.drawLine(xD,yB,xD+23,yB);
         MaestroG.drawArrowtip(xD+20, yB, 7, g);
         
         // z axis
         MaestroG.subscripterSansItalic3("z","","",g,18,xD+10,4*getSize().height/5+40);
         g.drawLine(xD,4*getSize().height/5,xD,4*getSize().height/5+33);
         MaestroG.drawArrowtip(xD, 4*getSize().height/5+30, 6, g);
         
         // "w"
         g.drawLine(xC,yB-20,xC,yB-40);
         g.drawLine(xA,yA-20,xA,yA-40);
         g.drawLine(xC,yB-30,xA,yA-30);
         MaestroG.drawArrow(xA-7, yA-23, 9, g);
         MaestroG.drawArrow(xC+7, yB-37, 10, g);
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
         MaestroG.subscripterSansItalic3("w","","",g,18,xC+(xA-xC)/2-10,yA-10);
         
         // "l"
         g.drawLine(xB,yA-20,xB,yA-40);
         g.drawLine(xA,yA-30,xB,yA-30);
         MaestroG.drawArrowtip(xB-10, yA-30, 7, g);
         MaestroG.drawArrowtip(xA+10, yA-30, 8, g);
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
         MaestroG.subscripterSansItalic3("l","","",g,18,xB-(xB-xA)/2,yA-33);
                         
         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+10), (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,16,xD+35,yB+L_skin_depth+8);
             g.setColor(Color.black);
             MaestroG.subscripter("skin depth","","",g,14,20,yB+L_skin_depth-3);
         }
         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+10), (double)(yB+L_total_length), 2, Color.orange);
         g.setColor(Color.black);
         MaestroG.subscripterSansItalic3("h","","",g,18,xD+20,yB+L_total_length+8);
         
         g.setColor(Color.black);
         MaestroG.subscripterSansItalic5("Equivalent  ","J","0","",g,16,125,475);
         
         // Make checkbox with graphics - We are in canvas, not in panel - EquivalentOn.java does not work with Application
         g.setColor(Color.gray);
         g.drawRect(105, 465, 11, 11);
         drawLineThick(g,104,464,115,464,1,Color.black);
         drawLineThick(g,104,464,104,475,1,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,110,473,114,468,2,Color.black);  // Check the box
             drawLineThick(g,110,473,107,469,1,Color.black);
         }
         
         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
         
         if(test_conductor < 100.0){
            g.setColor(Color.red);
            MaestroG.subscripterB("WARNING","","", g, 14, 15, getSize().height-120);
            if(test_conductor >= 1.0E-6){
                MaestroG.subscripterB("\u03c3 / \u03c9\u03b5 = "+MaestroA.rounder(test_conductor,6),"","", g, 12, 15, getSize().height-105);
            }
            else{
                MaestroG.subscripterB("\u03c3 / \u03c9\u03b5 ~ 0.0 ","","", g, 12, 15, getSize().height-105);
            }
            MaestroG.subscripterB("For good conductor condition","","", g, 14, 15, getSize().height-84);
            MaestroG.subscripterB("increase conductivity or ","","", g, 14,15, getSize().height-68);
            MaestroG.subscripterB("decrease frequency","","", g, 14, 15, getSize().height-52);
            
         }
    }
    
    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;
    }
}
