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;
    private boolean IsYRangeMaxSet, IsYRangeMinSet, IsXRangeMaxSet, IsXRangeMinSet; 
    private boolean IsZRangeMaxSet, IsZRangeMinSet;
    private int Orth_Axis_Front=63, Orth_Axis_Back=63; //Size of orthogonal axis (y-direction);
    private int axis_one_ref, axis_two_ref, down, down2;
    private int LeftMargin, RightMargin, TopMargin, BottomMargin;
    
    private double zpos[];   //position of the reference planes
    private double alpha, total_length, wavelength, Ex, Hy, skin_depth;
    private static final String znames[] ={"A", "B"};
    private int WIDTH, HEIGHT, SkinZ1_z, SkinZ1_x, SkinZ2_z, SkinZ2_x;
    private String Z1, Z2, Z3, X1, X2, X3, X4, TITLE, legend1, legend2;
    private Image im;
    private Graphics buf;
    private int VPos = 0;
   
    private Font TitleFont;
    private Font LabelFont;
    private double[] z;
    //private double myangle = 135.0+45;
    private double[] EField_z, HField_z;
    private int[] Field_zx, Field_zx_old, Decay1, Decay2; 
    private int[] Field_zy, Field_zy_old;
    private int[] zx, zx_old, zy, zy_old, zy2;
    private int current_z;
    private double H_ratio, E_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 = 10;
    private double angle = 135.0;
    private double costhetanew,sinthetanew;   
    PlaneWave_State state;
    
    public PlaneWaveCanvas(PlaneWave_State state){
	super();
        this.state = state;
        
        TitleFont = new Font("SanSerif",Font.BOLD,state.s11);
        LabelFont = new Font("SanSerif",Font.PLAIN,state.s11);
    
	N = 360;
	setBackground(bgcolor);
	xmax = 2.0;
	xmin = -2.0;
	ymax = 2.0;
	ymin = -2.0;
	zmax = 1.0;
	zmin = 0.0;
        skin_depth = Double.POSITIVE_INFINITY;
        
        Orth_Axis_Front = state.s63; Orth_Axis_Back = state.s63;
        down = state.s20; down2 = state.s10;
        LeftMargin = state.s95; 
        RightMargin = state.s80; 
        TopMargin = state.s60; 
        BottomMargin = state.s60;
        
	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);
        
        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;
	IsTraceOn = false;
	IsCleanUpOn = false;
	IsDynamic = false;
	IsPhasorOn = true;
        IsSkinDepthOn = true;
        
        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;
        
        try{
	    z = new double[N];
	    EField_z = new double[N];
	    HField_z = new double[N];
	    Field_zx = new int[N];
	    Field_zx_old = new int[N];
	    Decay1 = new int[N];
	    Decay2 = new int[N];
	    Field_zy = new int[N];
	    Field_zy_old = new int[N];
	    zx = new int[N];
	    zx_old = new int[N];
	    zy = new int[N];
	    zy2 = 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;
	    Field_zx[i] = 0;
	    Field_zx_old[i] = 0;
	    Decay1[i] = 0;
	    Decay2[i] = 0;
	    zx[i] = i;
	    zx_old[i] = i;
	    zy[i] = i;
	    zy_old[i] = i;
	    zy2[i] =i;
	}
	//Positions of reference planes
	zpos = new double[2];
	//zpos[0] = 0.0;
	//zpos[1] = 0.0;
	
	//Position of rotor
	current_z = 0;
	//ignition();
    }
    
    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);
	//draw dark half horizontal plane
        drawDarkBack(g);
	drawPlanes(g);
	drawDarkBack2(g);
        
        //drawAxis(g);
	labelDetect();
	drawZeroLine(g);
	drawLabels(g);
	
        drawPoints(g,1);
	drawLabels(g);
	
        drawRotor(g);
	
        // Arrow for z-axis
	g.setColor(Color.black);
	//MaestroG.drawArrow(getSize().width-state.s65,getSize().height/2,7,g);
        //======================================================================
        Polygon pX1 = new Polygon();
                pX1.addPoint(getSize().width-state.s65+state.s7,getSize().height/2);
		pX1.addPoint(getSize().width-state.s65,getSize().height/2-state.s2);
		pX1.addPoint(getSize().width-state.s65,getSize().height/2+state.s2);
                g.drawPolygon(pX1);
		g.fillPolygon(pX1);
                
        //======================================================================
	
        
	g.drawLine(getSize().width-state.s80,getSize().height/2,getSize().width-state.s65,getSize().height/2);
    }
    
    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);
	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);
		
		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);
        } 	
        // find skin depth location	
    }
    
    private synchronized void drawRotor(Graphics g){
	int myX, myZ;
	int current_z;
	 
        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){drawLineThick(g,zx[current_z],Field_zx[current_z],myZ,myX,3,Color.red.brighter());}
            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());}
	}
    }
    
    private synchronized void drawPlanes(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 = 135.0;
	double costhetanew,sinthetanew;
        
        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);
	
        for(int i = 0; i < 2; i++){
            alpha = 0.1f;
        
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
        
            myX = (int)MaestroA.mapper(zpos[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
	    myY = (int)MaestroA.mapper(0.0,(double)TopMargin,(double)getSize().height-BottomMargin,xmax,xmin);
	    
            x[0] = myX + (int)(costheta*Orth_Axis_Front);
	    x[1] = x[0];
	    x[2] = myX - (int)(costheta*Orth_Axis_Back);
	    x[3] = x[2];
	
	    y[0] = myY + (int)(sintheta*Orth_Axis_Front)+9*HEIGHT/20;
	    y[1] = myY + (int)(sintheta*Orth_Axis_Front)-9*HEIGHT/20;
	    y[2] = myY - (int)(sintheta*Orth_Axis_Back)-9*HEIGHT/20;
	    y[3] = myY - (int)(sintheta*Orth_Axis_Back)+9*HEIGHT/20;
	

	    g.setColor(Color.lightGray);
            g.fillPolygon(x,y,4);
	    g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f));
            
            if(i == 0){
                g.setColor(Color.black);
            }
            else{
                g.setColor(Color.red.darker());
            }
            g.setFont(TitleFont);
	    if(i == 0){g.drawString(znames[i],myX+state.s35,BottomMargin-state.s5);}
	    else{g.drawString(znames[i],myX+state.s45,BottomMargin+state.s5);}
	            
            g.setColor(bgcolor.darker());
	    g.drawPolygon(x,y,4);
	    
            g2d.setComposite(AlphaComposite.getInstance(rule, 0.5f));
            g.drawLine(x[0],(y[0]+y[1])/2,x[2],(y[2]+y[3])/2);
	    g.drawLine((x[0]+x[2])/2,(y[1]+y[2])/2,(x[0]+x[2])/2,(y[0]+y[3])/2);
            float[] dashPattern = {3,3};
            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern,0));
            g.drawLine((x[0]+x[2])/2,(y[0]+y[3])/2,(x[0]+x[2])/2,VPos+down2);
            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER));
            
            g2d.setComposite(AlphaComposite.getInstance(rule, 0.9f));
            if(i==0){
                g.setColor(Color.black);
                MaestroG.subscripterCompact("z","A","",g,state.font11,(x[0]+x[2])/2-state.s4,getSize().height-state.s16);
            }
            else if(i==1){
                g.setColor(Color.red.darker());
                MaestroG.subscripterCompact("z","B","",g,state.font11,(x[0]+x[2])/2-state.s4,getSize().height-state.s6);
            }
	}
            // draw fixed axes
            x[0] = state.s28;
	    x[1] = state.s28;
	    x[2] = state.s162;
	    x[3] = state.s162;
	
	    y[0] = state.s300+state.s45;
	    y[1] = state.s139;
	    y[2] = state.s5;
	    y[3] = state.s200+state.s11;
            
            g.setColor(Color.black);
	    g2d.setComposite(AlphaComposite.getInstance(rule, 0.9f));
            g.drawLine(x[0]-state.s7,(y[0]+y[1])/2+state.s7,x[2],(y[2]+y[3])/2);
	    g.drawLine((x[0]+x[2])/2,(y[1]+y[2])/2-state.s10,(x[0]+x[2])/2,(y[0]+y[3])/2);
            //MaestroG.drawArrow((x[0]+x[2])/2,(y[1]+y[2])/2-state.s10,5,g);
            Polygon pX4 = new Polygon();
                        pX4.addPoint((x[0]+x[2])/2,(y[1]+y[2])/2-state.s17);
                        pX4.addPoint((x[0]+x[2])/2 + state.s2,(y[1]+y[2])/2-state.s10);
                        pX4.addPoint((x[0]+x[2])/2 - state.s2,(y[1]+y[2])/2-state.s10);
                        g.drawPolygon(pX4);
                        g.fillPolygon(pX4);
            //==================================================================
            //MaestroG.drawArrow(x[0]-state.s7,(y[0]+y[1])/2+state.s7,10,g); // oblique arrow
            int xA, yA;
                xA = x[0]-state.s7;
                yA = (y[0]+y[1])/2+state.s7;

                Polygon pH = new Polygon();
                    pH.addPoint(xA, yA);
                    pH.addPoint(xA+state.s7, yA - state.s3);
                    pH.addPoint(xA+state.s3,yA - state.s7);
                    g.drawPolygon(pH);
                    g.fillPolygon(pH);
            //==================================================================
            x[0] = state.s700+state.s33-state.s50;
	    x[1] = state.s700+state.s33-state.s50;
	    x[2] = state.s800+state.s67-state.s50;
	    x[3] = state.s800+state.s67-state.s50;
	
	    y[0] = state.s300+state.s45;
	    y[1] = state.s139;
	    y[2] = state.s5;
	    y[3] = state.s200+state.s11;
            
            g.setColor(Color.black);
	    g2d.setComposite(AlphaComposite.getInstance(rule, 0.9f));
            g.drawLine(x[0],(y[0]+y[1])/2,x[2],(y[2]+y[3])/2);
	    g.drawLine((x[0]+x[2])/2,(y[1]+y[2])/2,(x[0]+x[2])/2,(y[0]+y[3])/2);
            //MaestroG.drawArrow((x[0]+x[2])/2,(y[1]+y[2])/2,5,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.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
                    SkinZ1_z = state.s95;   
                    SkinZ1_x = state.s73;
	
                    SkinZ2_z = (int)MaestroA.mapper(skin_depth,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);   
                    SkinZ2_x = state.s175;
                    
                    //skin depth
                    //if(IsPhasorOn){
                        if(skin_depth < total_length*wavelength && IsSkinDepthOn){
                            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                      
                            g.setColor(new Color(0,200,0));
                            g.drawLine(SkinZ1_z,SkinZ1_x,SkinZ2_z,SkinZ2_x);

                            float[] dashPattern = {10,10};
                            g2d.setStroke(new BasicStroke(1.0F,BasicStroke.CAP_BUTT,BasicStroke.JOIN_MITER,10.0F,dashPattern,0));
                            g.drawLine(SkinZ2_z,SkinZ2_x,SkinZ2_z,VPos+down+state.s5);
                            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.font12,SkinZ2_z-state.s6,VPos+state.s17+down);
                        }
                    //}
                    // horizontal axis near bottom 
                    g.setColor(Color.lightGray);
                    g.drawLine(LeftMargin-state.s5,VPos+down2-state.s2,getSize().width-RightMargin+state.s6,VPos+down2-state.s2);
        
		    if(IsPhasorOn){
                        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
                        g.setColor(Color.orange);
                        g.drawPolyline(zx,Decay1,zx.length);
                        g.fillRect(getSize().width/2-state.s120,state.s7,state.s30,state.s3);
                        g.setColor(Color.red);
                        legend1 ="E-phasor Magnitude";
                        MaestroG.subscripter(""+legend1,"","",g, state.font11,getSize().width/2-state.s80,state.s13);

                        g.setColor(Color.magenta);
                        g.drawPolyline(zy2,Decay2,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";
                        MaestroG.subscripter(""+legend1,"","",g, state.font11,getSize().width/2+state.s90,state.s13);
                    }
		    
                    g.setColor(Color.black);
		    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        
                    if(IsEon){g.drawPolyline(zx,Field_zx,zx.length);}
		    if(IsHon){g.drawPolyline(zy,Field_zy,zx.length);}
		    
                    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);}
                if(IsHon){g.drawPolyline(zy_old,Field_zy_old,zy_old.length);}
		break;
	}
    }
    
    private synchronized void drawRefPoints(Graphics g){
	int myX, myZ, myZ2;
	myX = (int)MaestroA.mapper(0,(double)TopMargin,(double)VPos,xmax,xmin);
	/*
        if(IsEon){
        g.setColor(Color.red);
            for(int i = 0; i < zx.length; i=i+10){
                myZ = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
                g.drawLine(zx[i],Field_zx[i],myZ,myX);
            }
        }
        if(IsHon){
	g.setColor(Color.blue);
            for(int i = 0; i < zy.length; i=i+10){
                myZ = (int)MaestroA.mapper(z[i],(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
                g.drawLine(zy[i],Field_zy[i],myZ,myX);
            }
        }*/
        
        for(int i = 0; i < zx.length; i=i+nlines){
            g.setColor(Color.red);
            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);
            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);}
        }
    }
    
    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 = String.valueOf(MaestroA.rounder(xmax,2))+" ";
	//X2 = String.valueOf(MaestroA.rounder(xmin,2))+" ";
	X1 = "E (x, t)";
	X2 = "H (y, t)";
	X3 = "_";
	X4 = "|";
    }
    
    private void drawLabels(Graphics g){
	String tmp;
	
        g.setFont(LabelFont);
	FontMetrics fm = g.getFontMetrics();
	
        g.setColor(Color.black);
	
        tmp = Z1;
	MaestroG.subscripter(tmp,"","",g,state.font12,LeftMargin-state.s3,VPos+fm.getHeight()+state.s1+down2 + state.s5);
        tmp = Z2+" = "+total_length+" \u03bb";
	MaestroG.subscripterSansItalic6("l",""," = "+MaestroA.rounder(total_length,6)," \u03bb",
                g,state.font12,getSize().width-RightMargin-fm.stringWidth(tmp)/2+state.s1,VPos+fm.getHeight()+state.s1+down2 + state.s5);
	
        g.setFont(LabelFont);
	
        tmp = Z3;
	g.setColor(Color.red);
	g.drawString(tmp,getSize().width-RightMargin+state.s15,getSize().height/2);
	g.setColor(Color.red);
	tmp = X1;
	MaestroG.subscripterSansItalic3("E","x","( t )",g,state.font12,LeftMargin-state.s40-state.s5,TopMargin+state.s10);
        tmp = X2;
	g.setColor(Color.blue);
	MaestroG.subscripterSansItalic3("H","y","( t )",g,state.font12,state.s6,getSize().height/2-(int)(4*(Orth_Axis_Back*costheta)/5));
        
        g.setColor(Color.gray);
        tmp = X3;
	//g.drawString(tmp,LeftMargin-5,VPos-1);
	//g.drawString(tmp,LeftMargin-5, TopMargin);
	
        tmp = X4;
        g.drawString(tmp,LeftMargin-state.s1,VPos+state.s2+down2);
	g.drawString(tmp,getSize().width-RightMargin-fm.stringWidth(tmp)/2,VPos+state.s2+down2);
        
        g.setColor(Color.black);
        
	tmp = TITLE;
	g.setFont(TitleFont);
	g.drawString(tmp,LeftMargin+state.s2,TopMargin-fm.getHeight()/2);
    }
    
    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;
	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
	drawPlanes(g);
	drawRotor(g);
	push();
    }
    
    
    public synchronized void plot(double xdata[], double tEField_z[], double tHField_z[]){
   
	if(N != xdata.length){
	    N = xdata.length;
	    z = new double[N];
	    EField_z = new double[N];
	    HField_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 ;
	   
	}
	//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(!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);
	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);
        
	for(int i = 0; i < zx.length; i++){
		double Factor1 = Ex*Math.exp(-alpha*Deltax*i);
		double Factor2 = Hy*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);
		
		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);
	
	} 	
	
	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];
	}
    
	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];
	}
    }
    
     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];
	}
    
	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;
	}
    }
    
    
    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 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;
    }
        
    private void drawDarkBack(Graphics g){
	int x[], y[], myX, myW, myW2;
	double zposmax, zposmin;
        
        zposmax = Math.max(zpos[0],zpos[1]);
        zposmin = Math.min(zpos[0],zpos[1]);
        
        x = new int[4];
	y = new int[4];
	myX = (int)MaestroA.mapper(0,(double)TopMargin,(double)VPos,xmax,xmin);
        myW = (int)MaestroA.mapper(zposmax,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
	myW2 = (int)MaestroA.mapper(zposmin,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
	        
	//x[0] = LeftMargin;
	//x[1] = LeftMargin-(int)(Orth_Axis_Front*costhetanew);
	//x[2] = getSize().width-RightMargin-(int)(Orth_Axis_Back*costhetanew);
	//x[3] = getSize().width-RightMargin;
	
        x[0] = myW2;
	x[1] = myW2-(int)(Orth_Axis_Front*costhetanew);
	
        x[2] = myW - (int)(Orth_Axis_Back*costhetanew);
	x[3] = myW;
	
        
	y[0] = myX;
	y[1] = myX-(int)(Orth_Axis_Back*sinthetanew);
	y[2] = y[1];
	y[3] = y[0];
        
        
        Graphics2D g2d = (Graphics2D)g;
        int rule; 
        float alpha;
        rule = AlphaComposite.SRC_OVER;
        alpha = 0.3f;
        
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
        
        
	//g.setColor(bgcolor.darker());
	//g.setXORMode(bgcolor);
	g.setColor(Color.lightGray);
	g.fillPolygon(x,y,4);
	//g.setPaintMode();
        
        
        x[0] = LeftMargin;
	x[1] = LeftMargin-(int)(Orth_Axis_Front*costhetanew);
        x[3] = myW2;
	x[2] = myW2-(int)(Orth_Axis_Front*costhetanew);
	
        g.setColor(new Color(255,200,200));
	g.fillPolygon(x,y,4);
	
        x[0] = LeftMargin;
	x[1] = LeftMargin;
        x[3] = myW2;
	x[2] = myW2;
        
        y[0] = myX;
	y[1] = myX + state.s105;
	y[2] = y[1];
	y[3] = y[0];
        	
        g.setColor(new Color(255,200,200));
	//g.fillPolygon(x,y,4);
        
        g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f));
        
    } 
    
    private void drawDarkBack2(Graphics g){
	int x[], y[], myX, myW;
        double zposmax;
        
        zposmax = Math.max(zpos[0],zpos[1]);
        
	x = new int[4];
	y = new int[4];
	myX = (int)MaestroA.mapper(0,(double)TopMargin,(double)VPos,xmax,xmin);
        myW = (int)MaestroA.mapper(zposmax,(double)(getSize().width-RightMargin),(double)LeftMargin,zmax,zmin);
	    
	x[0] = myW;
	x[1] = myW - (int)(Orth_Axis_Front*costhetanew);
	x[2] = getSize().width-RightMargin-(int)(Orth_Axis_Back*costhetanew);
	x[3] = getSize().width-RightMargin;
	
	y[0] = myX;
	y[1] = myX-(int)(Orth_Axis_Back*sinthetanew);
	y[2] = y[1];
	y[3] = y[0];
        
        
        Graphics2D g2d = (Graphics2D)g;
        
        int rule; 
        float alpha;
        rule = AlphaComposite.SRC_OVER;
        alpha = 0.30f;
        
        //g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setComposite(AlphaComposite.getInstance(rule, alpha));
        
	//g.setColor(bgcolor.darker());
	//g.setXORMode(bgcolor);
	g.setColor(new Color(255,200,200));
	g.fillPolygon(x,y,4);
        
        x[0] = myW;
	x[1] = myW;
        x[3] = getSize().width-RightMargin;
	x[2] = getSize().width-RightMargin;
        
        y[0] = myX;
	y[1] = myX+105;
	y[2] = y[1];
	y[3] = y[0];
        	
        g.setColor(new Color(255,200,200));
	//g.fillPolygon(x,y,4);
        
	//g.setPaintMode();
        g2d.setComposite(AlphaComposite.getInstance(rule, 1.0f));
        
    }
}
