import java.awt.*;
 
public class RectWaveGuideSpectrumCanvas extends Canvas {
	private static final Color bgcolor = Color.black;
	private static final Color acolor = new Color(152,152,152);
	private static final Color ccolor = new Color(236,236,236);
	private Image im;
	private Graphics buf;
	private boolean IsTEmode = true;
	private static final int MaxModes = 11; //Maximum number of modes plotted
	private int LeftMargin, RightMargin, TopMargin, BottomMargin, Offset;
	RectWaveGuide_State state;
	double fMax, fMin; //maximum and miminum frequency range
	//private static final int F_AXIS, S_AXIS; //y coordinates of Frequency and Spectrum axis
	//private static final int F_TE_A, F_TE_B, F_TE_C, F_TE_D, F_TE_E, F_TE_F; //y coordinates of Frequency tiers for TE(m,0), TE(0,n), and TE(m,n)
	//private static final int F_TE_G, F_TE_H;
	private int F_AXIS, S_AXIS; //y coordinates of Frequency and Spectrum axis
	private int F_TE_A, F_TE_B, F_TE_C, F_TE_D, F_TE_E, F_TE_F; //y coordinates of Frequency tiers for TE(m,0), TE(0,n), and TE(m,n)
	private int F_TE_G, F_TE_H;
	
	public RectWaveGuideSpectrumCanvas(RectWaveGuide_State state){
            super();
            setBackground(bgcolor);
            this.state = state;
            //fMax=12.0E9;
            fMax = 18.0E9;
            fMin = 0.0E9;
            
            LeftMargin = state.s10; 
            RightMargin = state.s10; 
            TopMargin = state.s10; 
            BottomMargin = state.s10; 
            Offset = state.s100;
	
            //y coordinates of Frequency and Spectrum axis
            F_AXIS = state.s150; S_AXIS = state.s80;
            //y coordinates of Frequency tiers for TE(m,0), TE(0,n), and TE(m,n)
            F_TE_A = state.s137; F_TE_B = state.s120; F_TE_C = state.s103; F_TE_D = state.s86; F_TE_E = state.s69; F_TE_F = state.s52;
            F_TE_G = state.s35; F_TE_H = state.s18;
	}
	
	public void paint(Graphics g){
	    if(im == null){
		im = createImage(getSize().width,getSize().height);
		buf = im.getGraphics();
		drawCanvas(buf);
	    }
	    else{
		drawCanvas(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 clear(){
		this.getGraphics().clearRect(0,0,getSize().width,getSize().height);
	        repaint();
	}
	
	private void drawCanvas(Graphics g){	
	    //Draw the black rectangle
	    g.setColor(Color.black);
	    g.fillRect(0,0,getSize().width,getSize().height);
    
	    //g.setColor(bgcolor.darker());
	    g.setColor(bgcolor);
	    g.fillRect(0,getSize().height-2,getSize().width,2);
	    g.fillRect(getSize().width-2,0,2,getSize().height);
	    g.setColor(Color.white);
	    g.drawRect(4,4,getSize().width-8,getSize().height-8);
	   
	    
	    drawFrequency(g);
	    drawSpectrum(g);
	}	
	
	private void drawFrequency(Graphics g){
	    int mPos_frequency;
	    mPos_frequency = LeftMargin + (int) (
			    (getSize().width-LeftMargin-RightMargin)* 
			    (state.frequency)/(fMax-fMin) 
	    );	
	    //Draw operational frequency
	    g.setColor(Color.yellow);
	    g.drawLine(mPos_frequency,getSize().height-state.s10,mPos_frequency,state.s5);
	    
            //Draw the arrow for operational frequency
	    //MaestroG.drawArrow(mPos_frequency,getSize().height-state.s15,5,g);
            drawArrowScaled( mPos_frequency,getSize().height-state.s15, 1,state.sfactor, g);
	}
	
	private void drawSpectrum(Graphics g){
	    int mPos, i, j, spacer, spacer1, spacer2;
	    double my_f;
	    //draw axis
	    drawAxis(g);
	    //draw  modes
	   
	    i=0; 
	    j=0;
            spacer = state.s30; spacer1 = state.s30; spacer2 = state.s36;
	    my_f = getModeFrequency(i,j);
            
	    while(my_f < fMax){
		while(my_f < fMax){
		    mPos = LeftMargin + (int) (
			    (getSize().width-LeftMargin-RightMargin)* 
			    (my_f)/(fMax-fMin) 
		    );
		    
                    g.setColor(Color.white);
                    spacer = state.s30; spacer1 = state.s30; spacer2 = state.s36;
		    if(i!=0 && j==0){//Top Tier has TE(n,0) modes
			g.drawLine(mPos,F_TE_A+state.s5,mPos,F_TE_A-state.s10);
                        if(i>9){spacer = spacer2;} else{spacer = spacer1;}
			MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_A);
		    }
		    else if(j!=0 && i==0){//Second Tier has TE(0,n) modes
			g.drawLine(mPos,F_TE_B+state.s5,mPos,F_TE_B-state.s10);
                        if(j>9){spacer = spacer2;} else{spacer = spacer1;}
			MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_B);
		    }
		    
		  if(IsTEmode){
                       g.setColor(Color.cyan);
                       if(i>=1 && j==1){//Third tier has TE(m,1) modes
                            g.drawLine(mPos,F_TE_C+state.s5,mPos,F_TE_C-state.s10);
                            if(i>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_C);
                       }

                        else if(i==1 && j>=2){//Fourth tier has TE(1,n) modes (no TE(1,0));
                            g.drawLine(mPos,F_TE_D+state.s5,mPos,F_TE_D-state.s10);
                            if(j>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_D);
                       }

                       else if(i>=2 && j==2){//Fifth tier has TE(m,2) modes
                            g.drawLine(mPos,F_TE_E+state.s5,mPos,F_TE_E-state.s10);
                            if(i>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_E);
                       } 
                       else if(i==2 && j>=3 ){//Sixth tier has TE(2,n) modes
                            g.drawLine(mPos,F_TE_F+state.s5,mPos,F_TE_F-state.s10);
                            if(j>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_F);
                       }

                       else if(i>=3 && j==3){//Seventh tier has TE(m,2) modes
                            g.drawLine(mPos,F_TE_G+state.s5,mPos,F_TE_G-state.s10);
                            if(i>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_G);
                       } 
                       else if(i==3 && j>=4 ){//Eighth tier has TE(2,n) modes
                            g.drawLine(mPos,F_TE_H+state.s5,mPos,F_TE_H-state.s10);
                            if(j>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TE",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_H);
                       }
		   
                      // else if(i+j>=5 && j!=0 && i!=0){//Rest of modes
                            //g.drawLine(mPos,F_TE_H+5,mPos,F_TE_H-10);
                            //MaestroG.subscripter("TE",""+i+","+j,"",g,11,mPos-30,F_TE_H);
                       //} 
	          }
	          else{
                       spacer = state.s33; spacer1 = state.s33; spacer2 = state.s39;
                       g.setColor(Color.green); 
                       if(i>=1 && j==1){//Third tier has TE(m,1) modes
                            g.drawLine(mPos,F_TE_C+state.s5,mPos,F_TE_C-state.s10);
                            if(i>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_C);
                       }

                        else if(i==1 && j>=2){//Fourth tier has TE(1,n) modes (no TE(1,0));
                            g.drawLine(mPos,F_TE_D+state.s5,mPos,F_TE_D-state.s10);
                            if(j>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_D);
                       }

                       else if(i>=2 && j==2){//Fifth tier has TE(m,2) modes
                            g.drawLine(mPos,F_TE_E+state.s5,mPos,F_TE_E-state.s10);
                            if(i>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_E);
                       } 
                       else if(i==2 && j>=3 ){//Sixth tier has TE(2,n) modes
                            g.drawLine(mPos,F_TE_F+state.s5,mPos,F_TE_F-state.s10);
                            if(j>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_F);
                       }

                       else if(i>=3 && j==3){//Seventh tier has TE(m,2) modes
                            g.drawLine(mPos,F_TE_G+state.s5,mPos,F_TE_G-state.s10);
                            if(i>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_G);
                       } 
                       else if(i==3 && j>=4 ){//Eighth tier has TE(2,n) modes
                            g.drawLine(mPos,F_TE_H+state.s5,mPos,F_TE_H-state.s10);
                            if(j>9){spacer = spacer2;} else{spacer = spacer1;}
                            MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-spacer,F_TE_H);
                       }

                       //else if(i+j>=5 && j!=0 && i!=0){//Rest of modes
                            //g.drawLine(mPos,F_TE_H+state.s5,mPos,F_TE_H-state.s10);
                            //MaestroG.subscripter("TM",""+i+","+j,"",g,state.font11,mPos-state.s30,F_TE_H);
                       //} 
                    }   
		    j++;
		    my_f = getModeFrequency(i,j);
		}
		i++;
		j=0;
		my_f = getModeFrequency(i,j);
	    }
	    int mPos_frequency;
	    mPos_frequency = LeftMargin + (int) (
			    (getSize().width-LeftMargin-RightMargin)* 
			    (state.frequency)/(fMax-fMin) 
	    );	
	    g.setColor(Color.yellow);
	    int x = mPos_frequency+state.s10;
	    int y = getSize().height-state.s10;
	    double f_normalized;
            
	//MaestroG.subscripter("Higher order modes are listed in the Mode Properties panel ( use Mode Selector to scan modes )","","",g,10,20, getSize().height-10);
	MaestroG.subscripter("Mode Spectrum","","",g,state.font14,state.s20,state.s25);
        Font normalfont = new Font("SanSerif",Font.PLAIN,state.font12);
        g.setFont(normalfont);
        
	if(state.frequency < 1.0E3){
		    f_normalized = state.frequency;
		    g.drawString(""+MaestroA.rounder(f_normalized,3)+" Hz",x,y);	
		}
		else if(state.frequency < 1.0E6 && state.frequency >= 1.0E3  ){
		    f_normalized = state.frequency/1.0E3;
		    g.drawString(""+MaestroA.rounder(f_normalized,3)+" kHz",x,y);	
		}
		else if(state.frequency < 1.0E9 && state.frequency >= 1.0E6 ){
		    f_normalized = state.frequency/1.0E6;
		    g.drawString(""+MaestroA.rounder(f_normalized,3)+" MHz",x,y);	
		}
		else if(state.frequency < 1.0E12 && state.frequency >= 1.0E9 ){
		    f_normalized = state.frequency/1.0E9;
		    g.drawString(""+MaestroA.rounder(f_normalized,3)+" GHz",x,y);	
		}
		else if(state.frequency < 1.0E15 && state.frequency >=1.0E12 ){
		    f_normalized = state.frequency/1.0E12;
		    g.drawString(""+MaestroA.rounder(f_normalized,3)+" THz",x,y);	
		}
		else{
		    f_normalized = state.frequency/1.0E12;
		    g.drawString(""+MaestroA.rounder(f_normalized,3)+" THz",x,y);
		}
	
	}	
	
	public void drawAxis(Graphics g){
	    g.setColor(Color.white);
	    g.drawLine(state.s7,F_AXIS,getSize().width-state.s15,F_AXIS);
	    //MaestroG.drawArrow(getSize().width-state.s15,F_AXIS,7,g);
            drawArrowScaled( getSize().width-state.s15,F_AXIS, 3,state.sfactor, g);
            
            Graphics2D g2d = (Graphics2D)g;
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            
            // Print twice or smoothing makes it too faint on Mac - Mac sucks!!!
	    MaestroG.subscripterSer6("","f","","",g,state.font12,getSize().width-state.s24,F_AXIS+state.s16);
	    MaestroG.subscripterSer6("","f","","",g,state.font12,getSize().width-state.s24,F_AXIS+state.s16);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
	    
            MaestroG.subscripter("0","","",g,state.font12,state.s7,F_AXIS+state.s18);
	    g.drawLine(LeftMargin,F_AXIS-state.s5,LeftMargin,F_AXIS+state.s5);
	}
        
        public void drawArrowScaled(int x, int y, int tipo, double sfactor, Graphics g){
	Graphics2D g2d = (Graphics2D)g;
        double s;
        s = sfactor;
        
        switch (tipo){
	   
          case 1://ArrowUpSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                g.drawLine(x,y-1,x,y+(int)(s*5));
		//draw oblique arrow head
		Polygon pH = new Polygon();
		pH.addPoint(x-(int)(s*2), y-(int)(s*2));
		pH.addPoint(x+(int)(s*2), y-(int)(s*2));
		pH.addPoint(x,y-(int)(s*8));
		g.drawPolygon(pH);
		g.fillPolygon(pH);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        
          break;
          
          case 2://ArrowDownSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                g.drawLine(x,y+1,x,y-(int)(s*5));
		//draw oblique arrow head
		Polygon pJ = new Polygon();
		pJ.addPoint(x-(int)(s*2), y+(int)(s*2));
		pJ.addPoint(x+(int)(s*2), y+(int)(s*2));
		pJ.addPoint(x,y+(int)(s*8));
		g.drawPolygon(pJ);
		g.fillPolygon(pJ);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
	   break;
           
           case 3://ArrowRightSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                g.drawLine(x+1,y,x-(int)(s*5),y);
		//draw oblique arrow head
		Polygon pK = new Polygon();
		pK.addPoint(x+(int)(s*2), y-(int)(s*2));
		pK.addPoint(x+(int)(s*2), y+(int)(s*2));
		pK.addPoint(x+(int)(s*8),y);
		g.drawPolygon(pK);
		g.fillPolygon(pK);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
	   
	   break;
           
           case 4://ArrowLeftSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                g.drawLine(x-1,y,x+(int)(s*5),y);
		//draw oblique arrow head
		Polygon pL = new Polygon();
		pL.addPoint(x-(int)(s*2), y-(int)(s*2));
		pL.addPoint(x-(int)(s*2), y+(int)(s*2));
		pL.addPoint(x-(int)(s*8),y);
		g.drawPolygon(pL);
		g.fillPolygon(pL);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
 
	   break;
           
           case 5://ArrowOblique 45 degrees pointing NE
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
		//draw oblique arrow head
		Polygon pM = new Polygon();
                
                pM.addPoint(x+(int)(s*6),y-(int)(s*6)); // longer arrow
		pM.addPoint(x+(int)(s*1),y-(int)(s*3));
		pM.addPoint(x+(int)(s*2),y+(int)(s*1));
		
                g.drawPolygon(pM);
		g.fillPolygon(pM);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
                 
           break;
           
           case 6://ArrowOblique 45 degrees pointing SW
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
		//draw oblique arrow head
		Polygon pN = new Polygon();
                
                pN.addPoint(x-(int)(s*6),y+(int)(s*6)); 
		pN.addPoint(x-(int)(s*1),y+(int)(s*3));
		pN.addPoint(x-(int)(s*2),y-(int)(s*2));
		
                g.drawPolygon(pN);
		g.fillPolygon(pN);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
                 
           break;
           
           case 7://Larger ArrowRightSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                Polygon pR = new Polygon();
		pR.addPoint(x, y-(int)(s*3));
		pR.addPoint(x, y+(int)(s*3));
		pR.addPoint(x+(int)(s*7),y);
		g.drawPolygon(pR);
		g.fillPolygon(pR);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
	   
	   break;
           
           case 8://Larger ArrowLeftSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                Polygon pS = new Polygon();
		pS.addPoint(x, y-(int)(s*3));
		pS.addPoint(x, y+(int)(s*3));
		pS.addPoint(x-(int)(s*7),y);
		g.drawPolygon(pS);
		g.fillPolygon(pS);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
 
	   break;
           
           case 9://ArrowUpSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                Polygon pU = new Polygon();
		pU.addPoint(x-(int)(s*3), y);
		pU.addPoint(x+(int)(s*3), y);
		pU.addPoint(x,y-(int)(s*7));
		g.drawPolygon(pU);
		g.fillPolygon(pU);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
        
          break;
          
          case 10://ArrowDownSmooth
               g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        
                Polygon pD = new Polygon();
                pD.addPoint(x-(int)(s*3), y);
		pD.addPoint(x+(int)(s*3), y);
		pD.addPoint(x,y+(int)(s*7));
		g.drawPolygon(pD);
		g.fillPolygon(pD);
                
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_OFF);
	   break;
	}		
    }

	
	/*public void update(Graphics g){
		g.clearRect(0,0,getSize().width,getSize().height);
		drawCanvas(g);
	}*/
	
	public synchronized void setFmax(double frequency){
	    this.fMax = frequency+0.2*frequency;
	}
	
	public synchronized void setTE(boolean IsTEmode ){
	    this.IsTEmode = IsTEmode;
	}
	
	private double getModeFrequency(int i, int j){
	    double myf;
	    double a, b;
	    a = state.a;
	    b = state.a / state.a_to_b_ratio;
	    myf = (1.0/Math.sqrt(state.epsilon0*state.epsilon_r*state.mu0*state.mu_r))*
		  Math.sqrt(
		    Math.pow((i*Math.PI/a),2.0)+Math.pow((j*Math.PI/b),2.0)
		  )/(2.0*Math.PI);
	    return myf;
	}
	
	
}	

