//GraphCanvas.java
/* A Java class for
 * SingleStub.java
 * Electromagnetic Transmission Line Applet
 * Applet without Smith Chart - Prepared by Umberto Ravaioli 
 * for 6th edition of Fundamentals of Applied Electromagnetics Book
 * June 2009 - All Rights Reserved
 */   

import java.awt.*;

public class GraphCanvas extends Canvas{
    protected static final Color bgcolor = new Color(216,216,191);
    
    protected Image im;
    protected Graphics buf;
    protected int LeftMargin;
    protected int TopSep;
    protected int BottomSep;
    protected int RightMargin;
    protected int VPos=0;
    protected String XLabel, YLabel, ZLabel, TITLE, XLabel2;
    protected String X1, X2, X3, Xcenter;
    protected String Y1, Y2, Y3, Y4;
    protected int NumPoints, yband1, yband2, yband3, yband4, yband5, yband6, yband7, yband8, yband9, scan_index;
    protected double x[];
    protected double y[];
    protected double ymin, ymax;
    protected double xmin, xmax;
    protected int xx[];
    protected int yy[];
    protected double xRef, BW1, BW2;
    protected int BWpos1, BWpos2;
    protected boolean Should_Plot_Zero_Line, BigBand;
    protected boolean Should_Plot_Ref_Point;
    protected boolean MilsLabel;
    protected boolean IsYRangeMinSet, IsYRangeMaxSet;
    protected boolean IsXRangeMinSet, IsXRangeMaxSet;
    protected boolean IsWZero;

    protected Font font1;
    protected Font font2;
    protected Font font3;
    StateVars state;
    
    public GraphCanvas(StateVars state){
	super();
        this.state = state;
        
	setBackground(bgcolor);
        
        LeftMargin = state.s45;
        TopSep = state.s50;
        BottomSep = state.s40;
        RightMargin = state.s25;
        
        font1 = new Font("Sanserif",Font.PLAIN,state.font11);
        font2 = new Font("Serif",Font.PLAIN,state.font11);
        font3 = new Font("Serif",Font.PLAIN,state.font12);
        
	XLabel2="x-axis";
	YLabel="y-axis";
	TITLE ="Unknown Title";
	Y1 = " ";
	Y2 = " ";
	Y3 = " ";
	X1 = " ";
	X2 = " ";
	
	X3 = " ";
	NumPoints = 1001;
	x = new double[NumPoints];
	y = new double[NumPoints];
	xx = new int[NumPoints];
	yy = new int[NumPoints];
	for(int i=0;i<NumPoints;i++){
	    x[i]=i;
	    y[i]=0.0;
	}
	IsYRangeMinSet=false;
	IsYRangeMaxSet=false;
	IsXRangeMinSet=false;
	IsXRangeMaxSet=false;
	IsWZero = false;
	
	xRef = 0.0;
	
	Should_Plot_Zero_Line = false;
	Should_Plot_Ref_Point = false;
	MilsLabel = false;
	BigBand = false;
    }
     
public void paint(Graphics g){
    if(im == null){
	im = createImage(getSize().width,getSize().height);
	buf = im.getGraphics();
	drawGraph(buf);
    }
    drawGraph(buf);
    g.drawImage(im,0,0,null);
}

//Addition to reduce flicker new routine
public void update(Graphics g){		// added to avoid clearing
	paint(g);
}

public void drawGraph(Graphics g){
	
	g.clearRect(0,0,getSize().width,getSize().height);
    	drawAxis(g);
	if(Should_Plot_Zero_Line){plotZeroLine(g);}
	g.setColor(Color.white);
	
	drawTitle(g);
        plotPoints(g);
	plotRefPoint(g);
}

protected void ignition(){
    int height=getSize().height;
    int width=getSize().width;
    int yaxis = height - TopSep - BottomSep;
    
    if(!IsYRangeMinSet){ymin = MaestroA.getMin(y);}
    if(!IsYRangeMaxSet){ymax = MaestroA.getMax(y);}
    if(!IsXRangeMaxSet){xmax = x[x.length-1];}
    if(!IsXRangeMinSet){xmin = x[0];}
    if(IsYRangeMinSet || IsYRangeMaxSet){
	MaestroA.confiner(y,ymax,ymin);
    }
    if(IsXRangeMinSet || IsXRangeMaxSet){
	MaestroA.confiner(x,xmax,xmin);
    }
    
    if(ymin==ymax){ymax=2*ymin+1;}
    for(int i=0;i<xx.length;i++){
	xx[i]= (int)MaestroA.mapper(x[i],(double)(width-RightMargin),(double)(LeftMargin),xmax,xmin);
	yy[i]= (int)MaestroA.mapper(y[i],(double)TopSep,(double)(height-BottomSep),ymax,ymin);
    } 
    
    if(x[x.length-1] >= 1.0E12){
	X1=""+MaestroA.rounder(x[0]/1.0E12,3);
	X2=""+MaestroA.rounder(x[x.length-1]/1.0E12,3);
	Xcenter=""+MaestroA.rounder(x[NumPoints/2]/1.0E12,3);
	XLabel2="Frequency [ THz ]";
    }
    else if(x[x.length-1] < 1.0E12 && x[x.length-1] >= 1.0E9){
	X1=""+MaestroA.rounder(x[0]/1.0E9,3);
	X2=""+MaestroA.rounder(x[x.length-1]/1.0E9,3);
	Xcenter=""+MaestroA.rounder(x[NumPoints/2]/1.0E9,3);
	XLabel2="Frequency [ GHz ]";
    }
    else if(x[x.length-1] < 1.0E9 && x[x.length-1] >= 1.0E6){
	X1=""+MaestroA.rounder(x[0]/1.0E6,3);
	X2=""+MaestroA.rounder(x[x.length-1]/1.0E6,3);
	Xcenter=""+MaestroA.rounder(x[NumPoints/2]/1.0E6,3);
	XLabel2="Frequency [ MHz ]";
    }
    else if(x[x.length-1] < 1.0E6 && x[x.length-1] >= 1.0E3){
	X1=""+MaestroA.rounder(x[0]/1.0E3,3);
	X2=""+MaestroA.rounder(x[x.length-1]/1.0E3,3);
	Xcenter=""+MaestroA.rounder(x[NumPoints/2]/1.0E3,3);
	XLabel2="Frequency [ kHz ]";
    }
    else if(x[x.length-1] < 1.0E3 && x[x.length-1] >= 0.0){
	X1=""+MaestroA.rounder(x[0],3);
	X2=""+MaestroA.rounder(x[x.length-1],3);
	Xcenter=""+MaestroA.rounder(x[NumPoints/2],3);
	XLabel2="Frequency [ Hz ]";
    }
    
    X3="|";
    Y1=""+MaestroA.rounder(ymin,3);
    if(ymax < 1.0e230){
	Y2=""+MaestroA.rounder(ymax,3);
    }
    else{
	Y2="\u221e";
    }
    Y3="_";
    
    Y4 ="0.2";
    
    yband1 = TopSep + (yaxis *9)/10;
    yband2 = TopSep + (yaxis *4)/5;
    yband3 = TopSep + (yaxis *7)/10;
    yband4 = TopSep + (yaxis *3)/5;
    yband5 = TopSep + (yaxis *5)/10;
    yband6 = TopSep + (yaxis *2)/5;
    yband7 = TopSep + (yaxis *3)/10;
    yband8 = TopSep + (yaxis *1)/5;
    yband9 = TopSep + (yaxis *1)/10;
}

protected void plotZeroLine(Graphics g){
    if(ymin*ymax>0){return;}
    FontMetrics fm = g.getFontMetrics();
    g.setFont(font1);
    int yy;
    yy = (int)MaestroA.mapper(0.0,(double)TopSep,(double)(getSize().height-BottomSep),ymax,ymin);
    g.setColor(Color.red);
    g.drawLine(LeftMargin,yy,getSize().width-RightMargin,yy);
    g.drawString("0",LeftMargin-fm.stringWidth("0"),yy+fm.getHeight()/3);
}

public synchronized void plotZeroLine(boolean Should_Plot_Zero_Line){
    this.Should_Plot_Zero_Line = Should_Plot_Zero_Line;
}

protected void plotRefPoint(Graphics g){
    int myX=0, myY=0, i, BWX1=0, BWX2=0;
    i = (int)(NumPoints*(xRef-x[0])/(x[x.length-1]-x[0]));
    if(i<0) {i = 0;}
    if(i>=NumPoints){i=NumPoints-1;}
    myX = (int)MaestroA.mapper(xRef,(double)(getSize().width-RightMargin),(double)(LeftMargin),xmax,xmin);
    if(y[i]>0.0){
	myY = (int)MaestroA.mapper(y[i],(double)TopSep,(double)(getSize().height-BottomSep),ymax,ymin);
    }
    else{
	myY =getSize().height-BottomSep ;
    }
    
    //Dots for bandwidth

    BWX1 = (int)MaestroA.mapper(BW1,(double)(getSize().width-RightMargin),(double)(LeftMargin),xmax,xmin);
    BWX2 = (int)MaestroA.mapper(BW2,(double)(getSize().width-RightMargin),(double)(LeftMargin),xmax,xmin);
    
    Graphics2D g2d = (Graphics2D)g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    
    g.setColor(Color.white);
    MaestroG.fillCircle(BWX1,yband2,state.s6,g);
    MaestroG.fillCircle(BWX2,yband2,state.s6,g);
    g.setColor(Color.black);
    MaestroG.drawCircle(BWX1,yband2,state.s6,g);
    MaestroG.drawCircle(BWX2,yband2,state.s6,g);
    
    g.setColor(Color.white);
    MaestroG.subscripter("F","1","",g,state.font12,BWX1-state.s15,yband2+state.s15);
    MaestroG.subscripter("F","2","",g,state.font12,BWX2+state.s7,yband2+state.s15);
    
    //cursor reference point
    g.setColor(Color.white);
    g.drawLine(myX,myY,myX,getSize().height-BottomSep+state.s5);
    
    g.setColor(Color.green);
    MaestroG.fillCircle(myX,myY,state.s6,g);
    g.setColor(Color.black);
    MaestroG.drawCircle(myX,myY,state.s6,g);
    
   g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
}

public synchronized void plotRefPoint(boolean Should_Plot_Ref_Point){
    this.Should_Plot_Ref_Point = Should_Plot_Ref_Point;
}

protected void plotPoints(Graphics g){
    ignition();
    g.setColor(Color.yellow);
    g.drawPolyline(xx,yy,xx.length);
}

protected void drawTitle(Graphics g){
    FontMetrics fm = g.getFontMetrics();
    
        String Bigomega, omega, alpha, lambda, Ohm, infinity, Gamma, epsilon;
        
	Bigomega = "\u03a9";
	omega = "\u03c9";
	alpha="\u03b1";
	lambda="\u03bb";
	Ohm="\u03a9";
	infinity="\u221e";
	Gamma="\u0393";
        epsilon="\u03b5";
        
    g.setFont(font1);
    fm = g.getFontMetrics();
    g.setColor(Color.white);
    g.drawString(Xcenter,LeftMargin+(getSize().width-LeftMargin-RightMargin-fm.stringWidth(Xcenter))/2,
			 getSize().height-BottomSep+3*fm.getHeight()/2);
    
    g.drawString(XLabel2,(getSize().width)/2+state.s40,getSize().height-2*fm.getHeight()/3);
    
    g.setColor(Color.white);
    int xtitle = RightMargin+state.s10;
    
    g.drawString(TITLE,xtitle-state.s20,(13*TopSep)/30);
    //------------------------------------------------------------------------------
    String tempf1="", tempf2="", tempf3="", tempf4="";
    double BW3;
    
    BW3 = BW2 - BW1;
    
    if(BW1 >= 1.0E12){
	tempf1=" = "+MaestroA.rounder((BW1/1.0E12),3)+" [THz]";
    }
    else if(BW1 < 1.0E12 && BW1 >= 1.0E9){
	tempf1=" = "+MaestroA.rounder((BW1/1.0E9),3)+" GHz";
    }
    else if(BW1 < 1.0E9 && BW1 >= 1.0E6){
	tempf1=" = "+MaestroA.rounder((BW1/1.0E6),3)+" MHz";
    }
    else if(BW1 < 1.0E6 && BW1 >= 1.0E3){
	tempf1=" = "+MaestroA.rounder((BW1/1.0E3),3)+" kHz";
    }
    else if(BW1 < 1.0E3 && BW1 >= 0.0){
	tempf1=" = "+MaestroA.rounder(BW1,3)+" Hz";
    }
    
    if(BW2 >= 1.0E12){
	tempf2=" = "+MaestroA.rounder((BW2/1.0E12),3)+" [THz]";
    }
    else if(BW2 < 1.0E12 && BW2 >= 1.0E9){
	tempf2=" = "+MaestroA.rounder((BW2/1.0E9),3)+" GHz";
    }
    else if(BW2 < 1.0E9 && BW2 >= 1.0E6){
	tempf2=" = "+MaestroA.rounder((BW2/1.0E6),3)+" MHz";
    }
    else if(BW2 < 1.0E6 && BW2 >= 1.0E3){
	tempf2=" = "+MaestroA.rounder((BW2/1.0E3),3)+" kHz";
    }
    else if(BW2 < 1.0E3 && BW2 >= 0.0){
	tempf2=" = "+MaestroA.rounder(BW1,3)+" Hz";
    }
    if(!BigBand){
	if(BW3 >= 1.0E12){
	    tempf3=" = "+MaestroA.rounder((BW3/1.0E12),3)+" [THz]";
	}
	else if(BW3 < 1.0E12 && BW3 >= 1.0E9){
	    tempf3=" = "+MaestroA.rounder((BW3/1.0E9),3)+" GHz";
	}
	else if(BW3 < 1.0E9 && BW3 >= 1.0E6){
	    tempf3=" = "+MaestroA.rounder((BW3/1.0E6),3)+" MHz";
	}
	else if(BW3 < 1.0E6 && BW3 >= 1.0E3){
	    tempf3=" = "+MaestroA.rounder((BW3/1.0E3),3)+" kHz";
	}
	else if(BW3 < 1.0E3 && BW3 >= 0.0){
	    tempf3=" = "+MaestroA.rounder(BW3,3)+" Hz";
	}
    }
    else{
	if(BW3 >= 1.0E12){
	    tempf3=" > "+MaestroA.rounder((BW3/1.0E12),3)+" [THz]";
	}
	else if(BW3 < 1.0E12 && BW3 >= 1.0E9){
	    tempf3=" > "+MaestroA.rounder((BW3/1.0E9),3)+" GHz";
	}
	else if(BW3 < 1.0E9 && BW3 >= 1.0E6){
	    tempf3=" > "+MaestroA.rounder((BW3/1.0E6),3)+" MHz";
	}
	else if(BW3 < 1.0E6 && BW3 >= 1.0E3){
	    tempf3=" > "+MaestroA.rounder((BW3/1.0E3),3)+" kHz";
	}
	else if(BW3 < 1.0E3 && BW3 >= 0.0){
	    tempf3=" > "+MaestroA.rounder(BW3,3)+" Hz";
	}
    }
    
    if(xRef >= 1.0E12){
	tempf4=" = "+MaestroA.rounder((xRef/1.0E12),3)+" [THz]";
    }
    else if(xRef < 1.0E12 && xRef >= 1.0E9){
	tempf4=" = "+MaestroA.rounder((xRef/1.0E9),3)+" GHz";
    }
    else if(xRef < 1.0E9 && xRef >= 1.0E6){
	tempf4=" = "+MaestroA.rounder((xRef/1.0E6),3)+" MHz";
    }
    else if(xRef < 1.0E6 && xRef >= 1.0E3){
	tempf4=" = "+MaestroA.rounder((xRef/1.0E3),3)+" kHz";
    }
    else if(xRef < 1.0E3 && xRef >= 0.0){
	tempf4=" = "+MaestroA.rounder(xRef,3)+" Hz";
    }

    int xx1 = xtitle + fm.stringWidth(TITLE)+state.s5;
    int yy1 = (9*TopSep)/30;
    int yy2 = (18*TopSep)/30;
    int yy3 = (27*TopSep)/30;
    int yy4 = (54*TopSep)/30;
    
    Graphics2D g2d = (Graphics2D)g;
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
    
    g.setColor(Color.green);
    MaestroG.fillCircle(xx1-state.s8,yy3-state.s5,state.s6,g);
    g.setColor(Color.black);
    MaestroG.drawCircle(xx1-state.s8,yy3-state.s5,state.s6,g);
    
    g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
    
    g.setColor(Color.white);
    g.drawLine(xx1-state.s10,state.s5,xx1-state.s10,state.s30);
    g.drawLine(xx1-state.s10,state.s5,xx1-state.s5,state.s5);
    g.drawLine(xx1-state.s10,state.s30,xx1-state.s5,state.s30);
    
    MaestroG.subscripter("F","1",""+tempf1,g,state.font11,xx1,yy1);
    MaestroG.subscripter("F","2",""+tempf2,g,state.font11,xx1+fm.stringWidth("F1"+tempf1)+state.s15,yy1);
    MaestroG.subscripter("F","",""+tempf4,g,state.font11,xx1,yy3);
    MaestroG.subscripterSS3("| "+Gamma,"","( F ) | = "+MaestroA.rounder(y[scan_index],4),g,state.font11,xx1+state.s5+fm.stringWidth("F = 100.100 GHZ"),yy3);
    
    g.setColor(Color.yellow);
    MaestroG.subscripter("( @ VSWR",""," < 1. 5 )",g,state.font11,xx1+fm.stringWidth("   B W"+tempf3),yy2);
    MaestroG.subscripter("B W","",""+tempf3,g,state.font11,xx1,yy2);
    
    g.setColor(Color.yellow);
    g.drawString(X1,LeftMargin-fm.stringWidth(X1)/2,getSize().height-BottomSep+3*fm.getHeight()/2);
    g.drawString(X2,getSize().width-RightMargin-fm.stringWidth(X2)/2,getSize().height-BottomSep+3*fm.getHeight()/2);
    
    g.setColor(Color.white);
    g.drawLine(LeftMargin+(getSize().width-RightMargin-LeftMargin)/2,getSize().height-BottomSep,
               LeftMargin+(getSize().width-RightMargin-LeftMargin)/2,getSize().height-BottomSep+state.s5);
    g.setColor(Color.yellow);
    g.drawString(Y1,Math.max(state.s4,LeftMargin-fm.stringWidth(Y1))-state.s7,getSize().height-BottomSep+state.s5);
    
    g.drawString(Y2,Math.max(state.s4,LeftMargin-fm.stringWidth(Y2))-state.s7,TopSep+state.s4);
    
    g.setColor(Color.white);
    g.drawString(Y4,LeftMargin-fm.stringWidth(Y4) - state.s7,yband2 + state.s4);
    g.setFont(font3);
    g.drawString("| "+Gamma+" |",LeftMargin/2 - state.s10,(4*TopSep)/2);
    g.setColor(Color.black);
}

protected void drawAxis(Graphics g){
    VPos = getSize().height-BottomSep;
    g.setColor(Color.white);
    //Vertical Axis
    g.drawLine(LeftMargin,TopSep,LeftMargin,getSize().height-BottomSep+state.s5);
    g.drawLine(getSize().width-RightMargin,TopSep,getSize().width-RightMargin,getSize().height-BottomSep+state.s5);
    
    //Horizontal Axis
    g.drawLine(LeftMargin-state.s5,TopSep,getSize().width-RightMargin,TopSep);
    g.drawLine(LeftMargin-state.s5,VPos,getSize().width-RightMargin,VPos);
    
    //tick marks for Gamma and bandwidth level
    g.drawLine(LeftMargin-state.s10,yband5,LeftMargin,yband5);
    g.setColor(Color.lightGray);
    g.drawLine(LeftMargin-state.s5,yband1,LeftMargin,yband1);
    g.drawLine(LeftMargin-state.s5,yband2,getSize().width-RightMargin,yband2);
    g.drawLine(LeftMargin-state.s5,yband3,LeftMargin,yband3);
    g.drawLine(LeftMargin-state.s5,yband4,LeftMargin,yband4);
    
    g.drawLine(LeftMargin-state.s5,yband6,LeftMargin,yband6);
    g.drawLine(LeftMargin-state.s5,yband7,LeftMargin,yband7);
    g.drawLine(LeftMargin-state.s5,yband8,LeftMargin,yband8);
    g.drawLine(LeftMargin-state.s5,yband9,LeftMargin,yband9);
    
}

public final synchronized void setXLabel(String XLabel){
    this.XLabel=XLabel;
}

public final synchronized void setYLabel(String YLabel){
    this.YLabel=YLabel;
} 

public final synchronized void setTitle(String TITLE){
    this.TITLE = TITLE;
}

public void setWZero(boolean IsWZero){
    this.IsWZero = IsWZero;
}

public final synchronized void setLabels(String TITLE, String XLabel, String YLabel, String ZLabel){
    this.TITLE=TITLE;
    this.YLabel = YLabel;
    this.XLabel = XLabel;
    this.ZLabel = ZLabel;
}
 
public void plot(double[] xdata, double[] ydata){
    if(NumPoints != xdata.length){
	NumPoints = xdata.length;
	x = new double[NumPoints];
	y = new double[NumPoints];
	xx = new int[NumPoints];
	yy = new int[NumPoints];
    }
    for(int i = 0; i < NumPoints; i++){
	x[i] = xdata[i];
	y[i] = ydata[i];
    }
    repaint();
}

public void setBand(double BW1, double BW2, int BWpos1, int BWpos2, boolean BigBand){
    this.BW1 = BW1;
    this.BW2 = BW2;
    this.BWpos1 = BWpos1;
    this.BWpos2 = BWpos2;
    this.BigBand = BigBand;
}

public void setYRange(double ymax, double ymin){
    IsYRangeMaxSet=true;
    IsYRangeMinSet=true;
    this.ymax=ymax;
    this.ymin=ymin;
}

public void setYRangeMin(double ymin){
    IsYRangeMinSet=true;
    this.ymin=ymin;
}

public void setYRangeMax(double ymax){
    IsYRangeMaxSet=true;
    this.ymax=ymax;
}

public void setLabelAxis(boolean MilsLabel){
    this.MilsLabel = MilsLabel;
}

public void setAuto(){
    IsYRangeMaxSet=false;
    IsYRangeMinSet=false;
    IsXRangeMaxSet=false;
    IsXRangeMinSet=false;
}

public synchronized void setRefPoint(double xRef, int scan_index){
    this.xRef = xRef;
    this.scan_index = scan_index;
}


}
