#include<stdio.h>
#include<stdlib.h>  /* exit() */
#include<stdarg.h>
#include<string.h>
#include<math.h>

#include "fig2pdf.h"

void write_arrow(struct arrow *a,double x,double y,double dx,double dy,
                 int colour,char *buffer, int *i);

void write_arc(char* p){
  int i,j,open,filled,steps;
  int obj,sub,line_style,thickness,pen_colour,fill_colour,depth;
  int pen_style,fill,cap,dir,arrow_f,arrow_b;

  int debug;
  double style,width;
  double cx,cy,x1,x2,x3,y1,y2,y3;
  double theta,theta1,theta2,phi,phi1,phi2,r;
  double ax,ay,bx,by,q1,q2,k2;

  char *f;

  struct arrow forward,backward;

  /* DANGER */

  char buffer[1000];

  debug=flags&DEBUG_MASK;

  i=sscanf(p,"%d %d %d %d %d %d %d %d %d %lf %d %d %d %d"
	   " %lf %lf %lf %lf %lf %lf %lf %lf",
           &obj,&sub,&line_style,&thickness,&pen_colour,&fill_colour,
           &depth,&pen_style,&fill,&style,&cap,&dir,&arrow_f,&arrow_b,
           &cx,&cy,&x1,&y1,&x2,&y2,&x3,&y3);

  if (i!=22){
    fprintf(stderr,"Error parsing arc object\n");
    exit(1);
  }

  if (sub==1)
    open=1;
  else if (sub==2)
    open=0;
  else{
    fprintf(stderr,"Unexpected arc subtype skipped\n");
    return;
  }

  if (arrow_f){
    p=fgets(buffer,180,fig);
    i=sscanf(p,"%d %d %lf %lf %lf",&forward.type,&forward.style,
             &forward.thickness,&forward.width,&forward.height);
    if (i!=5){
      fprintf(stderr,"Error parsing forward arrow from arc - skipping.\n");
      return;
    }
  }

  if (arrow_b){
    p=fgets(buffer,180,fig);
    i=sscanf(p,"%d %d %lf %lf %lf",&backward.type,&backward.style,
             &backward.thickness,&backward.width,&backward.height);
    if (i!=5){
      fprintf(stderr,"Error parsing backward arrow from arc - skipping.\n");
      return;
    }
  }

  if (debug>2) fprintf(stderr,"Arc object read\n");
  /* Make co-ords relative to centre */

  x1-=cx;
  x2-=cx;
  x3-=cx;
  y1-=cy;
  y2-=cy;
  y3-=cy;

  /* And change to +ve y being up */

  y1=-y1;
  y2=-y2;
  y3=-y3;

  /* Scale to points */

  x1*=72.0/1200;
  x2*=72.0/1200;
  x3*=72.0/1200;
  y1*=72.0/1200;
  y2*=72.0/1200;
  y3*=72.0/1200;

  cx*=72.0/1200;
  cy=pg[1]-72.0*cy/1200;

  /* The following seems to be mad but true */ 

  if (thickness>1)
    width=(thickness-1)*72.0/80;
  else
    width=thickness*72.0/160;
      
  if (arrow_f){
    forward.width*=72.0/1200;
    forward.height*=72.0/1200;
    forward.thickness*=72.0/80;
  }

  if (arrow_b){
    backward.width*=72.0/1200;
    backward.height*=72.0/1200;
    backward.thickness*=72.0/80;
  }

  style*=72.0/80;

  filled=0;
  if ((fill>=0)&&(fill<=40)) filled=1;
  else if (fill!=-1) fprintf(stderr,"Unsupported fill type ignored\n");

  if ((filled==0)&&(width==0)) return; /* Nothing to do */

  i=sprintf(buffer,"q");

  if ((pen_colour<-1)||(pen_colour>MAX_COL)) pen_colour=-1;

  if (pen_colour==-1)
    i+=sprintf(buffer+i," 0 0 0 RG");
  else if (fig_colours[pen_colour])
    i+=sprintf(buffer+i," %s RG",fig_colours[pen_colour]);
  else
    fprintf(stderr,"Invalid pen colour %d\n",pen_colour);

  f=fill_col(fill_colour,fill);
  if (f) i+=sprintf(buffer+i," %s rg",f);

  i+=sprintf(buffer+i," %.2f w\n",width);

  if (cap) i+=sprintf(buffer+i,"%d J\n",cap);   /* 0 butt,
                                                   1 round,
                                                   2 projecting,
						   same as PDF */

  if (line_style>0) write_dash(line_style,style,buffer,&i);

  /* Shift centre to origin */
  /* gsave first so can grestore before arrows to undo shift */

  i+=sprintf(buffer+i,"q 1 0 0 1 %.2f %.2f cm\n",cx,cy);

  if (open)
    i+=sprintf(buffer+i,"%.2f %.2f m\n",x1,y1);
  else
    i+=sprintf(buffer+i,"0 0 m %.2f %.2f l\n",x1,y1);

  theta1=atan2(y1,x1);
  theta2=atan2(y3,x3);

  theta=theta2-theta1;

  if (dir&&(theta<0)) theta+=2*M_PI;
  if ((!dir)&&(theta>0)) theta-=2*M_PI;

  r=sqrt(x1*x1+y1*y1);
  if (debug>2)
    fprintf(stderr,"theta1=%f theta2=%f theta=%f\n",theta1,theta2,theta);

  /* Sufficient points to construct the bounding box are:
   * the centre (if it is a closed curve)
   * the end points
   * the points at theta = 0, pi/2, pi, 3pi/2 wrt x axis
   *
   * However, theta lies in the range -3pi to 3pi
   */ 

  if (!open) bb_fix(cx,cy,width);
  bb_fix(cx+x1,cy+y1,width);
  bb_fix(cx+x3,cy+y3,width);
  for(j=-6;j<=6;j++){
    phi=0.5*j*M_PI;
    if (((theta>0)&&((phi>theta1)&&(phi<theta1+theta)))||
	((theta<0)&&((phi>theta1+theta)&&(phi<theta1))))
      bb_fix(cx+r*cos(phi),cy+r*sin(phi),width);
  }

  /* Make arc in between one and four bezier steps */

  steps=1+fabs(theta)/1.3;
  phi=theta/steps;

  for(j=0;j<steps;j++){
    phi1=theta1+j*phi;
    phi2=phi1+phi;
    ax=r*cos(phi1);   /* See A Riskus, Information Technology and Control */
    ay=r*sin(phi1);   /* (2006) Vol 35 No 4 page 371 for these formulae */
    bx=r*cos(phi2);
    by=r*sin(phi2);

    q1=ax*ax+ay*ay;
    q2=q1+ax*bx+ay*by;

    k2=4*(sqrt(2*q1*q2)-q2)/(3*(ax*by-ay*bx));

    i+=sprintf(buffer+i,"%.2f %.2f %.2f %.2f %.2f %.2f c\n",
	       ax-k2*ay,ay+k2*ax,bx+k2*by,by-k2*bx,bx,by);

  }

  //  fprintf(stderr,"Arc end is (%.2f,%.2f) or (%.2f,%.2f)\n",bx,by,x3,y3);
  //  fprintf(stderr,"Arc end is %.3f or %.3f\n",theta2,phi2);

  if (filled)
    if (width==0.0)
      i+=sprintf(buffer+i,"h f\n");
    else
      if (open)
	i+=sprintf(buffer+i,"B\n");
      else
	i+=sprintf(buffer+i,"b\n");
  else
    if (open)
      i+=sprintf(buffer+i,"S\n");
    else
      i+=sprintf(buffer+i,"h S\n");
  
  if (dir==0) dir=-1;

/* Undo co-ord transform */
  i+=sprintf(buffer+i,"Q ");

  /* Need to correct for long arrows on tightish curves */

  if (arrow_f){
    if (forward.height<r){
      phi=2*asin(0.5*forward.height/r);
      ax=r*cos(theta2-dir*phi);
      ay=r*sin(theta2-dir*phi);
      write_arrow(&forward,cx+x3,cy+y3,x3-ax,y3-ay,
		  pen_colour,buffer,&i);
    }
    else write_arrow(&forward,cx+x3,cy+y3,-dir*y3,dir*x3,
		     pen_colour,buffer,&i);
  }

  if (arrow_b){
    if (backward.height<r){
      phi=2*asin(0.5*backward.height/r);
      ax=r*cos(theta1+dir*phi);
      ay=r*sin(theta1+dir*phi);
      write_arrow(&backward,cx+x1,cy+y1,x1-ax,y1-ay,
		  pen_colour,buffer,&i);
    }
    else write_arrow(&backward,cx+x1,cy+y1,dir*y1,-dir*x1,
		     pen_colour,buffer,&i);
  }

  i+=sprintf(buffer+i,"Q");
  
  OBJ_PRN("<</Length %d>> stream\n%s\nendstream\nendobj\n\n",i,buffer);

  add_obj(cref,depth);
  
}
