import java.awt.*;
import java.awt.geom.*;
class CuCu 
 {
  static String type="CuCu";
  boolean rw=false;
  PathIterator iterator;
  CubicCurve2D c;
  static M parent;
  Te te;
  LC lc;
  static final double PI=Math.PI;
  static final double DR=PI/180;
  static final double RD=180/PI;
  int mi=-1;
  double x=0,y=0;
  int xi=0,yi=0;
  Point p;
  Point2D p2d;
  dP dp;
  dP[] dpa=new dP[0];
  Rec[] reca=new Rec[0];
  int reci=-1;
  dP odp;
  Graphics2D g;
  boolean closed=true;
  boolean handles=true;
  String name;
  double snap=10;
  public CuCu(M p,String n,boolean c,boolean h,dP[] a)
   {
    parent=p;
    name=n;
    te=parent.te; 
    lc=parent.lc;
    closed=c;
    handles=h;
    dpa=a;
    reca=new Rec[dpa.length];
    for(int i=0;i<dpa.length;i+=3) dpa[i+2]=dpa[i+1].sym(dpa[i]);
    for(int i=0;i<dpa.length;i++) reca[i]=new Rec(dpa[i].sub(4,4),8,8);
    Te.CuCuh.put(name,this);
    lc.hh.put(name,type);
    lc.rm=1;
    //te.ar(name,type);
    te.ar(name);
    fender();
   }
  void yank(double u)
   {
    double [] eqn={ dpa[1].y-u,3*(dpa[2].y-dpa[1].y),3*(dpa[1].y-2*dpa[2].y+dpa[3].y),3*dpa[2].y-dpa[1].y+dpa[4].y-3*dpa[3].y };
    double [] roots={0,1,2,3};
    int toots=CubicCurve2D.solveCubic(eqn, roots);
    tta("yank rez  toots:"+toots+"  0:"+roots[0]+"  1:"+roots[1]+"  2:"+roots[2]+"  3:"+roots[3]);
   }
  void setclosed(boolean b)
   {
    closed=b;
    render();
   }
  void sethandles(boolean b)
   {
    handles=b;
    render();
   }
  void setdpa(dP[] a)
   {
    dpa=a;
    for(int i=0;i<dpa.length;i++) reca[i]=new Rec(dpa[i].sub(4,4),8,8);
    render();
   }
  void closeseg() 
   {
    closed=true; 
    render();
   }
  void addseg(dP a,dP b)
   {
    dP[] dpb=new dP[dpa.length];
    for(int i=0;i<dpa.length;i++) dpb[i]=dpa[i];
    dpa=new dP[3+dpa.length];
    reca=new Rec[dpa.length];
    int i=0;
    for(i=0;i<dpb.length;i++) dpa[i]=dpb[i];
    dpa[i++]=a;
    dpa[i++]=b;
    dpa[i]=b.sym(a);
    for(i=0;i<dpa.length;i++) reca[i]=new Rec(dpa[i].sub(4,4),8,8);
    render();
   }
  void snap(double d)
   {
    snap=d;
    if(snap==0) return;
    for(int i=0;i<dpa.length;i++) dpa[i]=dP.snap(dpa[i],snap);
    render();
   }
  void fender()
   {
    if(lc.rm==0 )
     {
      lc.clearoffscreen();
      render();
      lc.myRepaint();
     }
    else te.teS("render");
   }
  void render()   // not old render
   {
    if(dpa.length<=3) return;
    double opw=lc.pw;
    int i=0;
    c=new CubicCurve2D.Double();
    while(i+5<dpa.length)
     {
      tta("New CuCu.render dp1:"+dpa[i+1]+" dp2:"+dpa[i+2]+"dp3:"+dpa[i+3]+" dp4:"+dpa[i+4]);   
      // control 1b  +0
      // anchor 1   +1
      // control 1   +2
      // control 2    +3
      // anchor 2    +4
      // control 2b +5
      c.setCurve(dpa[i+1].x,dpa[i+1].y,dpa[i+2].x,dpa[i+2].y,dpa[i+3].x,dpa[i+3].y,dpa[i+4].x,dpa[i+4].y);
      //  setCurve(double x1,   double y1, double ctrlx1,  double ctrly1,  double ctrlx2,   double ctrly2,    double x2,   double y2)
      lc.offsgdraw(c);
      lc.spw(1);
      if(handles)
       {
        lc.offsgdraw(new Line2D.Double(dpa[i],dpa[i+2]));
        lc.offsgdraw(new Line2D.Double(dpa[i+3],dpa[i+5]));
       }
      i+=3;
      lc.spw(opw); 
     }
    if(closed)
     {
      i-=3;
      c.setCurve(dpa[i+4].x,dpa[i+4].y,dpa[i+5].x,dpa[i+5].y,dpa[0].x,dpa[0].y,dpa[1].x,dpa[1].y);
      lc.offsgdraw(c);
     }
    if(handles)
     {
      for(i=0;i<dpa.length;i++)
       {
        if(i==reci) lc.offsgsetColor(Color.green);
        lc.offsgfill(reca[i].rect);
        if(i==reci) lc.offsgsetColor(Color.black);
       }
     }
   }
  void oldrender()  
   {
    if(dpa.length<=3) return;
    double opw=lc.pw;
    int i=0;
    c=new CubicCurve2D.Double();
    while(i+5<dpa.length)
     {
      tta("CuCu.render dp1:"+dpa[i+1]+" dp2:"+dpa[i+2]+"dp3:"+dpa[i+3]+" dp4:"+dpa[i+4]);
      c.setCurve(dpa[i+1].x,dpa[i+1].y,dpa[i+2].x,dpa[i+2].y,dpa[i+3].x,dpa[i+3].y,dpa[i+4].x,dpa[i+4].y);
      lc.offsgdraw(c);
      lc.spw(1);
      if(handles)
       {
        lc.offsgdraw(new Line2D.Double(dpa[i],dpa[i+2]));
        lc.offsgdraw(new Line2D.Double(dpa[i+3],dpa[i+5]));
       }
      i+=3;
      lc.spw(opw); 
     }
    if(closed)
     {
      i-=3;
      c.setCurve(dpa[i+4].x,dpa[i+4].y,dpa[i+5].x,dpa[i+5].y,dpa[0].x,dpa[0].y,dpa[1].x,dpa[1].y);
      lc.offsgdraw(c);
     }
    if(handles)
     {
      for(i=0;i<dpa.length;i++)
       {
        if(i==reci) lc.offsgsetColor(Color.green);
        lc.offsgfill(reca[i].rect);
        if(i==reci) lc.offsgsetColor(Color.black);
       }
     }
   }
  boolean mmdp(dP dp)
   {
    for(int i=0;i<dpa.length;i++)
     {
      if(reca[i].contains(dp))
       {
        mi=i;
        lc.onsgsetColor(Color.blue);
        lc.onsgfill(reca[i].rect);
        return true;
       }
      if(mi==i)
       {
        mi=-1;
        lc.onsgsetColor(Color.black);
        lc.onsgfill(reca[i].rect);
       }
     }
    return false;
   }
  boolean mpdp(dP dp)
   {
    reci=-1;
    for(int i=0;i<dpa.length;i++) 
     {
      if(reca[i].contains(dp))
       {
        reci=i;
        odp=new dP(dpa[reci]);
        lc.onsgsetColor(Color.yellow);
        lc.onsgfill(reca[i].rect);
        return true;
       }
     }
    return false;
   }
  void mddp(dP dp)
   {
    if(reci ==-1) return;
    dpa[reci]=dp;
    int j=reci%3;
    if(j==0) dpa[reci+2]=dpa[reci+1].sym(dpa[reci]);
    else if(j==1)
     {
      dpa[reci+1]=dpa[reci].sub(odp.sub(dpa[reci+1]));
      dpa[reci-1]=dpa[reci].sub(odp.sub(dpa[reci-1]));
     }
    else if(j==2) dpa[reci-2]=dpa[reci-1].sym(dpa[reci]);
    for(int i=reci-j;i<reci-j+3;i++) reca[i]=new Rec(dpa[i].sub(4,4),8,8);
    odp=dp;
    fender();
   }
  void mrdp(dP dp) { reci=-1; }
  void ed()
   {
    tta1(name+".closed "+Te.Svo(closed));
    tta1(name+".handles "+Te.Svo(handles));
    tta1(name+".dpa "+Te.Svo(dpa));
   }
  static void tta(String s) { parent.tta(s); }
  static void tta1(String s) { parent.tta1(s); }
  public void rewind() 
   {
    c=new CubicCurve2D.Double();
    int i=0;
    c.setCurve(dpa[i+1].x,dpa[i+1].y,dpa[i+2].x,dpa[i+2].y,dpa[i+3].x,dpa[i+3].y,dpa[i+4].x,dpa[i+4].y);
    iterator = c.getPathIterator(null, 0.001);
    rw=true;
   }
  public dP next() 
   {
    if(! rw) rewind();
    double[] da = new double[6];
    iterator.currentSegment(da);
    int i=0;
    if ((Math.round(da[0]) == dpa[i+3].x) && (Math.round(da[1]) == dpa[i+3].y)) 
     {
      rw=false;
      tta("at end");
      return null;
     }
    iterator.next();
    iterator.currentSegment(da);
    return new dP(da[0],da[1]);
   }
  public dP dPAt(int index) 
   {
    rewind();
    for (int j=0;j<index; j++) iterator.next();
    double[] da = new double[8];
    iterator.currentSegment(da);
    return new dP(da[0],da[1]);
   }
 }
