//drawing routines
//Yves Moreau, may 98
import java.util.*;
import java.awt.*;
import java.applet.Applet;
import java.awt.image.ColorModel;
import java.awt.image.MemoryImageSource;

class drawing extends Canvas{
    modAppl appl; float min; float max;
    shape selected = null;
    //private Thread movie;
   Color basicColor[]={Color.white,Color.gray,Color.magenta,Color.blue,Color.green,Color.yellow,Color.orange,Color.red,new Color(100,50,0),Color.black};
   //Color basicColor[]= {Color.gray,Color.green,Color.yellow,Color.blue,Color.orange,Color.red};
   int nbColors=basicColor.length-1;
    private Image BufImg=null;  // mémoire tampon pour le tracé
    public Graphics gr=null;  // avec le contexte graphique associé
    public double scaleX =20.; public double scaleY=25.;
    public int centerX=0; public int centerY=0;// valeurs lues centrées
	  public int halfX =400; public int halfY=250;
    public double index=1.51; public double lambda = 1.3;
    public drawing(modAppl ap) { this.appl = ap;}
    public void fromProp(int i) { int k;
    	  double oldScaleX=scaleX; double oldScaleY=scaleY;
        this.scaleX= Double.valueOf( ((TextField)appl.xField.elementAt(3)).getText()).doubleValue();
        this.scaleY= Double.valueOf( ((TextField)appl.yField.elementAt(3)).getText()).doubleValue();
        shape sh=appl.last_(); while (sh instanceof shape) { sh.rescale(this.scaleX/oldScaleX,this.scaleY/oldScaleY);
                                                                                            sh = sh.prev_();} 
        halfX= (int) (scaleX*Double.valueOf( ((TextField)appl.xField.elementAt(0)).getText()).doubleValue());
        halfY= (int) (scaleY*Double.valueOf( ((TextField)appl.yField.elementAt(0)).getText()).doubleValue());
        this.index = Double.valueOf(appl.indexField.getText()).doubleValue();
        String str = appl.wl_nbField.getText();// is there a special code ?
    	  if ((k=str.indexOf('d'))>=0) 
    				{appl.debugCode = Integer.parseInt(str.substring(k+1),16);
    	  	   appl.displayMsg("\nDebugCode ="+appl.debugCode);
    	  		 }
    	  else if ((k=str.indexOf('u'))>=0) // upper limit for index
    				{try {appl.nmax = Double.valueOf(str.substring(k+1)).doubleValue();}catch (Exception ex) { appl.nmax=0;}
    	  	   appl.displayMsg("\nupper limit for effective indexes ="+appl.nmax);
    	  		 }
    	  else if ((k=str.indexOf('l'))>=0) // lower limit for index 
    				{try {appl.nmin = Double.valueOf(str.substring(k+1)).doubleValue();}catch (Exception ex) { appl.nmax=0;}
    	  	   appl.displayMsg("\nlower limit for effective indexes ="+appl.nmin);
    	  		 }
    	  else if ((k=str.indexOf('m'))>=0)// menu sinus ou mode simule
	           { Object obj = (str.charAt(k+1)=='s')?appl.sinesC:appl.modeC;
	           	 Event evt = new Event(obj,Event.ACTION_EVENT,(Object)str.substring(k+1));
	           	 appl.postEvent(evt);
	           }
    		else k = str.length();
    	  this.lambda = Double.valueOf(str.substring(0,k)).doubleValue();
        refresh(true);
    }
	public Rectangle coreBounds(boolean display)
	{ Rectangle box=null;
		shape sh = appl.last_();
		while (shape.valid(sh)) {
				if (sh.index>this.index) 
						{ if (box==null) box = sh.rect(); else box.add(sh.rect());}
				sh = sh.prev_();}
	 if (display) appl.displayMsg("\nguide: center (pixels):"+(box.x+box.width/2)+", "+(box.y+box.height/2)+"**size "+box.width/2+", "+box.height/2);
		return(box);
	}

  public Dimension getPreferredSize() {
		return new Dimension(300, 300);
    }
   public Graphics gr_() { return(gr);}
   public void paint(Graphics g) {
        if (BufImg instanceof Image) g.drawImage(BufImg,0,0,this);
      }
  public void update(Graphics g) {
        paint(g);
      }
  public void start() { setBackground(Color.lightGray);
        Rectangle r=this.getBounds();
        //System.out.print("\nstart :"+r.toString());
        shape sh= appl.last_(); while (sh instanceof shape)
  					{ sh._dr(this);sh.offset(-centerX,-centerY);sh = sh.prev_();}
  	    this.centerX = r.width/2;  this.centerY = r.height/2;
        BufImg = createImage(r.width,r.height);
        gr=BufImg.getGraphics();
        gr.drawRect(0,0,r.width-1,r.height-1);
        sh= appl.last_(); while (sh instanceof shape) { sh._dr(this);sh.offset(centerX,centerY);sh = sh.prev_();}
        //refresh(true);
        }
  public void refresh(boolean fill) { start();
  																		if (!(gr instanceof Graphics)) return;
  																		gr.setPaintMode();gr.setColor(getBackground());
                                      gr.fillRect(0,0,this.getSize().width,this.getSize().height);
                                      gr.setColor(Color.black);
                                      gr.drawRect(0,0,this.getSize().width-1,this.getSize().height-1);
                                      gr.drawLine(0,centerY,this.getBounds().width,centerY);
                                      gr.drawLine(centerX,0,centerX,this.getBounds().height);
                                      gr.setXORMode(getBackground());
  																		this.colorAdjust();
                                      if (! (appl.last_() instanceof shape)) { repaint(); return;}
                                      if (fill) repaintTo(appl.last_()); else refreshTo(appl.last_()); repaint();
                                   }
  public void refreshTo(shape sh) { if (sh.prev_()  instanceof shape) refreshTo(sh.prev_());
                                              sh.redraw();
                                    }
  public void repaintTo(shape sh) { if (sh.prev_()  instanceof shape) repaintTo(sh.prev_());
                                              sh.redraw(); gr.fillPolygon(sh.pol_());sh.mark();
                                    }
public boolean mouseDown(Event evt, int x, int y) {
    if (x<0 || y<0) return(false);
    if (appl.checkSel.getState()){//selection of a shape
    	this.setCursor(Cursor.getDefaultCursor());
                 selected = appl.last_();
                  while (selected  instanceof shape)
                       { if (selected.pol_().contains(x,y))
                                {gr.setColor(selected.kolor);
                                 gr.fillPolygon(selected.pol_());repaint();
                                  appl.displayMsg("\nshape :#"+selected.id+" selected");
                                   appl.toGlobals(false);
                                   return true;}
                         selected = selected.prev_();}
                         selected = null; appl.toGlobals(true);
                         return(true);
                       }
 this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
 if (!(selected instanceof shape)) { selected =new shape(appl.last_(),this);appl.toGlobals(false); }
 if (selected.s==4) {  selected =new shape(appl.last_(),this); }          
            gr.setColor(selected.kolor);
            selected.draw(x,y);
            gr.setXORMode(getBackground());                      
            repaint();

    return true;
  }
    public boolean mouseDrag(Event evt, int x, int y) {
      if (x<0 || y<0) return(false);
      if (appl.checkSel.getState()) return true;
      gr.setXORMode(getBackground());
      if  (!(selected instanceof shape)) return(false);
      selected.redraw(); selected.draw(x,y);
      selected.toProp(selected.s,(double)x,(double)y,appl);
     repaint();
    return true;
  }

public boolean mouseUp(Event evt, int x, int y) {
// validate the last drawn node  
    if (x<0 || y<0) return(false);
    if (appl.checkSel.getState()) return true;
    if  (!(selected instanceof shape)) return(true);
    selected.toProp(selected.s,(double)x,(double)y,appl);
    gr.setPaintMode(); selected.redraw(); repaint();
    selected.s++;
   if (selected.s ==4) { this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
   										appl.register(selected);}
   return true;
  }
public void fPaintMode(s_Mode mode) {
       if (mode instanceof s_Mode)
           {this._min_max(mode); float val;
           	Rectangle r = getBounds();    
            appl.displayMsg("\tField min:"+min+", max:"+max);//+",c[0] of mode:"+(float)mode.c[0]+" & c["+(mode.solv.mxe*mode.solv.my)+"] of mode:"+(float)mode.c[mode.solv.mxe*mode.solv.my]);
            appl.displayMsg("\npatience : image with "+r.height+" rows to build !\n");
            int pixel[] = new int[r.width * r.height];
            int c[] = new int[4]; int margin=5; int iValMax = 4096;
            //this.start();
            int k = 0; gr.setPaintMode(); int patienceNb= (int)(r.height/10);
            for (int yy = 0;yy < r.height;yy++) { if ( (yy % patienceNb)==0) { appl.showMsg("computing image..."+yy+"/"+r.height);
                                                                                                                appl.displayMsg("..."+yy);}
	    for (int xx = 0;xx <r.width;xx++) {
                if ((xx & 1)==1) { pixel[k]=pixel[k-1];k++;continue;}
                if ((yy & 1)==1) { pixel[k]=pixel[k-r.width];k++;continue;}
                if (!appl.checkSel.getState()){
                        if ((xx & 2)==2) { pixel[k]=pixel[k-1];k++;continue;}
                        if ((yy & 2)==2) { pixel[k]=pixel[k-r.width];k++;continue;}
                        }
									c[0] = c[1] = c[2] =c[3] = 0;
                 if (xx< margin) { cbuild(c, r.height-yy,r.height);}
                        else  if ((yy>mode.dom.basePoint().y) && (yy < mode.dom.basePoint().y+mode.dom.size_().height)
                                          && (xx>mode.dom.basePoint().x) && (xx < mode.dom.basePoint().x+mode.dom.size_().width))
                                             { val = (float) mode.Val(xx,yy) - min; val *= (iValMax)/(max-min);
                                               cbuild(c,(int)val,iValMax);
                                              }
                                pixel[k++] = ((c[3] << 24) |   (c[0] << 16) | (c[1] << 8) | (c[2] << 0));}
                       }
            Image img = createImage(new MemoryImageSource(r.width, r.height,ColorModel.getRGBdefault(),(int[])pixel, 0, r.width));
            gr.drawImage(img,0,0,this);gr.setXORMode(getBackground());
            refreshTo(appl.last_()); repaint();
      }
       else { appl.displayMsg("\nNot a valid mode!"); appl.showMsg("Not a valid mode!");}
  }
public void _min_max(s_Mode mode){
  min = Float.MAX_VALUE ; max =Float.MIN_VALUE;float val;
	for (int yy =  mode.dom.basePoint().y; yy <= mode.dom.basePoint().y+mode.dom.size_().height; yy+=8)
  			{for (int xx =  mode.dom.basePoint().x; xx <=(mode.dom.basePoint().x+mode.dom.size_().width); xx+=8)
                { if ((val= (float)mode.Val(xx,yy))<min) min = val;
                          if (val>max) max = val;
                }
         }
	}	
public void drawProfile(s_Mode mode, boolean displayFlag) {
	if (!(mode instanceof s_Mode))
			{ appl.displayMsg("\nNot a valid mode!"); appl.showMsg("Not a valid mode!");return;}
	int yy = mode.dom.basePoint().y+mode.dom.size_().height/2;// central line
	int yOld=centerY; int ixOld = mode.dom.basePoint().x;
	gr.setPaintMode();gr.setColor(Color.black);
	gr.drawLine(ixOld,yOld,ixOld+mode.dom.size_().width,yOld);
	if (Math.abs(min)>Math.abs(max)) { max = Math.abs(min);}
	appl.displayMsg("\nCentral profile of mode\nmin ="+min+"\tmax ="+max);
	if (displayFlag) appl.displayMsg("\n  x\t value");
  for (int ix =  mode.dom.basePoint().x; ix <=(mode.dom.basePoint().x+mode.dom.size_().width); ix ++)
				{ float val =  (float)mode.Val(ix,yy);
					if (displayFlag) appl.displayMsg("\n"+ (ix-mode.dom.basePoint().x - halfX)/scaleX+"\t"+val);
					try { val /= (max); } catch (Exception e) {val=0;}
					//if (ix==centerX) appl.displayMsg("\nx:"+ix+","+(float)((ix-mode.dom.basePoint().x - halfX)/scaleX)+":"+val+","+mode.Val(ix,yy));
					val *= -getBounds().height/2; 
					val += centerY;
					gr.drawLine(ixOld,yOld,ix,(int)Math.round(val));
				  ixOld=ix; yOld=(int)Math.round(val);}
	appl.displayMsg("\nEIM:");
	mode.kxEIM=mode.kxFromSquareFitting(0,(appl.debugCode & appl.EIMFITDEBUG)==appl.EIMFITDEBUG);//Number
	//gr.setColor(Color.red);drawEIMProfile(mode);
	//mode.kxEIM=mode.kxFromSquareFitting(mode.kxEIM,(appl.debugCode & appl.EIMFIT)==appl.EIMFIT);
	gr.setColor(Color.blue);drawEIMProfile(mode);
	double ncore= mode.indexCoreEIM(mode.kxEIM);
	appl.displayMsg(""+mode.nPeaks+" peaks\tn_core,mx,psi,kx,neff:\t"+(float)ncore+"\t"+(float)mode.mxEIM+"\t"+(float)mode.mxEIM2+"\t"+(float)mode.psiEIM+"\t"+(float)mode.kxEIM+"\t"+(float)mode.neff+" ");//modAppl.format("\t"+(float)mode.neff,11));
	drawEIMProfile(mode);
	repaint();
}
public void drawEIMProfile(s_Mode mode){
	// mode sine shape from effective index method
  if (!(mode instanceof s_Mode))
			{ appl.displayMsg("\nNot a valid mode!"); appl.showMsg("Not a valid mode!");return;}
  Rectangle box=this.coreBounds(false);
  double mxsEIM=mode.mxEIM;
  gr.setPaintMode();
  int yOld=999; int xOld = box.x;
  double val0= Math.round(Math.cos(mode.kxEIM*(box.x-centerX)/scaleX+mode.psiEIM)*getBounds().height/2.);
  val0 *=Math.exp(-mxsEIM*(box.x-centerX)/scaleX);
  for (int x =  mode.dom.basePoint().x; x <=(mode.dom.basePoint().x+mode.dom.size_().width); x ++)
  //for (int x =  box.x; x <= box.x+box.width; x++)
    {double xx= Math.round(x-this.centerX)/scaleX;
	   double val= Math.round(Math.cos(mode.kxEIM*xx+mode.psiEIM)*getBounds().height/2.);
	   if (x==box.x+box.width) { val0=val*Math.exp(mxsEIM*xx);mxsEIM=-mxsEIM;}
	   if ((x<box.x) || (x>box.x+box.width))
	   				val=Math.round(val0*Math.exp(mxsEIM*xx));
	   if (yOld!=999) gr.drawLine(xOld,yOld,x,(int)Math.round(-val+centerY));
	   xOld=x; yOld=(int)Math.round(-val+centerY);
	   }
	  repaint();
    }
/*kxEIM= mode.kxFromCorrel();
	if (mode.even) psiEIM=Math.PI/2; else psiEIM=0;
	appl.displayMsg("\nspatial freq.(correl.):"+(float)kxEIM+((mode.even)?" even":"odd"));
	gr.setPaintMode();gr.setColor(Color.red);
  yOld=999; xOld = box.x;
  for (int x =  box.x; x <= box.x+box.width; x++)
    {double xx= Math.round(x-this.centerX)/scaleX;
	   double val= Math.round(-Math.sin(kxEIM*xx+psiEIM)*getBounds().height/2. + centerY);
	   if (yOld!=999) gr.drawLine(xOld,yOld,x,(int)Math.round(val));
	   xOld=x; yOld=(int)Math.round(val);}
repaint();
}*/
private void cbuild(int c[], int ival,int ivalmax)
      {   
            int bl, bl1, rd,rd1,gr,gr1;
            if (ival<0) ival= 0;
             else if (ival>=ivalmax) ival= ivalmax-1;
            ival *= nbColors;  int v = (int) ival/ivalmax ; ival = ival % ivalmax;
            bl = basicColor[v].getBlue(); bl1 = basicColor[v+1].getBlue(); bl +=(bl1-bl)*ival/ivalmax; c[2]=bl;
            gr = basicColor[v].getGreen(); gr1 = basicColor[v+1].getGreen();gr +=(gr1-gr)*ival/ivalmax ;c[1]=gr;
            rd = basicColor[v].getRed();rd1 = basicColor[v+1].getRed(); rd += (rd1-rd)*ival/ivalmax ; c[0]= rd;           
            c[3]=255; 
    }
	private void colorAdjust() {
		double indMin = this.index; double indMax=0;shape sh;
		if (appl.nmin!=0) indMin = appl.nmin;
		if (appl.nmax!=0) indMax = appl.nmax;
			else { indMax=indMin;sh = appl.last_();
							while (shape.valid(sh)) {
							  if (sh.index >indMax) indMax =sh.index;
			    			sh = sh.prev_();}
						}
		Color col = Color.orange;
		Color backCol = this.getBackground();
		sh = appl.last_();
		while (shape.valid(sh)) {
					double ratio = Math.abs(sh.index - indMin)/(indMax-indMin);
			    int bl = (int)Math.round((col.getBlue()- backCol.getBlue())*ratio)+backCol.getBlue();
			    int rd = (int)Math.round((col.getRed()- backCol.getRed())*ratio)+backCol.getRed();
					int gr = (int)Math.round((col.getGreen()- backCol.getGreen())*ratio)+backCol.getGreen();
			    try { sh.kolor = new Color(rd,gr,bl);}catch(Exception ex) {sh.kolor = Color.green;}
			    sh = sh.prev_();}
	}
public void fPaintCoeff(s_Mode mm) {
       if (mm instanceof s_Mode)
           {  Rectangle r = getBounds(); int wx = r.width/mm.solv.mx; int wy = r.height/mm.solv.my;
              int pTot = 2 <<10; int c[]=new int[4];
              gr.setPaintMode();
              for (int i=0; i<mm.solv.mx;i++) 
                    for (int j=0; j<mm.solv.my;j++)
                        { cbuild(c,(int)mm.c[mm.solv.my*i+j]*pTot,pTot);
                          gr.setColor(new Color(c[0],c[1],c[2]));
                          gr.fillRect(i*wx,j*wy,wx,wy);}
              repaint();
            }
}
}// end class drawing