#include "abc2ps.h"
#include <string.h>
#include <math.h>
#include "buffer.h"

#if ABC_USE_GRAPHICS_LIB

#define DEBUG_COMMANDS 0

enum {
  kMoveTo,
  kLineTo,
  kCurveTo,
  kAddArc,
  kNewPath,
  kClosePath,
  kSetLineWidth,
  kFillPath,
  kStrokePath,
  kSave,
  kRestore,
  kTranslate,
  kScale,
  kSetFont,
  kDrawText,
};

#if DEBUG_COMMANDS
static const char* debugNames[] = {
  "kMoveTo",
  "kLineTo",
  "kCurveTo",
  "kAddArc",
  "kNewPath",
  "kClosePath",
  "kSetLineWidth",
  "kFillPath",
  "kStrokePath",
  "kSave",
  "kRestore",
  "kTranslate",
  "kScale",
  "kSetFont",
  "kDrawText",
};
#endif

static const char *bufferPtr;

static void put( char *p, int size )
{
  if (nbuf+size>BUFFSZ) {
    printf("+++ a2b: buffer full, BUFFSZ=%d\n", BUFFSZ);
    return;
  }

  int i;
  for ( i = 0; i < size; i++)
    buf[nbuf+i] = p[i];
  nbuf += size;
}

static void putInt( int i )
{
  put( (char*)&i, sizeof(int) );
}

static void putFloat( float v )
{
  put( (char*)&v, sizeof(float) );
}

static void putByte( char v )
{
  put( (char*)&v, sizeof(char) );
}

static void putString( const char *s )
{
  int size = strlen(s)+1;
  putInt( size );
  put( (char*)s, size );
}


static void get( char *p, int size )
{
  while ( size-- )
    *p++ = *bufferPtr++;
}

static int getInt()
{
  int i;
  get( (char*)&i, sizeof(int) );
#if DEBUG_COMMANDS
  printf("  - %d\n", i);
#endif
  return i;
}

static float getFloat()
{
  float v;
  get( (char*)&v, sizeof(float) );
#if DEBUG_COMMANDS
  printf("  - %f\n", v);
#endif
  return v;
}

static char getByte()
{
  char v;
  get( (char*)&v, sizeof(char) );
  return v;
}

static const char* getString()
{
  int size;
  size = getInt();
  const char *s = bufferPtr;
  bufferPtr += size;
#if DEBUG_COMMANDS
  printf("  - %s\n", s);
#endif
  return s;
}

void graphicsBeginPage( GraphicsContext cx )
{
  if ( gGraphicsMethods.beginPage )
    gGraphicsMethods.beginPage( cx );
}

void graphicsEndPage( GraphicsContext cx )
{
  if ( gGraphicsMethods.endPage )
    gGraphicsMethods.endPage( cx );
}

void graphicsMoveTo( GraphicsContext cx, float x, float y )
{
  check_buffer( NULL, 64 );
  putByte( kMoveTo );
  putFloat( x );
  putFloat( y );
}

void graphicsLineTo( GraphicsContext cx, float x, float y )
{
  check_buffer( NULL, 64 );
  putByte( kLineTo );
  putFloat( x );
  putFloat( y );
}

void graphicsCurveTo( GraphicsContext cx, float x1, float y1, float x2, float y2, float x3, float y3 )
{
  check_buffer( NULL, 64 );
  putByte( kCurveTo );
  putFloat( x1 );
  putFloat( y1 );
  putFloat( x2 );
  putFloat( y2 );
  putFloat( x3 );
  putFloat( y3 );
}

void graphicsAddArc( GraphicsContext cx, float x, float y, float radius, float startAngle, float endAngle )
{
  check_buffer( NULL, 64 );
  putByte( kAddArc );
  putFloat( x );
  putFloat( y );
  putFloat( radius );
  putFloat( startAngle );
  putFloat( endAngle );
}

void graphicsNewPath( GraphicsContext cx )
{
  putByte( kNewPath );
}

void graphicsClosePath( GraphicsContext cx )
{
  putByte( kClosePath );
}

void graphicsSetLineWidth( GraphicsContext cx, float w )
{
  check_buffer( NULL, 64 );
  putByte( kSetLineWidth );
  putFloat( w );
}

void graphicsFill( GraphicsContext cx )
{
  putByte( kFillPath );
}

void graphicsStroke( GraphicsContext cx )
{
  putByte( kStrokePath );
}

void graphicsSave( GraphicsContext cx )
{
  putByte( kSave );
}

void graphicsRestore( GraphicsContext cx )
{
  putByte( kRestore );
}

void graphicsTranslate( GraphicsContext cx, float x, float y )
{
  check_buffer( NULL, 64 );
  putByte( kTranslate );
  putFloat( x );
  putFloat( y );
}

void graphicsScale( GraphicsContext cx, float x, float y )
{
  check_buffer( NULL, 64 );
  putByte( kScale );
  putFloat( x );
  putFloat( y );
}

void graphicsSetFont( GraphicsContext cx, int font, int size )
{
  check_buffer( NULL, 64 );
  putByte( kSetFont );
  putInt( font );
  putInt( size );
}

void graphicsDrawText( GraphicsContext cx, float x, float y, const char *text, int alignment )
{
  check_buffer( NULL, 64 );
  putByte( kDrawText );
  putFloat( x );
  putFloat( y );
  putString( text );
  putInt( alignment );
}


void graphicsFlushBuffer( GraphicsContext cx, const char* buffer, int start, int end )
{
  const char *bufferEnd = buffer+end;
  bufferPtr = buffer+start;
#if DEBUG_COMMANDS
printf("flushBuffer %d %d\n", start, end);
#endif
  while ( bufferPtr < bufferEnd) {
    char command;
    float x, y, x2, y2, x3, y3;
    int j, k;
    const char *s;

    command = getByte();
#if DEBUG_COMMANDS
    if ( command >= kMoveTo && command <= kDrawText )
      printf("* %s\n", debugNames[command]);
    else
      printf("* %d\n", (int)command);
#endif
    switch ( command ) {
    case kMoveTo:
      x = getFloat();
      y = getFloat();
      gGraphicsMethods.moveTo( cx, x, y );
      break;
    case kLineTo:
      x = getFloat();
      y = getFloat();
      gGraphicsMethods.lineTo( cx, x, y );
      break;
    case kCurveTo:
      x = getFloat();
      y = getFloat();
      x2 = getFloat();
      y2 = getFloat();
      x3 = getFloat();
      y3 = getFloat();
      gGraphicsMethods.curveTo( cx, x, y, x2, y2, x3, y3 );
      break;
    case kAddArc:
      x = getFloat();
      y = getFloat();
      x2 = getFloat();
      y2 = getFloat();
      x3 = getFloat();
      gGraphicsMethods.addArc( cx, x, y, x2, y2, x3 );
      break;
    case kNewPath:
      gGraphicsMethods.newPath( cx );
      break;
    case kClosePath:
      gGraphicsMethods.closePath( cx );
      break;
    case kFillPath:
      gGraphicsMethods.fill( cx );
      break;
    case kStrokePath:
      gGraphicsMethods.stroke( cx );
      break;
    case kSave:
      gGraphicsMethods.save( cx );
      break;
    case kRestore:
      gGraphicsMethods.restore( cx );
      break;

    case kTranslate:
      x = getFloat();
      y = getFloat();
      gGraphicsMethods.translate( cx, x, y );
      break;
    case kScale:
      x = getFloat();
      y = getFloat();
      gGraphicsMethods.scale( cx, x, y );
      break;

    case kSetLineWidth:
      x = getFloat();
      gGraphicsMethods.setLineWidth( cx, x );
      break;

    case kSetFont:
      j = getInt();
      k = getInt();
      gGraphicsMethods.setFont( cx, j, k );
      break;
    case kDrawText:
      x = getFloat();
      y = getFloat();
      s = getString();
      k = getInt();
      gGraphicsMethods.drawText( cx, x, y, s, k );
      break;
    default:
      printf("Bad command %d\n", command);
      return;
    }
  }
}



static void curveTo( GraphicsContext cx, float x, float y, float f1, float f2, float p[][2], int i0, int ncv )
{
  int i1,m;
  
  i1=i0;
  for (m=0; m<ncv; m++) {
    graphicsCurveTo(cx, 
       x+f1*(p[i1+0][0]), 
       y+f2*(p[i1+0][1]),
       x+f1*(p[i1+1][0]), 
       y+f2*(p[i1+1][1]),
       x+f1*(p[i1+2][0]), 
       y+f2*(p[i1+2][1])
    );
    i1=i1+3;
  }
}

static void addLineSegments(GraphicsContext cx, float x, float y, float f1, float f2, float p[][2], int i0, int nseg)
{
  int i;
  for (i=0; i<nseg; i++)
    graphicsLineTo( cx, x+f1*(p[i0+i][0]), y+f2*(p[i0+i][1]) );
}

static void moveTo(GraphicsContext cx, float x, float y, float f1, float f2, float p[][2], int i0)
{
  graphicsMoveTo( cx, x+f1*p[i0][0], y+f2*p[i0][1] );
}

void cgcshow( GraphicsContext cx, float x, float y, const char *s )
{
  graphicsDrawText( cx, x, y, s, 0 );
}

void cglshow( GraphicsContext cx, float x, float y, const char *s )
{
  graphicsDrawText( cx, x, y, s, -1 );
}

void cgrshow( GraphicsContext cx, float x, float y, const char *s )
{
  graphicsDrawText( cx, x, y, s, 1 );
}

void cgwd( GraphicsContext cx, const char *s, float x, float y )
{
  cgrshow( cx, x, y, s );
}

void cgwhf( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsScale( cx, 0.5f, 1.2f );
  cgrshow( cx, x, y, "-" );
  graphicsRestore( cx );
}

void cgwln( GraphicsContext cx, float x1, float x2, float y )
{
  graphicsSave( cx );
  graphicsSetLineWidth( cx, 0.6f );
  graphicsMoveTo( cx, x1, y );
  graphicsLineTo( cx, x2, y );
  graphicsStroke( cx );
  graphicsRestore( cx );
}

void drawTimeSignature( GraphicsContext cx, float x, const char *top, int bottom )
{
  char buf[32];
  graphicsSetFont( cx, kSerifFont, 13 );
  cgcshow( cx, x, 14, top );
  sprintf( buf, "%d", bottom );
  cgcshow( cx, x, 2, buf );
}

void drawStemUp( GraphicsContext cx, float x, float y, float u )
{
  graphicsMoveTo( cx, x+STEM_XOFF, y+STEM_YOFF );
  graphicsLineTo( cx, x+STEM_XOFF, y+u );
  graphicsStroke( cx );
}

void drawStemDown( GraphicsContext cx, float x, float y, float u )
{
  graphicsMoveTo( cx, x-STEM_XOFF, y-STEM_YOFF );
  graphicsLineTo( cx, x-STEM_XOFF, y-u );
  graphicsStroke( cx );
}

void drawDot( GraphicsContext cx, float x, float y, float dx, float dy )
{
  graphicsMoveTo( cx, x+dx, y+dy );
  graphicsAddArc( cx, x+dx, y+dy, 1.2f, 0, 2*M_PI );
  graphicsFill( cx );
}

void drawHat( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x-4, y-2 );
  graphicsLineTo( cx, x, y+4 );
  graphicsStroke( cx );

  graphicsMoveTo( cx, x, y+4 );
  graphicsLineTo( cx, x+4, y-2 );
  graphicsLineTo( cx, x+2, y-2 );
  graphicsLineTo( cx, x-1, y+2.5 );
  graphicsFill( cx );
}

void drawAtt( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x-4, y-3 );
  graphicsLineTo( cx, x+4, y );
  graphicsLineTo( cx, x-4, y+3 );
  graphicsStroke( cx );
}

void drawRollDown( GraphicsContext cx, float x, float y ) {
  float q[7][2] = {
    {-13,0},{-12,-9},{12,-9},{13,0},{10,-7.4},{-10,-7.4},{-13,-0} };

  float f1,f2;

  f1=0.5;
  f2=0.5;
  f2=f2*1.8;
  moveTo(cx, x, y,f1,f2,q,0);
  curveTo(cx, x, y,f1,f2,q,1,2);
  graphicsFill( cx );
}

void drawRollUp( GraphicsContext cx, float x, float y ) {
  float q[7][2] = {
    {-13,0},{-12,9},{12,9},{13,0},{10,7.4},{-10,7.4},{-13,-0} };

  float f1,f2;

  f1=0.5;
  f2=0.5;
  f2=f2*1.8;
  moveTo(cx, x, y,f1,f2,q,0);
  curveTo(cx, x, y,f1,f2,q,1,2);
  graphicsFill( cx );
}

void drawSlide( GraphicsContext cx, float x, float y, float dy ) {
  float s[7][2] = {
    {-8,-4.8},{-6,-5.5},{-3,-4.6},{0,0},{-2.3,-5},{-6,-6.8},{-8.5,-6} };

  float f1,f2;
  f1=0.9;
  f2=1.0;
  moveTo(cx, x, y-dy,f1,f2,s,0);
  curveTo(cx, x, y-dy,f1,f2,s,1,2);
  graphicsFill( cx );
}

void drawTrill( GraphicsContext cx, float x, float y ) {
  graphicsSetFont( cx, kSansSerifFont, 13 );
  cgcshow( cx, x, y, "tr" );//FIXME-italic
}

void drawGracing( GraphicsContext cx, float x, float y ) {
  float p[7][2] = {
    {-10,-2},{0,15},{1,-11},{10,2},{0,-15},{-1,11},{-10,-2} };

  moveTo( cx, x, y, 0.5, 0.5, p, 0 );
  curveTo( cx, x, y, 0.5, 0.5, p, 1, 2 );
  graphicsFill( cx );
}

void drawStaccato( GraphicsContext cx, float x, float y ) {
  graphicsMoveTo( cx, x, y );
  graphicsAddArc( cx, x, y, 1.2f, 0, 2*M_PI );
  graphicsFill( cx );
}

void drawBarMark( GraphicsContext cx, float x, float y ) {
	graphicsSave( cx );
  graphicsSetLineWidth( cx, 1.4f );
#if ABC_USE_CAIRO
  cairo_set_line_cap( cx, CAIRO_LINE_CAP_ROUND );
#else
  CGContextSetLineCap( cx, kCGLineCapRound );
#endif
  graphicsMoveTo( cx, x-3.5f, y );
  graphicsLineTo( cx, x+3.5f, y );
  graphicsStroke( cx );
	graphicsRestore( cx );
}

void drawHold( GraphicsContext cx, float x, float y ) {
  float p[8][2] = {     /* for hold sign */
    {-15,0},{-15,23},{15,23},{15,0},
    {14.5,0},{12,18},{-12,18},{-14.5,0} };

  float f1,f2;

  f1=f2=0.5;
  graphicsMoveTo( cx, x, y );
  graphicsAddArc( cx, x, y+1.5f, 1.3f, 0, 2*M_PI );
  graphicsFill( cx );

  moveTo(cx, x, y,f1,f2,p,0);
  curveTo(cx, x, y,f1,f2,p,1,1);
  addLineSegments(cx, x, y,f1,f2,p,4,1);
  curveTo(cx, x, y,f1,f2,p,5,1);
  graphicsFill( cx );
}

void drawUpBow( GraphicsContext cx, float x, float y ) {
  float r[3][2] = {
    {-3.2,11},{0,0},{3.2,11} };

  float f1,f2;

  f1=f2=0.8;
  moveTo(cx, x, y,f1,f2,r,0);
  addLineSegments(cx, x, y,f1,f2,r,1,2);
  graphicsStroke( cx );
}

void drawDownBow( GraphicsContext cx, float x, float y ) {
  float q[8][2] = {
    {-4,0},{-4,9},{4,9},{4,0},
    {-4,6},{-4,9},{4,9},{4,6} };

  float f1,f2;

  f1=f2=0.8;
  moveTo(cx, x, y, f1,f2,q,0);
  addLineSegments(cx, x, y, f1,f2,q,1,3);
  graphicsStroke( cx );
  moveTo(cx, x, y, f1,f2,q,4);
  addLineSegments(cx, x, y, f1,f2,q,5,3);
  graphicsFill( cx );
}

void drawHorizontalLine( GraphicsContext cx, float x, float y )
{
  graphicsNewPath( cx );
  graphicsMoveTo( cx, x-5.5f, y );
  graphicsLineTo( cx, x+5.5f, y );
  graphicsStroke( cx );
}

void cghl1( GraphicsContext cx, float x, float y )
{
  graphicsNewPath( cx );
  graphicsMoveTo( cx, x-7, y );
  graphicsLineTo( cx, x+7, y );
  graphicsStroke( cx );
}

void cgbm( GraphicsContext cx, float x1, float y1, float x2, float y2, float t )
{
  graphicsMoveTo( cx, x2, y2 );
  graphicsLineTo( cx, x2, y2-t );
  graphicsLineTo( cx, x1, y1-t );
  graphicsLineTo( cx, x1, y1 );
  graphicsFill( cx );
}

void cgbnum( GraphicsContext cx, float x, float y, int n )
{
  char s[32];
  sprintf( s, "%d", n );
  graphicsSetFont( cx, kSansSerifFont, 12 );
  cgcshow( cx, x, y, s );
}

void cghbr( GraphicsContext cx, float x1, float y1, float x2, float y2 )
{
  graphicsMoveTo( cx, x2, y2 );
  graphicsLineTo( cx, x1, y1 );
  graphicsLineTo( cx, x1, y1-3 );
  graphicsStroke( cx );
}

static float sFlagUpPath[13][2] = {
  {0.0, 0.0},  {1.5, -3.0},  {1.0, -2.5},  {4.0, -6.0},  {9.0, -10.0},  
  {9.0, -16.0},  {8.0, -20.0},  {7.0, -24.0},  {4.0, -26.0},  
  {6.5, -21.5},  {9.0, -15.0},  {4.0, -9.0},  {0.0, -8.0} } ;

static float sFlagDownPath[13][2] = {
  {0.0, 0.0},  {1.5, 3.0},  {1.0, 2.5},  {4.0, 6.0},  {9.0, 10.0},  
  {9.0, 16.0},  {8.0, 20.0},  {7.0, 24.0},  {4.0, 26.0},  
  {6.5, 21.5},  {9.0, 15.0},  {4.0, 9.0},  {0.0, 8.0} } ;

void drawFlag( GraphicsContext cx, float x, float y, float len, int s, char du )
{
  float f1,f2;
  int i;

  f1=f2=5.0/9.0;

  if ( du == 'u' ) {
    x += STEM_XOFF;
    y += len;
    for ( i = 0; i < s; i++ ) {
      moveTo(cx,x,y,f1,f2,sFlagUpPath,0);
      curveTo(cx,x,y,f1,f2,sFlagUpPath,1,4);
      y -= 6.2;
    }
  } else {
    x -= STEM_XOFF;
    y -= len;
    for ( i = 0; i < s; i++ ) {
      moveTo(cx,x,y,f1,f2,sFlagDownPath,0);
      curveTo(cx,x,y,f1,f2,sFlagDownPath,1,4);
      y += 6.2;
    }
  }
  graphicsFill( cx );
}

void drawSharpSign0( GraphicsContext cx, float x, float y )
{
  float q[14][2]={  
    {4,4},{4,7},{-4,5},{-4,2},{4,4},{4,-5},{4,-2},{-4,-4},{-4,-7},{4,-5}, 
    {2,-10},{2,11.5},{-2,-11.5},{-2,10} };

  float f2=6.5/9.0;
  float f1=f2*0.9;

  moveTo(cx, x, y, f1,f2,q,0);
  addLineSegments(cx, x, y, f1,f2,q,1,4);
  moveTo(cx, x, y, f1,f2,q,0);
  addLineSegments(cx, x, y, f1,f2,q,6,4);
  graphicsFill( cx );
  moveTo(cx,x, y, f1,f2,q,10);
  addLineSegments(cx,x, y, f1,f2,q,11,1);
  graphicsStroke( cx );
  moveTo(cx,x, y, f1,f2,q,12);
  addLineSegments(cx,x, y, f1,f2,q,13,1);
  graphicsStroke( cx );
}

void drawSharpSign( GraphicsContext cx, float x, float y, float dx )
{
  drawSharpSign0( cx, x-dx, y );
}

void drawFlatSign0( GraphicsContext cx, float x, float y )
{
  static float p[12][2]={  
    {-2,3},{6,6.5},{6,-1},{-2,-4.5},{4,0},{4,4},{-2,2},{-2,10},{-2,-4}};  

  float f1,f2;
  
  f2=8.0/9.0;
  f1=f2*0.9;
  moveTo(cx,x, y, f1,f2,p,0);
  curveTo(cx,x, y, f1,f2,p,1,2);
  graphicsFill( cx );
  moveTo(cx,x, y, f1,f2,p,7);
  addLineSegments(cx,x, y, f1,f2,p,8,1);
  graphicsStroke( cx );
}

void drawFlatSign( GraphicsContext cx, float x, float y, float dx )
{
  drawFlatSign0( cx, x-dx, y );
}

// Narrow flat sign
void cgftx( GraphicsContext cx, float x, float y )
{
  static float p[12][2]={  
    {-2,3},{6,6.5},{6,-1},{-2,-4.5},{4,0},{4,4},{-2,2},{-2,10},{-2,-4}};  

  float f1,f2;
  
  f2=8.0/9.0;
  f1=f2*0.8;
  moveTo(cx,x, y, f1,f2,p,0);
  curveTo(cx,x, y, f1,f2,p,1,2);
  graphicsFill( cx );
  moveTo(cx,x, y, f1,f2,p,7);
  addLineSegments(cx,x, y, f1,f2,p,8,1);
  graphicsStroke( cx );
}

// Double flat
void cgdft0( GraphicsContext cx, float x, float y )
{
  cgftx( cx, x-2.5f, y );
  cgftx( cx, x+2.5f, y );
}

void drawNaturalSign0( GraphicsContext cx, float x, float y )
{
  static float r[14][2]={  
    {-2.5,-6}, {2.5,-5}, {2.5,-2}, {-2.5,-3}, {-2.5,6},  
    {-2.5,2}, {2.5,3}, {2.5,6}, {-2.5,5}, {-2.5,2},
    {-2.5,11}, {-2.5,-5.5},  
    {2.5,5.5}, {2.5,-11} };

  float f1,f2;
  
  f2=6.5/9.0;
  f1=f2*0.9;
  moveTo(cx,x,y,f1,f2,r,0);
  addLineSegments(cx,x,y,f1,f2,r,1,4);
  moveTo(cx,x,y,f1,f2,r,5);
  addLineSegments(cx,x,y,f1,f2,r,6,4);
  graphicsFill( cx );
  moveTo(cx,x,y,f1,f2,r,10);
  addLineSegments(cx,x,y,f1,f2,r,11,1);
  graphicsStroke( cx );
  moveTo(cx,x,y,f1,f2,r,12);
  addLineSegments(cx,x,y,f1,f2,r,13,1);
  graphicsStroke( cx );
}

void drawNaturalSign( GraphicsContext cx, float x, float y, float dx )
{
  drawNaturalSign0( cx, x-dx, y );
}

void drawRest1( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x-3, y+6 );
  graphicsLineTo( cx, x-3, y+3 );
  graphicsLineTo( cx, x+3, y+3 );
  graphicsLineTo( cx, x+3, y+6 );
  graphicsClosePath( cx );
  graphicsFill( cx );
}

void drawRest2( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x-3, y );
  graphicsLineTo( cx, x-3, y+3 );
  graphicsLineTo( cx, x+3, y+3 );
  graphicsLineTo( cx, x+3, y );
  graphicsClosePath( cx );
  graphicsFill( cx );
}

void drawRest4( GraphicsContext cx, float x, float y )
{
  float p[14][2]={  
    {-1,17}, {15,4}, {-6,8}, {6.5,-5}, {-2,-2}, {-5,-11}, {1,-15},
    {-9,-11}, {-6,0}, {1,-1},   {-9,7}, {7,5}, {-1,17} };

  float f1,f2;

  f1=f2=6.0/11.5;
  moveTo(cx,x,y,f1,f2,p,0);
  curveTo(cx,x,y,f1,f2,p,1,4);
  graphicsFill( cx );
}

void drawRest8( GraphicsContext cx, float x, float y )
{
  float q[16][2]={  
    {8,14}, {5,9}, {3,5}, {-1.5,4},
    {4,11}, {-9,14}, {-9,7},
    {-9,4}, {-6,2}, {-3,2},
    {4,2}, {5,7}, {7,11},
    {-1.8,-20},  {-0.5,-20}, {8.5,14}};

  float f1,f2;

  f1=f2=7/18.0;
  moveTo(cx,x,y,f1,f2,q,0);
  curveTo(cx,x,y,f1,f2,q,1,4);
  addLineSegments(cx,x,y,f1,f2,q,13,3);
  graphicsFill( cx );
}

void drawRest16( GraphicsContext cx, float x, float y )
{
  float r[29][2]={  
    {8,14}, {5,9}, {3,5}, {-1.5,4},
    {4,11}, {-9,14}, {-9,7},
    {-9,4}, {-6,2}, {-3,2},
    {4,2}, {5,7}, {7,11},
    {8,14}, {5,9}, {3,5}, {-1.5,4},
    {4,11}, {-9,14}, {-9,7},
    {-9,4}, {-6,2}, {-3,2},
    {4,2}, {5,7}, {7.3,11},
    {-1.8,-21},  {-0.5,-21}, {8.5,14} };
  float f1,f2;
  int i;

  for (i=13;i<26;i++) { r[i][0]-=4.2; r[i][1]-=14; }
  f1=f2=7/18.0;
  moveTo(cx,x,y,f1,f2,r,0);
  curveTo(cx,x,y,f1,f2,r,1,4);
  addLineSegments(cx,x,y,f1,f2,r,13,1);
  curveTo(cx,x,y,f1,f2,r,14,4);
  addLineSegments(cx,x,y,f1,f2,r,26,3);
  graphicsFill( cx );
}

void drawRest32( GraphicsContext cx, float x, float y )
{
  /* get 32nd, 64th rest by overwriting 8th and 16th rests */
  drawRest16( cx, x, y );
  drawRest8( cx, x+1.6f, y+5.5f );
}

void drawRest64( GraphicsContext cx, float x, float y )
{
  drawRest16( cx, x+1.6f, y+5.5f );
  drawRest16( cx, x-1.5f, y-5.5f );
}


void drawBarLine( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x, y+24 );
  graphicsStroke( cx );
}

void cgdbar( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x, y+24 );
  graphicsMoveTo( cx, x-3, y );
  graphicsLineTo( cx, x-3, y+24 );
  graphicsStroke( cx );
}

void cgfbar1( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x, y+24 );
  graphicsLineTo( cx, x+3, y+24 );
  graphicsLineTo( cx, x+3, y );
  graphicsFill( cx );
  graphicsMoveTo( cx, x+6, y );
  graphicsLineTo( cx, x+6, y+24 );
  graphicsStroke( cx );
}

void cgfbar2( GraphicsContext cx, float x, float y )
{
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x, y+24 );
  graphicsLineTo( cx, x-3, y+24 );
  graphicsLineTo( cx, x-3, y );
  graphicsFill( cx );
  graphicsMoveTo( cx, x-6, y );
  graphicsLineTo( cx, x-6, y+24 );
  graphicsStroke( cx );
}

void drawRepeatDots( GraphicsContext cx, float x, float y )
{
  y += 9;
  graphicsMoveTo( cx, x, y );
  graphicsAddArc( cx, x, y, 1.2f, 0, 2*M_PI );
  y += 6;
  graphicsMoveTo( cx, x, y );
  graphicsAddArc( cx, x, y, 1.2f, 0, 2*M_PI );
  graphicsFill( cx );
}

void cgend1( GraphicsContext cx, float x1, float x2, int n )
{
  /* use dy=20 for tall boxes */
  int y=50,dy=6;

  graphicsMoveTo( cx, x2, y-dy );
  graphicsLineTo( cx, x2, y );
  graphicsLineTo( cx, x1, y );
  graphicsLineTo( cx, x1, y-dy );
  graphicsStroke( cx );
  char text[32];
  sprintf( text, "%d", n );
  graphicsSetFont( cx, kSansSerifFont, 12 );
  cgrshow( cx, x1, y-10, text );
}

void cgend2( GraphicsContext cx, float x1, float x2, int n )
{
  /* use dy=20 for tall boxes */
  int y=50,dy=6;

  //FIXME-not done this one yet
  graphicsMoveTo( cx, x2, y-dy );
  graphicsLineTo( cx, x2, y );
  graphicsLineTo( cx, x1, y );
  graphicsLineTo( cx, x1, y-dy );
  graphicsStroke( cx );
  char text[32];
  sprintf( text, "%d", n );
  graphicsSetFont( cx, kSansSerifFont, 12 );
  cgrshow( cx, x1, y-10, text );
}

void cggc( GraphicsContext cx, float x, float y, const char *text )
{
  graphicsSetFont( cx, kSansSerifFont, 14 );
  cgrshow( cx, x, y, text );
}

/* ----- xxxdef_sl ------ */
void cgsl( GraphicsContext cx,
  float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4,
  float x5, float y5, float x6, float y6, float x7, float y7, float x8, float y8
)
{
  graphicsNewPath( cx );
  graphicsMoveTo( cx, x8, y8 );
  graphicsCurveTo( cx, x5, y5, x6, y6, x7, y7 );
  graphicsLineTo( cx, x4+x7, y4+y7 );
  graphicsCurveTo( cx, x1, y1, x2, y2, x3, y3 );
  graphicsClosePath( cx );
  graphicsFill( cx );
}

void cghd( GraphicsContext cx, float x, float y )
{
  float p[7][2] = {
    {8.0, 0.0},  {8.0, 8.0},  {-8.0, 8.0},  {-8.0, 0.0},  {-8.0, -8.0},  
    {8.0, -8.0},  {8.0, 0.0} };

  float c,s,xx,yy,f1,f2;
  int i;
  
  c=0.825; s=0.565;

  for (i=0;i<7;i++) {
    xx = c*p[i][0] - s*p[i][1];
    yy = s*p[i][0] + c*p[i][1];
    p[i][0]=xx;
    p[i][1]=yy;
  }
  
  f1=f2=6.0/12.0;
  graphicsNewPath( cx );
  moveTo(cx, x, y, f1,f2,p,0);
  curveTo(cx, x, y, f1,f2,p,1,2);
  graphicsClosePath( cx );
  graphicsFill( cx );
}

void cgHd( GraphicsContext cx, float x, float y )
{
  float p[14][2] = {
    {8.0, 0.0},  {8.0, 8.5},  {-8.0, 8.5},  {-8.0, 0.0},  {-8.0, -8.5},  
    {8.0, -8.5},  {8.0, 0.0},  {7.0, 0.0},  {7.0, -4.0},  {-7.0, -4.0}, 
    {-7.0, 0.0},  {-7.0, 4.0},  {7.0, 4.0},  {7.0, 0.0} };

  float c,s,xx,yy,f1,f2;
  int i;

  c=0.878; s=0.479;

  for (i=0;i<14;i++) {
    xx = c*p[i][0] - s*p[i][1];
    yy = s*p[i][0] + c*p[i][1];
    p[i][0]=xx;
    p[i][1]=yy;
  }
  
  f1=f2=6.0/12.0;
  moveTo(cx,x, y, f1,f2,p,0);
  curveTo(cx,x, y, f1,f2,p,1,2);
  moveTo(cx,x, y, f1,f2,p,7);
  curveTo(cx,x, y, f1,f2,p,8,2);
  graphicsFill( cx );
}

void cgHD( GraphicsContext cx, float x, float y )
{
  float p[13][2] = {
    {11.0, 0.0}, {11.0, 2.0},  {6.0, 6.5},  {0.0, 6.5},  {-6.0, 6.5}, 
    {-11.0, 2.0},  {-11.0, 0.0},  {-11.0, -2.0},  {-6.0, -6.5}, 
    {0.0, -6.5},  {6.0, -6.5},  {11.0, -2.0},  {11.0, 0.0}  };

  float q[8][2] = {
    {11.0, 0.0},  {5.0, 0.0},  {5.0, -5.0},  {-5.0, -5.0},  {-5.0, 0.0},  
    {-5.0, 5.0},  {5.0, 5.0},  {5.0, 0.0}};
           
  float c,s,xx,yy,f1,f2;
  int i;

/*phi=2.5;
  c=cos(phi);
  s=sin(phi); */
  
  c=-0.801; s=0.598;

  for (i=1;i<8;i++) {
    xx = c*q[i][0] - s*q[i][1];
    yy = s*q[i][0] + c*q[i][1];
    q[i][0]=xx;
    q[i][1]=yy;
  }
  
  f1=f2=6.5/12.0;
  moveTo(cx,x, y, f1,f2,p,0);
  curveTo(cx,x, y, f1,f2,p,1,4);
  moveTo(cx,x, y, f1,f2,q,2);
  curveTo(cx,x, y, f1,f2,q,2,2);
  graphicsFill( cx );
}

void cgghl( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsSetLineWidth( cx, 0.7f );
  graphicsMoveTo( cx, x-3, y );
  graphicsLineTo( cx, x+3, y );
  graphicsStroke( cx );
  graphicsRestore( cx );
}

void cggnt( GraphicsContext cx, float x, float y, float l )
{
  float p[7][2] = {
    {0,10}, {16,10}, {16,-10}, {0,-10}, {-16,-10}, {-16,10}, {0,10} };

  float f1,f2;
  
  f1=f2=2./10.0;

  moveTo(cx, x, y, f1,f2,p,0);
  curveTo(cx, x, y, f1,f2,p,1,2);
  graphicsFill( cx );
  graphicsMoveTo( cx, x+GSTEM_XOFF, y );
  graphicsLineTo( cx, x+GSTEM_XOFF, y+l );
  graphicsStroke( cx );
}

void cggn1( GraphicsContext cx, float x, float y, float l )
{
  float p[7][2] = {
    {0,10}, {16,10}, {16,-10}, {0,-10}, {-16,-10}, {-16,10}, {0,10} };

  float f1,f2;
  
  f1=f2=2./10.0;

  moveTo(cx, x, y, f1,f2,p,0);
  curveTo(cx, x, y, f1,f2,p,1,2);
  graphicsFill( cx );
  x += GSTEM_XOFF;
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x, y+l );
  y += l;
  graphicsMoveTo( cx, x, y );
  graphicsCurveTo( cx, x+3, y-4, x+4, y-5, x+2, y-8 );

  graphicsMoveTo( cx, x-3, y-6 );
  graphicsLineTo( cx, x+4, y-2 );
  graphicsStroke( cx );
}

void cggsh0( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, 0.7f, 0.7f );
  drawSharpSign0( cx, 0, 0 );
  graphicsRestore( cx );
}

void cggft0( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, 0.7f, 0.7f );
  drawFlatSign0( cx, 0, 0 );
  graphicsRestore( cx );
}

void cggnt0( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, 0.7f, 0.7f );
  drawNaturalSign0( cx, 0, 0 );
  graphicsRestore( cx );
}

void cggdf0( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, 0.7f, 0.6f );
  cgdft0( cx, 0, 0 );
  graphicsRestore( cx );
}

//FIXME
void cggds0( GraphicsContext cx, float x, float y )
{
  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, 0.7f, 0.7f );
//  cgdsh0( cx, 0, 0 );
  graphicsRestore( cx );
}

void cggbm2( GraphicsContext cx, float x0, float y0, float x1, float y1 )
{
  graphicsSave( cx );
  graphicsSetLineWidth( cx, 1.4f );
  graphicsNewPath( cx );
  graphicsMoveTo( cx, x0, y0-0.5f );
  graphicsLineTo( cx, x1, y1-0.5f );
  graphicsMoveTo( cx, x0, y0-3.4f );
  graphicsLineTo( cx, x1, y1-3.4f );
  graphicsStroke( cx );
  graphicsRestore( cx );
}

void cggbm3( GraphicsContext cx, float x0, float y0, float x1, float y1 )
{
  graphicsSave( cx );
  graphicsSetLineWidth( cx, 1.2f );
  graphicsNewPath( cx );
  graphicsMoveTo( cx, x0, y0-0.3f );
  graphicsLineTo( cx, x1, y1-0.3f );
  graphicsMoveTo( cx, x0, y0-2.5f );
  graphicsLineTo( cx, x1, y1-2.5f );
  graphicsMoveTo( cx, x0, y0-4.7f );
  graphicsLineTo( cx, x1, y1-4.7f );
  graphicsStroke( cx );
  graphicsRestore( cx );
}

void cggsl( GraphicsContext cx, float x0, float y0, float x1, float y1, float x2, float y2, float x3, float y3 )
{
  graphicsMoveTo( cx, x0, y0 );
  graphicsCurveTo( cx, x1, y1, x2, y2, x3, y3 );
  graphicsStroke( cx );
}

void drawCTimeSig( GraphicsContext cx, float x )
{
  float y = 10;
  float p[25][2]={
  {0,26},  
  {4,26}, {11,23},  {11,14}, 
  {11,20},  {5,19}, {5,14}, 
  {5,9}, {12,9}, {12,15}, 
  {12,25}, {6,28},  {0,28}, 
  {-15,28}, {-25,17}, {-25,2}, 
  {-25,-10}, {-10,-28}, {11,-8}, 
  {-6,-20}, {-18,-11}, {-18,2}, 
  {-18,14}, {-14,26}, {0,26} };

  float f1,f2;
  
  f1 = f2 = 0.25;
  moveTo(cx,x,y,f1,f2,p,0);
  curveTo(cx,x,y,f1,f2,p,1,8);
  graphicsFill( cx );
}

void drawCTTimeSig( GraphicsContext cx, float x )
{
  float y = 4;
  drawCTimeSig( cx, x );
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x, y+16 );
  graphicsStroke( cx );
}

void drawTrebleClef( GraphicsContext cx, float x )
{
  float p[71][2]={
    {-6, 16},  {-8, 13},  {-14, 19},  {-10, 35},  {2, 35},  {8, 37},  
    {21, 30},  {21, 17},  {21, 5},  {10, -1},  {0, -1},  {-12, -1},  
    {-23, 5},  {-23, 22},  {-23, 29},  {-22, 37},  {-7, 49},  {10, 61},  
    {10, 68},  {10, 73},  {10, 78},  {9, 82},  {7, 82},  {2, 78},  
    {-2, 68},  {-2, 62},  {-2, 25},  {10, 18},  {11, -8},  {11, -18}, 
    {5, -23},  {-4, -23},  {-10, -23},  {-15, -18},  {-15, -13},  
    {-15, -8},  {-12, -4},  {-7, -4},  {3, -4},  {3, -20},  {-6, -17},
    {-5, -23},  {9, -20},  {9, -9},  {7, 24},  {-5, 30},  {-5, 67}, 
    {-5, 78},  {-2, 87},  {7, 91},  {13, 87},  {18, 80},  {17, 73},  
    {17, 62},  {10, 54},  {1, 45},  {-5, 38},  {-15, 33},  {-15, 19}, 
    {-15, 7},  {-8, 1},  {0, 1},  {8, 1},  {15, 6},  {15, 14},  {15, 23},
    {7, 26},  {2, 26},  {-5, 26},  {-9, 21},  {-6, 16} };

  float f1,f2;
  
  f1 = f2 = 24.0/65.0;
  moveTo(cx,x, 0, f1,f2,p,0);
  addLineSegments(cx,x, 0, f1,f2,p,1,1);
  curveTo(cx,x, 0, f1,f2,p,2,23);
  graphicsFill( cx );
}

void drawSmallTrebleClef( GraphicsContext cx, float x )
{
  graphicsSave( cx );
  graphicsScale( cx, 0.85f, 0.85f );
  drawTrebleClef( cx, x/0.85f );
  graphicsRestore( cx );
}

void drawBassClef( GraphicsContext cx, float x )
{
  float p[42][2]={
    {-2.3,3}, {6,7}, {10.5,12}, {10.5,16},
    {10.5,20.5}, {8.5,23.5}, {6.2,23.3},
    {5.2,23.5}, {2,23.5}, {0.5,19.5},
    {2,20}, {4,19.5}, {4,18},
    {4,17}, {3.5,16}, {2,16},
    {1,16}, {0,16.9}, {0,18.5},
    {0,21}, {2.1,24}, {6,24}, 
    {10,24}, {13.5,21.5}, {13.5,16.5},
    {13.5,11}, {7,5.5}, {-2.0,2.8},
    {14.9,21}, 
    {14.9,22.5}, {16.9,22.5}, {16.9,21},
    {16.9,19.5}, {14.9,19.5}, {14.9,21},
    {14.9,15},
    {14.9,16.5}, {16.9,16.5}, {16.9,15},
    {16.9,13.5}, {14.9,13.5}, {14.9,15} };
  
  int i;
  float f1,f2;

  for (i=0;i<42;i++) {p[i][0]-=7.5; p[i][1]-=0.5; }
  f1 = f2 = 1.0;
  moveTo(cx,x, 0, f1,f2,p,0);
  curveTo(cx,x, 0, f1,f2,p,1,9);
  curveTo(cx,x, 0, f1,f2,p,1,9);

  moveTo(cx,x, 0, f1,f2,p,28);
  curveTo(cx,x, 0, f1,f2,p,29,2);

  moveTo(cx,x, 0, f1,f2,p,25);
  curveTo(cx,x, 0, f1,f2,p,36,2);
  graphicsFill( cx );
}

void drawSmallBassClef( GraphicsContext cx, float x )
{
  graphicsSave( cx );
  graphicsScale( cx, 0.85f, 0.85f );
  graphicsTranslate( cx, 0, 4 );
  drawBassClef( cx, x/0.85f );
  graphicsRestore( cx );
}

void drawCClef( GraphicsContext cx, float x )
{
  float p[30][2]={
    {0,0}, {2,5.5}, 
    {9,4.5}, {12,10}, {12,15.5},
    {12,19.5}, {11,23.3}, {6.5,23.5},
    {5.2,23.5}, {2,23.5}, {0.5,19.5},
    {2,20}, {4,19.5}, {4,18},
    {4,17}, {3.5,16}, {2,16},
    {1,16}, {0,16.9}, {0,18.5},
    {0,21}, {2.1,24}, {6,24},
    {12,24}, {15,21.5}, {15,16.5},
    {15,10}, {10,4.5}, {4,5},
    {3,0} };
  int i;
  float f1,f2;

  for (i=0;i<30;i++) p[i][1]+=24;

  f1 = 0.6;
  f2 = 0.5;

  moveTo(cx,x, 0, f1,f2,p,0);
  addLineSegments(cx,x, 0, f1,f2,p,1,1);
  curveTo(cx,x, 0, f1,f2,p,2,9);
  addLineSegments(cx,x, 0, f1,f2,p,29,1);
  graphicsFill( cx );

  graphicsSave( cx );
  graphicsTranslate( cx, 0, 24 );
  graphicsScale( cx, 1, -1 );
  moveTo(cx,x, 0, f1,f2,p,0);
  addLineSegments(cx,x, 0, f1,f2,p,1,1);
  curveTo(cx,x, 0, f1,f2,p,2,9);
  addLineSegments(cx,x, 0, f1,f2,p,29,1);
  graphicsFill( cx );

  graphicsMoveTo( cx, x-6.5f, 0 );
  graphicsLineTo( cx, x-6.5f, 24 );
  graphicsLineTo( cx, x-3.5f, 24 );
  graphicsLineTo( cx, x-3.5f, 0 );
  graphicsFill( cx );

  graphicsRestore( cx );

  graphicsSetLineWidth( cx, 0.8f );
  graphicsMoveTo( cx, x-1.8f, 0 );
  graphicsLineTo( cx, x-1.8f, 24 );
  graphicsStroke( cx );
}

void drawSmallCClef( GraphicsContext cx, float x )
{
  drawCClef( cx, x );
}

void drawBrace( GraphicsContext cx, float scale, float x, float y )
{
  float p[8][2]={
    {7.2,60}, {-7,39}, {17,17}, {-1,0}, 
    {-1.4,0}, {13,13}, {-11,39}, {7,60} };

  float f1,f2;

  f1 = 0.9;
  f2 = 1.0;

  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, scale, scale );
  moveTo(cx,0, 0, f1,f2,p,0);
  curveTo(cx,0, 0, f1,f2,p,1,1);
  addLineSegments(cx,0, 0, f1,f2,p,4,1);
  curveTo(cx,0, 0, f1,f2,p,5,1);
  graphicsFill( cx );
  graphicsRestore( cx );

  graphicsSave( cx );
  graphicsTranslate( cx, x, y );
  graphicsScale( cx, scale, -scale );
  moveTo(cx,0, 0, f1,f2,p,0);
  curveTo(cx,0, 0, f1,f2,p,1,1);
  addLineSegments(cx,0, 0, f1,f2,p,4,1);
  curveTo(cx,0, 0, f1,f2,p,5,1);
  graphicsFill( cx );
  graphicsRestore( cx );
}

void drawBracket( GraphicsContext cx, float h, float x, float y )
{
  float q[8][2]={
    {-3,0}, {2,0}, {4,1}, {5.5,5}, 
    {5.9,4.7}, {4.7,1.2}, {3.2,-.4}, {-1,-1.2} };

  float f1,f2;

  f1 = 1.0;
  f2 = 1.0;

  moveTo(cx, x, y+h, f1,f2,q,0);
  curveTo(cx, x, y+h, f1,f2,q,1,1);
  addLineSegments(cx, x, y+h, f1,f2,q,4,1);
  curveTo(cx, x, y+h, f1,f2,q,5,1);
  graphicsFill( cx );

  graphicsSave( cx );
  graphicsScale( cx, 1, -1 );
  moveTo(cx, x, y+h, f1,f2,q,0);
  curveTo(cx, x, y+h, f1,f2,q,1,1);
  addLineSegments(cx, x, y+h, f1,f2,q,4,1);
  curveTo(cx, x, y+h, f1,f2,q,5,1);
  graphicsFill( cx );
  graphicsRestore( cx );

  graphicsSetLineWidth( cx, 0.8f );
  graphicsMoveTo( cx, x, y );
  graphicsLineTo( cx, x-3, y );
  graphicsLineTo( cx, x-3, y+h );
  graphicsLineTo( cx, x, y+h );
  graphicsClosePath( cx );
  graphicsFill( cx );
}

void drawStaff( GraphicsContext cx, float x, float y, float l )
{
	int i;
  graphicsSave( cx );
  graphicsSetLineWidth( cx, 0.5f );
  for ( i = 0; i < 5; i++ ) {
    graphicsMoveTo( cx, x, y+i*6 );
    graphicsLineTo( cx, x+l, y+i*6 );
	}
  graphicsStroke( cx );
  graphicsRestore( cx );
}

void drawSeparator( GraphicsContext cx, float x1, float x2 )
{
  graphicsMoveTo( cx, x1, 0 );
  graphicsLineTo( cx, x2, 0 );
  graphicsStroke( cx );
}

#endif
