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

public class PlaneWaveCanvas extends Canvas{
    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 double zpos[];   //position of the reference planes
    private double alpha, 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 = 2;
    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.s150;
        down2 = state.s140;
        down3 = state.s160;
        yshift = state.s200+state.s50;
        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 = 10.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 = true;
        
	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< 2 ; i++){
            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]+state.s1,myZ,myX,3,Color.red.brighter());
                    }
                    else{
                        drawLineThick(g,zx[current_z],Field_zx[current_z]-state.s1,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
                drawLineThick(g,zx[current_z],Field_zp[current_z]+state.s1,myZ,VPos+down2-state.s5,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);
                    g.drawLine(myZ,state.s60,myZ,yref + axis2); 
                    g.drawLine(myZ,yref + axis2 + state.s35,myZ,getSize().height-state.s60); 
                }
                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);
        //======================================================================
        Polygon pX1 = new Polygon();
                pX1.addPoint(getSize().width-state.s65+state.s7,yref);
		pX1.addPoint(getSize().width-state.s65,yref-state.s2);
		pX1.addPoint(getSize().width-state.s65,yref+state.s2);
                g.drawPolygon(pX1);
		g.fillPolygon(pX1);
                
        //======================================================================
	g.drawLine(getSize().width-RightMargin,yref,getSize().width-RightMargin+state.s20,yref);
        
        //z axis for Power
        //MaestroG.drawArrow(getSize().width-state.s65,VPos+down2-5,7,g);
	g.drawLine(getSize().width-RightMargin,VPos+down2-5,getSize().width-RightMargin+state.s20,VPos+down2-5);
        Polygon pX2 = new Polygon();
                pX2.addPoint(getSize().width-state.s65+state.s7,VPos+down2-5);
		pX2.addPoint(getSize().width-state.s65,VPos+down2-5-state.s2);
		pX2.addPoint(getSize().width-state.s65,VPos+down2-5+state.s2);
                g.drawPolygon(pX2);
		g.fillPolygon(pX2);
                
        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);

                Polygon pH = new Polygon();
                    pH.addPoint(xA-state.s1, yA);
                    pH.addPoint(xA+state.s7, yA - state.s3);
                    pH.addPoint(xA+state.s4,yA - state.s7);
                    g.drawPolygon(pH);
                    g.fillPolygon(pH);
            }
            // x axis
            if(IsEon){g.drawLine(LeftMargin,yref + axis2,LeftMargin,TopMargin);
                    //MaestroG.drawArrow(LeftMargin-state.s1,TopMargin,5,g);
            
                    Polygon pX4 = new Polygon();
                        pX4.addPoint(LeftMargin,TopMargin -state.s7);
                        pX4.addPoint(LeftMargin+state.s2,TopMargin);
                        pX4.addPoint(LeftMargin-state.s2,TopMargin);
                        g.drawPolygon(pX4);
                        g.fillPolygon(pX4);
            }
            // 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 power
            g.drawLine(LeftMargin,yref + axis2 + state.s25,LeftMargin,getSize().height - state.s60);
            g.drawLine(getSize().width - RightMargin,yref + axis2 + state.s25,getSize().width - RightMargin,getSize().height - state.s65);
            //MaestroG.drawArrow(LeftMargin,yref + axis2 + state.s25,5,g);
            Polygon pX3 = new Polygon();
                pX3.addPoint(LeftMargin,yref + axis2 + state.s25 -state.s7);
		pX3.addPoint(LeftMargin+state.s2,yref + axis2 + state.s25);
		pX3.addPoint(LeftMargin-state.s2,yref + axis2 + state.s25);
                g.drawPolygon(pX3);
		g.fillPolygon(pX3);
    }
    
    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 = Decay1[0];
	
                    SkinZ2_z = (int)MaestroA.mapper(skin_depth,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);   
                    SkinZ2_x = yref;
                    
                    PSkinZ1_z = LeftMargin;   

                    PSkinZ1_x = Decay3[0];
	
                    PSkinZ2_z = LeftMargin + (SkinZ2_z -LeftMargin)/2;   
                    //PSkinZ2_x = getSize().height-state.s70-7;
                    PSkinZ2_x = VPos+down2-5;
                    
                    //----------------------------------------
                    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];
                    //----------------------------------------------
                    //skin depth
                    //if(IsPhasorOn){
                        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
                            g.setColor(Color.cyan.darker());
                            g.drawLine(PSkinZ1_z,PSkinZ1_x,PSkinZ2_z,PSkinZ2_x); // linear approx of decay for Power
                            
                            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);
                            
                            float[] dashPattern2 = {5,5};
                            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern2,0));
                            g.setColor(Color.cyan.darker());
                            g.drawLine(PSkinZ2_z,PSkinZ2_x,PSkinZ2_z,VPos+down+10);
                            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
                            
                            g.setColor(Color.green.darker());
                            MaestroG.subscripterSansFrontBack("\u03b4","s"," = "+MaestroA.rounder(skin_depth/wavelength,4)," \u03bb",
                                    g,state.font14,SkinZ2_z-state.s10,yref+axis2+state.s10);
                            g.setColor(Color.cyan.darker());
                            MaestroG.subscripterSansFrontBack("\u03b4","s","/ 2","",g,state.font14,PSkinZ2_z-state.s10,VPos+state.s25+down);
                        }
                    //}
                    // horizontal axis near bottom 
                    g.setColor(Color.lightGray);
                    g.drawLine(LeftMargin-state.s5,VPos+down2-5,getSize().width-RightMargin+state.s6,VPos+down2-5);
        
		    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);
                            //g.drawLine(getSize().width/2-state.s110,state.s8,getSize().width/2-state.s90,state.s8);
                            //g.drawLine(getSize().width/2-state.s110,state.s7,getSize().width/2-state.s90,state.s7);
                      }
                      g.fillRect(getSize().width/2-state.s120,state.s7,state.s30,state.s3);
                        
		      g.setColor(Color.red);
		      legend1 ="E-phasor Magnitude";
		      if(IsEon){MaestroG.subscripter(""+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);
                            //g.drawLine(getSize().width/2+state.s60,state.s8,getSize().width/2+state.s80,state.s8);
                            //g.drawLine(getSize().width/2+state.s60,state.s7,getSize().width/2+state.s80,state.s7);
                      }
                      g.fillRect(getSize().width/2+state.s50,state.s7,state.s30,state.s3);
                        
		      g.setColor(Color.blue);
		      legend1 ="H-phasor Magnitude";
		      if(IsHon){MaestroG.subscripter(""+legend1,"","",g, state.font11,getSize().width/2+state.s90,state.s13);}
                      // Power decay
                      g.setColor(Color.pink);
                      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 power
		    
                    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-5;
        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);
        }
    }
    
    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);
	
        // z axis legends
        tmp = Z1;
	MaestroG.subscripter(tmp,"","",g,state.font13,LeftMargin-fm.stringWidth(tmp),VPos+fm.getHeight()+state.s2+down);
        tmp = Z2+" = "+total_length+" \u03bb";
	MaestroG.subscripterSansItalic6("l",""," = "+MaestroA.rounder(total_length,6)," \u03bb",
                g,state.font13,getSize().width-RightMargin-fm.stringWidth(tmp)/2,VPos+fm.getHeight()+state.s2+down);
	
        g.setFont(LabelFont);
        g.setColor(Color.red);
        
        tmp="Ex( t )";
	if(IsEon){MaestroG.subscripterSansItalic3("E","x","( t )",g,state.font14,LeftMargin-fm.stringWidth(tmp)-state.s20,TopMargin+fm.getHeight());}
        
        g.setColor(Color.blue);
	if(IsHon){MaestroG.subscripterSansItalic3("H","y","( t )",g,state.font14,state.s12,yref+state.s10);}
        
        g.setColor(Color.magenta.darker());
	MaestroG.subscripterSansItalic3("S","","( t )",g,state.font14,LeftMargin-fm.stringWidth(tmp)-state.s20,Decay3[0]);
        
        g.setColor(Color.black);
	MaestroG.subscripter("z","","",g,state.font14,getSize().width-state.s55,yref-state.s5);
        MaestroG.subscripter("z","","",g,state.font14,getSize().width-state.s55,VPos+down2-state.s10);
    }
    
    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(-2.0*alpha*Deltax*i)*Math.sqrt(Math.cos(-tau));
                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(PField_z[i],(double)TopMargin2,
                              (double)(getSize().height-BottomMargin2),pmax,pmin);
		Decay3[i] = (int)MaestroA.mapper(Factor3*P_ratio,(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);
		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){
	this.zpos[0] = zpos1;
	this.zpos[1] = zpos2;
    }
    
    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){
	this.alpha = alpha;
    }
    
    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;
    } 
}
