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

public class PlaneWaveCanvas extends Canvas{
    //private static final Color bgcolor = new Color(216,216,191);
    //private static final Color bgcolor = new Color(216,225,225);
    private static final Color bgcolor = new Color(255,255,255);
        
    private static final Color rotorcolor = Color.green;
   
    private double zmax, zmin, ymax, ymin, xmax, xmin, pmax, pmin;
    private boolean IsYRangeMaxSet, IsYRangeMinSet, IsXRangeMaxSet, IsXRangeMinSet; 
    private boolean IsZRangeMaxSet, IsZRangeMinSet, IsPRangeMaxSet, IsPRangeMinSet;
    private int Orth_Axis_Front, Orth_Axis_Back; //Size of orthogonal axis (y-direction);
    private int axis_one_ref, axis_two_ref, down, down2, down3;
    int yshift;
    private int LeftMargin, RightMargin, TopMargin, TopMargin2, 
                BottomMargin, BottomMargin2;
    
    private boolean IsEquivalent = false;
    private boolean refz;
    
    private double zpos[];   //position of the reference planes
    private double alpha, beta, frequency, total_length, wavelength, Ex, Hy, Pz, skin_depth;
    private static final String znames[] ={"A", "B"};
    private int WIDTH, HEIGHT, SkinZ1_z, SkinZ1_x, SkinZ2_z, SkinZ2_x;
    private int PSkinZ1_z, PSkinZ1_x, PSkinZ2_z, PSkinZ2_x;
    private String Z1, Z2, Z3, X1, X2, X3, X4, TITLE, legend1, legend2;
    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 double[] z;
    //private double myangle = 135.0+45;
    private double[] EField_z, HField_z, PField_z;
    private int[] Field_zx, Field_zx_old, Decay1, Decay1B, Decay2, Decay2B; 
    private int[] Field_zy, Field_zy_old;
    private int[] Field_zp, Field_zp_old, Decay3; 
    
    private int[] zx, zx_old, zy, zy_old, zy2, zy2B;
    private int current_z;
    private double H_ratio, E_ratio, P_ratio;
    private int N;
    private static final double theta = 135.*Math.PI / 180.0;//0.75
    
    private double sintheta = Math.sin(theta);
    private double costheta = Math.cos(theta);
    private boolean IsTraceOn, IsCleanUpOn, IsDynamic,IsPhasorOn, IsSkinDepthOn, IsEon, IsHon;
    private int nlines = 8;
    private double angle = 135.0;
    private double costhetanew,sinthetanew;   
    PlaneWave_State state;
    
    public PlaneWaveCanvas(PlaneWave_State state){
	super();
        this.state = state;
        
	N = 360;
	setBackground(bgcolor);
	
        Orth_Axis_Front = state.s63; 
        Orth_Axis_Back = state.s63; //Size of orthogonal axis (y-direction);
        down = state.s165; 
        down2 = state.s100; 
        down3 = state.s160;
        yshift = state.s250;
        LeftMargin = state.s90; 
        RightMargin = state.s85; 
        TopMargin = state.s60; 
        TopMargin2 = TopMargin+yshift;
        BottomMargin = state.s200+state.s10;
        BottomMargin2 = -state.s40;
    
	double frequency = 1.0E9;
	alpha = 0.0;
	wavelength = 1.0/Math.sqrt(8.8541878176E-12*1.25663706144E-6)/frequency;
	total_length =1.0;
	Ex = 1.0;
	Hy = Ex/Math.sqrt(1.25663706144/8.8541878176E-6/9.0);
        Pz = Ex;//normalize to Ex
        //costheta = Math.cos(myangle*Math.PI/180.0);    
	//sintheta = Math.cos(myangle*Math.PI/180.0);    
	costhetanew = Math.cos(angle*Math.PI/180.0);    
	sinthetanew = Math.sin(angle*Math.PI/180.0);
        
	Z1 = "0";
	Z2 = "L";
	Z3 = "     z";
	X1 = "  ";
	X2 = "  ";
	TITLE = "  ";
	IsYRangeMaxSet = false;
	IsYRangeMinSet = false;
	IsXRangeMaxSet = false;
	IsXRangeMinSet = false;
        IsPRangeMaxSet = true;
	IsPRangeMinSet = true;
	IsTraceOn = false;
	IsCleanUpOn = false;
	IsDynamic = false;
	IsPhasorOn = true;
        IsSkinDepthOn = true;
        
        xmax = 2.0;
	xmin = -2.0;
	ymax = 2.0;
	ymin = -2.0;
        pmax = Pz;
        pmin = -Pz;
        
	zmax = 1.0;
	zmin = 0.0;
        skin_depth = Double.POSITIVE_INFINITY;
        
        IsEon = true;
        IsHon = false;
        refz =false;
        
	axis_one_ref = (int)(0.85*getSize().height/2);
	axis_two_ref  = (int)(0.85*getSize().height/2);
        
        Orth_Axis_Front = (int)(0.55*getSize().height/2);
	Orth_Axis_Back  = (int)(0.55*getSize().height/2);
        
        H_ratio = 0.55/0.85;
        E_ratio = 0.75/0.85;
        P_ratio = 0.75/0.85;
        try{
	    z = new double[N];
	    EField_z = new double[N];
	    HField_z = new double[N];
            PField_z = new double[N];
	    Field_zx = new int[N];
	    Field_zx_old = new int[N];
	    Decay1 = new int[N];
	    Decay2 = new int[N];
            Decay1B = new int[N];
	    Decay2B = new int[N];
            
            Decay3 = new int[N];
	    Field_zy = new int[N];
	    Field_zy_old = new int[N];
            Field_zp = new int[N];
	    Field_zp_old = new int[N];
	    zx = new int[N];
	    zx_old = new int[N];
	    zy = new int[N];
	    zy2 = new int[N];
            zy2B = new int[N];
	    zy_old = new int[N];
	}
	catch(Exception e){e.printStackTrace();}
	for(int i = 0; i < z.length; i++){
	    z[i] = (double)i;
	    EField_z[i] = 0.0;
	    HField_z[i] = 0.0;
            PField_z[i] = 0.0;
	    Field_zx[i] = 0;
	    Field_zx_old[i] = 0;
            Field_zp[i] = 0;
	    Field_zp_old[i] = 0;
	    Decay1[i] = 0;
	    Decay2[i] = 0;
            Decay1B[i] = 0;
	    Decay2B[i] = 0;
            
            Decay3[i] = 0;
	    zx[i] = i;
	    zx_old[i] = i;
	    zy[i] = i;
	    zy_old[i] = i;
	    zy2[i] =i;
            zy2B[i] =i;
	}
	//Positions of reference planes
	zpos = new double[2];
	
	//Position of rotor
	current_z = 0;
	
    }
    
    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.draw3DRect(0,0,getSize().width-1,getSize().height-1,false);
	
	if(!IsDynamic){
	    g.clearRect(0,0,getSize().width,getSize().height);
	}
	g.clearRect(0,0,LeftMargin-1,getSize().height-1);
	g.clearRect(0,0,getSize().width-1,TopMargin-1);
	g.setColor(Color.black);
	
	g.draw3DRect(0,0,getSize().width-1,getSize().height-1,false);
	
        drawAxis(g);
	labelDetect();
	drawZeroLine(g);
	//drawLabels(g);
	drawPoints(g,1);
	drawLabels(g);
	drawRotor(g);
	
    }
    
    public synchronized void ignition(){
	Orth_Axis_Front = (int)(0.55*getSize().height/2);
	Orth_Axis_Back  = (int)(0.55*getSize().height/2);
         
        VPos = getSize().height - BottomMargin;
	WIDTH = getSize().width - LeftMargin -RightMargin;
	HEIGHT = VPos - TopMargin;
		
	N = z.length;
	//Find the boundaries for data
	if(!IsXRangeMaxSet){ xmax = MaestroA.getMax(EField_z);}
	if(!IsXRangeMinSet){ xmin = MaestroA.getMin(EField_z);}
		
    	if(!IsYRangeMaxSet){ ymax = MaestroA.getMax(HField_z);}
	if(!IsYRangeMinSet){ ymin = MaestroA.getMin(HField_z);}
	
        if(!IsZRangeMaxSet){ zmax = z[z.length-1];}
	if(!IsZRangeMinSet){ zmin = z[0]; }
	
	//Confine data
	MaestroA.confiner(z,zmax,zmin);
	MaestroA.confiner(HField_z,ymax,ymin);
	MaestroA.confiner(EField_z,xmax,xmin);
        MaestroA.confiner(PField_z,pmax,pmin);
	int myY;
	
        for(int i = 0; i < zx.length; i++){
		zx[i] = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
		Field_zx[i] = (int)MaestroA.mapper(EField_z[i],(double)TopMargin,(double)(getSize().height-BottomMargin),xmax,xmin);
		Field_zp[i] = (int)MaestroA.mapper(PField_z[i],(double)TopMargin2,
                              (double)(getSize().height-BottomMargin2),pmax,pmin);
                
		zy[i] = zx[i] + (int)MaestroA.mapper(costhetanew*HField_z[i],Orth_Axis_Front,-Orth_Axis_Back,ymax,ymin);	
    		Field_zy[i] = (int)MaestroA.mapper(sinthetanew*HField_z[i],(double)TopMargin,(double)getSize().height-BottomMargin,ymin,ymax);
        } 	
        
    }
    
    private synchronized void drawRotor(Graphics g){
        Graphics2D g2d = (Graphics2D)g;
        
	int myX, myZ;
	int current_z;
	int yref = TopMargin+(getSize().height-BottomMargin-TopMargin)/2;
        
        g.setColor(rotorcolor);
	for(int i = 0; i< 1 ; i++){ // i<1 only shows one thick line ; i<2 also shows thick line at end of domain
            current_z = (int)(zpos[i]*(zx.length)/(zmax-zmin));
            if(current_z>=zx.length){current_z = zx.length-1;}
            if(current_z<0){current_z=0;}

                myX = (int)MaestroA.mapper(0,(double)TopMargin,(double)VPos,xmax,xmin);
                myZ = (int)MaestroA.mapper(z[current_z],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
                if(IsEon){// electric field
                    if(Field_zx[current_z] < yref){
                        drawLineThick(g,zx[current_z],Field_zx[current_z]+1,myZ,myX,3,Color.red.brighter());
                    }
                    else{
                        drawLineThick(g,zx[current_z],Field_zx[current_z]-1,myZ,myX,3,Color.red.brighter());
                    }
                }
                // magnetic field
                myZ = (int)MaestroA.mapper(z[current_z],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
                if(IsHon){drawLineThick(g,zy[current_z],Field_zy[current_z],myZ,myX,3,Color.blue.brighter());}


                // power - MODIFY
                //drawLineThick(g,zx[current_z],Field_zp[current_z]+1,myZ,VPos+down2-5,3,Color.magenta.brighter());
                
                int axis2 = state.s100;
                // cursor line
                float[] dashPattern2 = {5,5};
                g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern2,0));
                if(i==0){
                    g.setColor(Color.lightGray);
                   
                    if(refz){
                        g.drawLine(myZ-state.s1,state.s60,myZ-state.s1,yref + axis2); 
                        g.drawLine(myZ-state.s1,yref + axis2 + state.s35,myZ-state.s1,getSize().height-state.s55); 
                    }
                }
                g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
        }
    }
    
    private synchronized void drawAxis(Graphics g){
	
        Graphics2D g2d = (Graphics2D)g;
        int rule; 
        float alpha;
        rule = AlphaComposite.SRC_OVER;
            
        int x[] = new int[4];
        int zposnew[] = new int[2];
	int y[] = new int[4];
	int myX, myY;
        double angle = 144.50;
	double costhetanew,sinthetanew;
        
        g.setColor(Color.gray);
        int yref = TopMargin+(getSize().height-BottomMargin-TopMargin)/2;
	
        //z axis for E and H
        //MaestroG.drawArrow(getSize().width-state.s65,yref,7,g);
        MaestroG.drawArrowScaled(getSize().width-state.s60,yref,3,1.2*state.sfactor,g);
	g.drawLine(getSize().width-RightMargin,yref,getSize().width-RightMargin + state.s20,yref);
        
        //z axis for Power
        //MaestroG.drawArrow(getSize().width-state.s65,VPos+down2 - state.s5,7,g);
        MaestroG.drawArrowScaled(getSize().width-state.s60,VPos+down2 - state.s5,3,1.2*state.sfactor,g); 
	g.drawLine(getSize().width-RightMargin,VPos+down2 - state.s5,getSize().width-RightMargin + state.s20,VPos+down2 - state.s5);
        
        costhetanew = Math.cos(angle*Math.PI/180.0);    
	sinthetanew = Math.sin(angle*Math.PI/180.0);
        zposnew[0] = (int)MaestroA.mapper(0.0,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
	zposnew[1] = (int)MaestroA.mapper(zmax,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
	
            int axis = state.s90;
            int axis2 = state.s110;
            int axis3 = state.s100;
            x[0] = LeftMargin + (int)(axis*costhetanew)-state.s1;
            x[1] = LeftMargin - (int)(axis*costhetanew)-state.s1;
            y[0] = yref + (int)(axis*sinthetanew);
            y[1] = yref - (int)(axis*sinthetanew);
            
            g.setColor(Color.gray);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            // y axis    
            if(IsHon){
                g.drawLine(x[0],y[0],x[1],y[1]);
                int xA, yA;
                xA = LeftMargin + (int)(axis3*costhetanew);
                yA = yref + (int)(axis3*sinthetanew);
                //MaestroG.drawArrowScaled(xA+state.s6,yA-state.s6,6,state.sfactor,g);
                Polygon pH = new Polygon();
                    pH.addPoint(xA-state.s1, yA);
                    pH.addPoint(xA+state.s5, yA-state.s7);
                    pH.addPoint(xA+state.s6,yA-state.s3);
                    g.drawPolygon(pH);
                    g.fillPolygon(pH);
            }
            // x axis
            if(IsEon){g.drawLine(LeftMargin-state.s1,yref + axis2,LeftMargin-state.s1,TopMargin);
                      //MaestroG.drawArrow(LeftMargin-state.s1,TopMargin,5,g);
                      MaestroG.drawArrowScaled(LeftMargin-state.s1,TopMargin,1,1.2*state.sfactor,g);
            }
            
            // axis replica at right of domain
            x[0] = getSize().width - RightMargin + (int)(axis*costhetanew);
            x[1] = getSize().width - RightMargin - (int)(axis*costhetanew);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            if(IsHon){g.drawLine(x[0],y[0],x[1],y[1]);}
            if(IsEon){g.drawLine(getSize().width - RightMargin,yref + axis2,getSize().width - RightMargin,TopMargin);}
            
            // vertical axis for current (replaces power)
            g.drawLine(LeftMargin-state.s1,yref + axis2 +state.s25,LeftMargin-state.s1,getSize().height-state.s50);
            g.drawLine(getSize().width - RightMargin,yref + axis2 + state.s25,getSize().width - RightMargin,getSize().height-state.s50);
            //MaestroG.drawArrow(LeftMargin-state.s1,yref + axis2 + state.s25,5,g);
            MaestroG.drawArrowScaled(LeftMargin-state.s1,yref + axis2 + state.s20,1,1.2*state.sfactor,g);
    }
    
    private synchronized void drawPoints(Graphics g, int tipo){
        Graphics2D g2d = (Graphics2D)g;
                    
	switch(tipo){
	    case 1:
		if(IsTraceOn){
		    g.setColor(Color.green);
		    //g.drawPolyline(zx,Field_zx,zx.length);
                    g.drawPolyline(zx,Field_zp,zx.length);
		    g.setColor(Color.orange);
		    g.drawPolyline(zy,Field_zy,zy.length);
		    g.setColor(Color.black);
		    //g.drawPolyline(zx_old,Field_zx_old,zx_old.length);
		    //g.drawPolyline(zy_old,Field_zy_old,zy_old.length);
		}
		else{
		    /// NOTE!!!  HARD-CODED!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                    // Nasty to do otherwise using field values, since they change dynamically
                    // Could be done, though
                    
                    int yref = TopMargin+(getSize().height-BottomMargin-TopMargin)/2;
                    int axis2 = state.s110;
                    
                    SkinZ1_z = LeftMargin;   
                    //SkinZ1_x = 73;
                    SkinZ1_x = Decay1[0];
	
                    SkinZ2_z = (int)MaestroA.mapper(skin_depth,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);   
                    //SkinZ2_x = TopMargin+115;
                    SkinZ2_x = yref;
                    
                    PSkinZ1_z = LeftMargin;   
                    //PSkinZ1_x = yref + axis2 +53;
                    PSkinZ1_x = Decay3[0];
	
                    PSkinZ2_z = LeftMargin + (SkinZ2_z -LeftMargin)/2;   
                    PSkinZ2_x = getSize().height-state.s77;
                    
                    //----------------------------------------
                    double angle = 144.50;
                    double costhetanew,sinthetanew;
                    
                    costhetanew = Math.cos(angle*Math.PI/180.0);    
                    sinthetanew = Math.sin(angle*Math.PI/180.0);
                    int axis = state.s80;
                    int xH = LeftMargin + (int)(axis*costhetanew);
                    int yH = Decay2[0];
                    //int yH = yref + (int)(axis*sinthetanew); 
                    //----------------------------------------------
                    //skin depth
                    //if(IsPhasorOn){
                        
                        if(IsEquivalent){
                                double afactor; int Jshift;
                                afactor = 1.0/Math.sqrt(1+(beta*beta/(alpha*alpha)));
                                Jshift = (int)(65*afactor);
                                
                                // change made to use true equivalent Jo
                                double y_eff = (double)(yref + axis2 + state.s100 - (int)(state.s65/Math.sqrt(2))); 
                                if(SkinZ2_z <= (getSize().width-RightMargin)){
                                    //drawLineThick(g,(double)LeftMargin,(double)(yref + axis2 + state.s35 + (Math.sqrt(2)-1)*state.s65),(double)SkinZ2_z,(double)(yref + axis2 + state.s35 + (Math.sqrt(2)-1)*state.s65),3,Color.yellow);
                                    drawLineThick(g,(double)LeftMargin,y_eff,(double)SkinZ2_z,y_eff,3,Color.yellow);
                                    drawLineThick(g,(double)SkinZ2_z,y_eff,(double)SkinZ2_z,(double)(yref + axis2 + state.s100),3,Color.yellow);
                                    drawLineThick(g,(double)SkinZ2_z,(double)(yref + axis2 + state.s100),(double)(getSize().width-RightMargin),(double)(yref + axis2 + state.s100),3,Color.yellow);
                                    g.setColor(Color.black); 
                                }
                                else{
                                    drawLineThick(g,(double)LeftMargin,(double)(yref + axis2 + state.s35),(double)(getSize().width-RightMargin),(double)(yref + axis2 + state.s35),3,Color.yellow);
                                }
                                MaestroG.subsubSansItalic4("< J",""," > = \u03c3 < E",""," >",g,state.font16,SkinZ2_z+state.s10,(int)(y_eff) + state.s5);
                        }
                   
                        if(skin_depth < total_length*wavelength && IsSkinDepthOn){
                            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                      
                            g.setColor(Color.green);
                            if(IsEon){g.drawLine(SkinZ1_z,SkinZ1_x,SkinZ2_z,SkinZ2_x);} // linear approx of decay for E
                            if(IsHon){g.drawLine(xH,yH,SkinZ2_z,SkinZ2_x);} // linear approx of decay for H
                            
                            float[] dashPattern = {10,10};
                            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern,0));
                            g.setColor(Color.green.darker());
                            g.drawLine(SkinZ2_z,SkinZ2_x,SkinZ2_z,yref+axis2-state.s10);
                            g.drawLine(SkinZ2_z,yref+axis2+state.s25,SkinZ2_z,VPos+down);
                        }
                        //----------------------------------------- Print skin depth
                        if(IsSkinDepthOn){
                            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
                            
                            int y = yref+axis2+state.s12;
                            g.setColor(Color.green.darker());
                            int x_here;
                            if(SkinZ2_z < (state.s200+state.s10)){
                                x_here = SkinZ2_z-state.s10;
                            }
                            else{
                                x_here = state.s200;
                            }
                            MaestroG.subscripterSansFrontBack("\u03b4","s"," = "+MaestroA.rounder(skin_depth/wavelength,4)," \u03bb",g,state.font14,x_here,y);
                            
                            int fonto = state.font14;
                            FontMetrics fm;
                            g.setFont(new Font("SanSerif",Font.PLAIN,state.font14));
                            fm = g.getFontMetrics();
                            
                            int dist = fm.stringWidth("\u03b4 s = "+MaestroA.rounder(skin_depth/wavelength,4)+" \u03bb");
                            int xinit2 = x_here + dist;
                            
                            double temp2 = skin_depth;
                            double temp;

                            if(temp2 >= 1.0E15 && frequency > 0.0){
                                temp = temp2/1.0E12;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","9"," km ]",g,fonto,xinit2,y);
                            }

                            else if(temp2 < 1.0e15 && temp2 >= 1.0E12){
                                temp = temp2/1.0E12;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","9"," km ]",g,fonto,xinit2,y); 
                            }
                            else if(temp2 < 1.0e12 && temp2 >= 1.0e9){
                                temp = temp2/1.0E9;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","6"," km ]",g,fonto,xinit2,y);   
                            }
                            else if(temp2 < 1.0e9 && temp2 >= 1.0e6){
                                temp = temp2/1.0E6; 
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","3"," km ]",g,fonto,xinit2,y);
                            }
                            else if(temp2 < 1.0E6 && temp2 >= 1.0E3){
                                temp = temp2/1.0E3;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ km ]","","",g,fonto,xinit2,y);  
                            }
                            else if(temp2 < 1.0E3 && temp2 >= 1.0){
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp2,5)+" [ m ]","","",g,fonto,xinit2,y);
                            }
                            else if(temp2 <1.0 && temp2 >= 1.0E-2){
                                temp = temp2*1.0E2;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ cm ]","","",g,fonto,xinit2,y);
                            }
                            else if(temp2 <1.0E-2 && temp2 >= 1.0E-4){
                                temp = temp2*1.0E3;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ mm ]","","",g,fonto,xinit2,y);
                            }
                            else if(temp2 < 1.0E-4 && temp2 >=1.0E-6 ){
                                temp = temp2*1.0E6;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ \u00b5 m ]","","",g,fonto,xinit2,y);
                            }
                            else if(temp2 < 1.0E-6 && temp2 >=1.0E-9){
                                temp = temp2*1.0E9;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ nm ]","","",g,fonto,xinit2,y);
                            }	
                            else if(temp2 < 1.0E-9 && temp2 >=1.0E-12){
                                temp = temp2*1.0E12;
                                MaestroG.superscripter("  =  "+MaestroA.rounder(temp,5)+" [ 10","-12","  m ]",g,fonto,xinit2,y);
                            }	   
                            else if(temp2 < 1.0E-12 && temp2 >=1.0E-15){
                                temp = temp2*1.0E15;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","-15","  m ]",g,fonto,xinit2,y);
                            }
                            else if(temp2 < 1.0E-15 && temp2 >=1.0e-18){
                                temp = temp2*1.0E18;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","-18","  m ]",g,fonto,xinit2,y);
                            }
                            else if(temp2 < 1.0E-18 && temp2 >=1.0E-21){
                                temp = temp2*1.0E21;
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp,5)+" [ 10","-21","  m ]",g,fonto,xinit2,y);
                            }
                            else if(temp2 < 1.0E-21 && temp2 > 0.0){
                                temp = temp2;
                                MaestroG.superscripterinsert("","","  =  "+temp+" [ m ]","","",g,fonto,xinit2,y);
                            }

                            else if(temp2 == 0.0){
                                MaestroG.superscripterinsert("","","  =  "+MaestroA.rounder(temp2,5)+" [ m ]","","",g,fonto,xinit2,y);
                            }
                        
                            //g.setColor(Color.cyan.darker());
                            //MaestroG.subscripterSansFrontBack("\u03b4","s","/ 2","",g,14,PSkinZ2_z-10,VPos+25+down);
                        }
                    //--------------------------------------------------------------------------------------------------
                    //}
                    // horizontal axis near bottom 
                    g.setColor(Color.lightGray);
                    g.drawLine(LeftMargin-state.s5,VPos+down2-state.s5,getSize().width-RightMargin+state.s6,VPos+down2-state.s5);
        
		    if(IsPhasorOn){
		      //Graphics2D g2d = (Graphics2D)g;
                    
                      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                      
                      // Electric Field decay (phasor magnitude)
                      g.setColor(Color.orange);
                      if(IsEon){
                            g.drawPolyline(zx,Decay1,zx.length);
                            g.drawPolyline(zx,Decay1B,zx.length);
                      }
                      
		      legend1 ="E-phasor Magnitude";
		      if(IsEon){
                          drawLineThick(g,getSize().width/2-state.s120,state.s10,getSize().width/2-state.s90,state.s10,4,Color.orange);
                          g.setColor(Color.red);
                          MaestroG.subscripterB(""+legend1,"","",g, state.font11,getSize().width/2-state.s80,state.s13);
                      }
                      
		      g.setColor(Color.magenta);
		      if(IsHon){
                            g.drawPolyline(zy2,Decay2,zx.length);
                            g.drawPolyline(zy2B,Decay2B,zx.length);
                      }
                      
		      legend1 ="H-phasor Magnitude";
		      if(IsHon){
                          drawLineThick(g,getSize().width/2+state.s50,state.s10,getSize().width/2+state.s80,state.s10,4,Color.magenta);
                          g.setColor(Color.blue);
                          MaestroG.subscripterB(""+legend1,"","",g, state.font11,getSize().width/2+state.s90,state.s13);
                      }
		      
                      // Current decay
                      g.setColor(Color.pink);
                      //if(!IsEquivalent)
                      {g.drawPolyline(zx,Decay3,zx.length);}
                    }
		    
                    g.setColor(Color.black);
		    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        
                    if(IsEon){g.drawPolyline(zx,Field_zx,zx.length);} // draw electric field
                    if(IsHon){g.drawPolyline(zy,Field_zy,zx.length);} // draw magnetic field
		    //g.drawPolyline(zx,Field_zp,zx.length); // draw current
		    
                    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
		    drawRefPoints(g);
                    
                    g.setColor(Color.black);
		}
		break;
	    case 2:
		g.setColor(bgcolor);
                if(IsEon){g.drawPolyline(zx_old,Field_zx_old,zx_old.length);} // draw electri field
                if(IsHon){g.drawPolyline(zy_old,Field_zy_old,zy_old.length);} // draw magnetic field
		g.drawPolyline(zx_old,Field_zp_old,zx_old.length); // draw power
                break;
	}
    }
    
    private synchronized void drawRefPoints(Graphics g){
	int myX, myX2, myZ, myZ2;
	myX = (int)MaestroA.mapper(0,(double)TopMargin,(double)VPos,xmax,xmin);
	myX2 = VPos+down2-state.s5;
        for(int i = 0; i < zx.length; i=i+nlines){
            g.setColor(Color.red); // electric field
            myZ = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
            if(IsEon){g.drawLine(zx[i],Field_zx[i],myZ,myX);}
            
            g.setColor(Color.blue); // magnetic field
            myZ2 = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
            if(IsHon){g.drawLine(zy[i],Field_zy[i],myZ2,myX);}
            
            //g.setColor(Color.magenta.darker()); // power
            //myZ = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
            //g.drawLine(zx[i],Field_zp[i],myZ,myX2);
            
        }
        int Len = state.s12;
        int linesJ = state.s10;
        for(int i = 0; i < zx.length; i=i+linesJ){
            g.setColor(Color.magenta.darker()); // power
            myZ = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
            
            double check = Math.abs(Field_zp[i]- myX2);
            double check2 = check/(double)Len;
            int mythick = state.s1;
            
            //if(check > Len){mythick = 2;}
            //else{mythick = 1;}
            
            double Ax = (double)state.s3;
            double Ay = (double)state.s6;
            int tx = (int)(Ax*check2);
            int ty = (int)(Ay*check2);
        
            Color mycolor = Color.magenta.darker();
            if(Field_zp[i] < myX2){
                if(check > Len){
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)zx[i]-Ax,(double)Field_zp[i]+Ay,mythick,mycolor);
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)zx[i]+Ax,(double)Field_zp[i]+Ay,mythick,mycolor);
                }
                else{
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)(zx[i]-tx),(double)(Field_zp[i]+ty),mythick,mycolor);
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)(zx[i]+tx),(double)(Field_zp[i]+ty),mythick,mycolor);
                }
            }
            else{
                if(check > Len){
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)zx[i]-Ax,(double)Field_zp[i]-Ay,mythick,mycolor);
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)zx[i]+Ax,(double)Field_zp[i]-Ay,mythick,mycolor);
                }
                else{
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)(zx[i]-tx),(double)(Field_zp[i]-ty),mythick,mycolor);
                    drawLineThick(g,(double)zx[i],(double)Field_zp[i],(double)(zx[i]+tx),(double)(Field_zp[i]-ty),mythick,mycolor);
                }
            }
            drawLineThick(g,(double)zx[i],(double)Field_zp[i],myZ,myX2,mythick,mycolor);
        }
    }
    
    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);
    }

    private void labelDetect(){
	X1 = "E (x, t)";
	X2 = "H (y, t)";
    }
    
    private void drawLabels(Graphics g){
	String tmp;
	int yref = TopMargin+(getSize().height-BottomMargin-TopMargin)/2;
        
        g.setFont(LabelFont);
	FontMetrics fm = g.getFontMetrics();
	
        g.setColor(Color.black);
        Graphics2D g2d = (Graphics2D)g;
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        // z axis legends
        tmp = Z1;
	MaestroG.subscripter(tmp,"","",g,state.font13,LeftMargin-fm.stringWidth(tmp),VPos+fm.getHeight()+down);
        tmp = Z2+" = "+total_length+" \u03bb";
	MaestroG.subscripterSansItalic6("h",""," = "+MaestroA.rounder(total_length,6)," \u03bb",g,state.font13,getSize().width-RightMargin-fm.stringWidth(tmp)/3-state.s2,VPos+fm.getHeight()+down);
	g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        g.setFont(LabelFont);
        g.setColor(Color.red);
        
        g.setFont(new Font("SanSerif",Font.BOLD,14));
        fm = g.getFontMetrics();
        
        tmp="Ex( t )  ";
	if(IsEon){MaestroG.subscripterB("E","x","(t)",g,state.font13,LeftMargin-fm.stringWidth(tmp)-state.s20,TopMargin+fm.getHeight());
        	  //MaestroG.subscripterSansItalic3("E","x","( t )",g,state.font12,LeftMargin-fm.stringWidth(tmp)-20,TopMargin+fm.getHeight());
        }

        g.setColor(Color.blue);
	if(IsHon){MaestroG.subscripterB("H","y","(t)",g,state.font13,state.s18,yref+state.s10);
                //MaestroG.subscripterSansItalic3("H","y","( t )",g,state.font12,12,yref+10);
        }
                
        g.setColor(Color.magenta.darker());
	MaestroG.subscripterB("J","x","(z,t)",g,state.font13,LeftMargin-fm.stringWidth(tmp)-state.s30,Decay3[0]);
        //MaestroG.subscripterSansItalic3("J","x","(z,t)",g,state.font12,LeftMargin-fm.stringWidth(tmp)-25,Decay3[0]);
        g.setColor(Color.black);
	MaestroG.subscripterSansItalic3("z","","",g,state.font16,getSize().width-state.s55,yref-state.s5);
        MaestroG.subscripterSansItalic3("z","","",g,state.font16,getSize().width-state.s55,VPos+down2-state.s10);
        
        tmp="E0";
        g.setColor(Color.black);
	if(IsEon){MaestroG.subsubSansItalic3("E","0","","",g,state.font16,LeftMargin+fm.stringWidth(tmp) + state.s10,TopMargin+15*fm.getHeight()/10);   
        }
        g.drawLine(LeftMargin-state.s2,TopMargin+state.s12,LeftMargin + state.s8,TopMargin+state.s12);
    }
    
    private void drawZeroLine(Graphics g){
	int myX;
	myX = (int)MaestroA.mapper(0,(double)TopMargin,(double)VPos,xmax,xmin);
	g.setColor(Color.red);
	g.drawLine(LeftMargin+state.s1,myX,getSize().width-RightMargin-state.s1,myX);
    }
    
    
    public synchronized void reset(){
	IsYRangeMaxSet = false;
	IsYRangeMinSet = false;
	IsXRangeMaxSet = false;
	IsXRangeMinSet = false;
        IsPRangeMaxSet = false;
	IsPRangeMinSet = false;
	IsZRangeMinSet = false;
	IsZRangeMaxSet = false;
	IsTraceOn = false;
	IsCleanUpOn = false;
    }
    
    public synchronized void cleanUp(){
	IsCleanUpOn=true;
    }
    
    public synchronized void setYRangeMax(double ymax){
	this.ymax = ymax;
	IsYRangeMaxSet = true;
    }
    
    public synchronized void setYRangeMin(double ymin){
	this.ymin = ymin;
	IsYRangeMinSet = true;
    }
    
    public synchronized void setZRangeMax(double zmax){
	this.zmax = zmax;
	IsZRangeMaxSet = true;
    }
    
    public synchronized void setZRangeMin(double zmin){
	this.zmin = zmin;
	IsZRangeMinSet = true;
    }
    
    public synchronized void setXRangeMax(double xmax){
	this.xmax = xmax;
	IsXRangeMaxSet = true;
    }
    
    public synchronized void setXRangeMin(double xmin){
	this.xmin = xmin;
	IsXRangeMinSet = true;
    }
    
    public synchronized void setTrace(boolean IsTraceOn){
	this.IsTraceOn = IsTraceOn;
	this.clean_memory();
    }
    
    public synchronized void setDynamics(boolean IsDynamic){
	this.IsDynamic = IsDynamic;
    }
    

    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;
	    drawAxis(g);
	    drawLabels(g);
	}
	drawZeroLine(g);
	if(!IsTraceOn){
	    drawPoints(g,2);//This cleans the previous graph
	}
	drawPoints(g,1);//This draws the new graph
	drawAxis(g);
	drawRotor(g);
	push();
    }
    
    
    public synchronized void plot(double xdata[], double tEField_z[], double tHField_z[], double tPField_z[], double tau){
   
	if(N != xdata.length){
	    N = xdata.length;
	    z = new double[N];
	    EField_z = new double[N];
	    HField_z = new double[N];
	    PField_z = new double[N];
	    zx = new int[N];
	    zy = new int[N];
	}
	for(int i = 0; i < N; i++){
	    z[i] = xdata[i];
	    EField_z[i] = tEField_z[i] * E_ratio;
	    HField_z[i] = tHField_z[i] * H_ratio ;
	    PField_z[i] = tPField_z[i] * P_ratio ;
	}
	//ignition();
	
	N = z.length;
	//Find the boundaries for data
	if(!IsXRangeMaxSet){ xmax = MaestroA.getMax(EField_z);}
	if(!IsXRangeMinSet){ xmin = MaestroA.getMin(EField_z);}
		
    	if(!IsYRangeMaxSet){ ymax = MaestroA.getMax(HField_z);}
	if(!IsYRangeMinSet){ ymin = MaestroA.getMin(HField_z);}
	if(!IsPRangeMaxSet){ pmax = MaestroA.getMax(PField_z);}
	if(!IsPRangeMinSet){ pmin = MaestroA.getMin(PField_z);}
	
	if(!IsZRangeMaxSet){ zmax = z[z.length-1];}
	if(!IsZRangeMinSet){ zmin = z[0]; }
	
	//Confine data
	MaestroA.confiner(z,zmax,zmin);
	MaestroA.confiner(HField_z,ymax,ymin);
	MaestroA.confiner(EField_z,xmax,xmin);
        MaestroA.confiner(PField_z,pmax,pmin);
        
	int myY;
	double Deltax = total_length*wavelength/zx.length;
	double angle = 140.0;
	double costhetanew,sinthetanew;
        
        costhetanew = Math.cos(angle*Math.PI/180.0);    
	sinthetanew = Math.sin(angle*Math.PI/180.0);
        int yref = TopMargin+(getSize().height-BottomMargin-TopMargin)/2;
	
        for(int i = 0; i < zx.length; i++){
		double Factor1 = Ex*Math.exp(-alpha*Deltax*i);
		double Factor2 = Hy*Math.exp(-alpha*Deltax*i);
		double Factor3 = Ex*Math.exp(-alpha*Deltax*i);
                zx[i] = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
		Field_zx[i] = (int)MaestroA.mapper(EField_z[i],(double)TopMargin,(double)(getSize().height-BottomMargin),xmax,xmin);
		Decay1[i] = (int)MaestroA.mapper(Factor1*E_ratio,(double)TopMargin,(double)(getSize().height-BottomMargin),xmax,xmin);
		Decay1B[i] = yref + (yref - Decay1[i]);
                Field_zp[i] = (int)MaestroA.mapper(EField_z[i],(double)TopMargin2,(double)(getSize().height-BottomMargin2-state.s80),pmax,pmin);
		Decay3[i] = (int)MaestroA.mapper(Factor3*E_ratio,(double)TopMargin2,(double)(getSize().height-BottomMargin2-state.s80),pmax,pmin);
		
		zy[i] = zx[i] + (int)MaestroA.mapper(costhetanew*HField_z[i],Orth_Axis_Front,-Orth_Axis_Back,ymax,ymin);	
		
    		Field_zy[i] = (int)MaestroA.mapper(sinthetanew*HField_z[i],(double)TopMargin,(double)getSize().height-BottomMargin,ymin,ymax);
		zy2[i] = zx[i] + (int)MaestroA.mapper(costhetanew*Factor2*H_ratio,Orth_Axis_Front,-Orth_Axis_Back,ymax,ymin);	
		Decay2[i] = (int)MaestroA.mapper(sinthetanew*Factor2*H_ratio,(double)TopMargin,(double)getSize().height-BottomMargin,ymin,ymax);
                zy2B[i] = zx[i] - (int)MaestroA.mapper(costhetanew*Factor2*H_ratio,Orth_Axis_Front,-Orth_Axis_Back,ymax,ymin);	
		Decay2B[i] = (int)MaestroA.mapper(-sinthetanew*Factor2*H_ratio,(double)TopMargin,(double)getSize().height-BottomMargin,ymin,ymax);
	} 
        
	repaint();
    }
    
    private synchronized void push(){
	if(zx.length != zx_old.length){
	    zx_old = new int[zx.length];
	    zy_old = new int[zx.length];
	    Field_zx_old = new int[zx.length];
	    Field_zy_old = new int[zx.length];
            Field_zp_old = new int[zx.length];
	}
    
	for(int i = 0; i < zx.length; i++){
	    zx_old[i] = zx[i];
	    zy_old[i] = zy[i];
	    Field_zx_old[i] = Field_zx[i];
	    Field_zy_old[i] = Field_zy[i];
            Field_zp_old[i] = Field_zp[i];
	}
    }
    
     private void clean_memory(){
	if(zx.length != zx_old.length){
	    zx_old = new int[zx.length];
	    zy_old = new int[zx.length];
	    Field_zx_old = new int[zx.length];
            Field_zy_old = new int[zx.length];
            Field_zp_old = new int[zx.length];
	}
    
	for(int i = 0; i < zx.length; i++){
	    zx_old[i] = zx[i];
	    zy_old[i] = zy[i];
	    Field_zx_old[i] = 0;
	    Field_zy_old[i] = 0;
            Field_zp_old[i] = 0;
	}
    }
    
    
    public synchronized void setTitle(String TITLE){
	this.TITLE = TITLE;
    }
    
    public synchronized void setLabels(String Z1, String Z2, String X1, String X2){
	this.Z1 = Z1;
	this.Z2 = Z2;
	this.X1 = X1;
	this.X2 = X2;
    }
    
    public synchronized void setMargins(int LeftMargin, int RightMargin, int TopMargin, int BottomMargin){
	this.LeftMargin = LeftMargin;
	this.RightMargin = RightMargin;
	this.TopMargin = TopMargin;
	this.BottomMargin = BottomMargin;
    }
    
    public synchronized void setPlanes(double zpos1, double zpos2, boolean refz){
	this.zpos[0] = zpos1;
	this.zpos[1] = zpos2;
        this.refz = refz;
    }
    
    public synchronized void setRotor(int current_z){
	this.current_z = current_z;
	if(current_z >= zx.length){ current_z = zx.length-1; }
    }
    
    public synchronized void setAlpha(double alpha, double beta, double frequency){
	this.alpha = alpha;
        this.beta = beta;
        this.frequency = frequency;
    }
    
    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 setLines(int nlines){
	this.nlines = nlines;
    }
    
    public synchronized void setEx(double Ex){
	this.Ex = Ex;
    }
    
    public synchronized void setHy(double Hy){
	this.Hy = Hy;
    }
    
    public synchronized void setPz(double Pz){
	this.Pz = Pz;
        this.pmax = Pz;
        this.pmin = -Pz;
    }
    
    public synchronized void setPhasor(boolean IsPhasorOn){
	this.IsPhasorOn = IsPhasorOn;
    }
    
    public synchronized void setEon(boolean IsEon){
	this.IsEon = IsEon;
    }
    
    public synchronized void setHon(boolean IsHon){
	this.IsHon = IsHon;
    }
    
    public synchronized void setSkinDepthOn(boolean IsSkinDepthOn){
	this.IsSkinDepthOn = IsSkinDepthOn;
    } 
    
    public synchronized void setEquivalent(boolean IsEquivalent){
	this.IsEquivalent = IsEquivalent;
    }
    
}
