#ifdef X
#include <X11/X.h>
#include <X11/Xlib.h>
#else
//#include <metawndo.h>
#include <stdlib.h>
//#include "fakex.h"
#endif

#include <math.h>
#include <stdio.h>
#include "trippy.h"
#include "color.h"
#include "frame.h"

extern XPoint PolartoRect(float radius, float angle);
extern int isqrt(int);
extern int ihypot(int,int);

extern foo options;

struct pt
{
  int x, y;
  int dx,dy;
  int pixel;
  struct pt *next, *prev;
};

typedef struct pt PT;

struct PTList
{
  int size;
  PT *next, *prev;
};
typedef struct PTList ptList;

ptList *head1,*head2,*head3,*head4;

extern int HCV;

static int inited=0;

void add(ptList *here,int init,int winno)
{
  PT *point;

  point=(PT *)malloc(sizeof(PT));

  if(init)
  {
    point->x=rndm(CX);
    point->y=rndm(CY);
    point->dx=1;
    point->dy=1;
    point->pixel=rndm(numcolors);
  }
  else
  {
    int radius;

    if(head2[winno].next!=NULL &&
       head1[winno].next!=NULL)
    {
      radius= ihypot(head2[winno].next->x-head1[winno].next->x,
                        head2[winno].next->y-head1[winno].next->y);
    }
    else
    { radius = 400;  }
    point->x=here->next->x+here->next->dx;
    point->y=here->next->y+here->next->dy;
    point->dx=here->next->dx;
    point->dy=here->next->dy;
    point->pixel=(here->next->pixel+HCV)%numcolors;
    if (!rndm((long)(1000)))
      point->pixel=rndm(numcolors);
    if((point->x<0)|| ((options.mode==circ)&&(point->x<radius)))
    {
      point->dx=rndm(7);
      point->x+=point->dx;
    }
    else if((point->x>CX)||
            ((options.mode==circ)&&(CX-point->x<radius)))
    {
      point->dx= -rndm(7);
      point->x+=point->dx;
    }
    if((point->y<0)|| ((options.mode==circ)&&(point->y<radius)))
    {
      point->dy=rndm(7);
      point->y+=point->dy;
    }
    else if((point->y>CY)||
            ((options.mode==circ)&&(CY-point->y<radius)))
    {
      point->dy= -rndm(7);
      point->y+=point->dy;
    }
  }

  if(here->prev==NULL)
    here->prev=point;
  if(here->next==NULL)
    here->next=point;
  else
  {
    here->next->prev=point;
    point->next=here->next;
    point->prev=here->prev;
    here->next=point;
  }
  here->size++;
}

void delete1(ptList *here)
{
  PT *temp=here->prev->prev;
  here->next->prev=temp;
  temp->next=here->next;

  free(here->prev);
  here->prev=temp;

  here->size--;
}

void
init_boxes(int winno)
{
#ifdef X
  int numwindows=options.windows;
#else
  int numwindows=1;
#endif

  /* make the first level */
  if(!inited)
  {
    /* 4 lists for each window, one for each point */
    head1=(ptList *)calloc(numwindows,sizeof(ptList));
    head2=(ptList *)calloc(numwindows,sizeof(ptList));
    if(options.mode==bozo||options.mode==bez)
    {
      head3=(ptList *)calloc(numwindows,sizeof(ptList));
      head4=(ptList *)calloc(numwindows,sizeof(ptList));
    }

    /* and now the second one */

    /* init the 4 points */
    head1[winno].prev=NULL;
    head1[winno].next=NULL;
    head1[winno].size=0;
    head2[winno].prev=NULL;
    head2[winno].next=NULL;
    head2[winno].size=0;
    if(options.mode==bozo||options.mode==bez)
    {
      head3[winno].prev=NULL;
      head3[winno].next=NULL;
      head3[winno].size=0;
      head4[winno].prev=NULL;
      head4[winno].next=NULL;
      head4[winno].size=0;
    }
    add(&head1[winno],1,winno);
    add(&head2[winno],1,winno);
    if(options.mode==bozo||options.mode==bez)
    {
      add(&head3[winno],1,winno);
      add(&head4[winno],1,winno);
    }

    inited=1;
  }


  if(options.multi)
    HCV=1;
  else
    HCV=0;
}

void
exit_boxes(int winno)
{
  if (inited)
  {
    int i;
    for(i=0;i<head1[winno].size;)
    {
      delete1(&head1[winno]);
    }
    free(head1);
    for(i=0;i<head2[winno].size;)
    {
      delete1(&head2[winno]);
    }
    free(head2);
    if(options.mode==bozo||options.mode==bez)
    {
      for(i=0;i<head3[winno].size;)
      {
        delete1(&head3[winno]);
      }
      free(head3);
      for(i=0;i<head4[winno].size;)
      {
        delete1(&head4[winno]);
      }
      free(head4);
    }
    inited=0;
  }
}

void
move_boxes(int winno)
{
  if(head1[winno].size>=options.number)
    delete1(&head1[winno]);
  if(head2[winno].size>=options.number)
    delete1(&head2[winno]);
  if(options.mode==bozo||options.mode==bez)
  {
    if(head3[winno].size>=options.number)
      delete1(&head3[winno]);
    if(head4[winno].size>=options.number)
      delete1(&head4[winno]);
  }

  if (options.mode==circ)
  {
    int radius = ihypot(head2[winno].next->x-head1[winno].next->x,
                        head2[winno].next->y-head1[winno].next->y);
    if(radius>40)
    {
      if(rndm(1))
        head2[winno].next->x=head1[winno].next->x-40;
      else
        head2[winno].next->y=head1[winno].next->y-40;
    }
  }
}

void
bounce(int winno)
{
  /*#*#* Bouncing Code *#*#*/
  add(&head1[winno],0,winno);
  add(&head2[winno],0,winno);
  if(options.mode==bozo||options.mode==bez)
  {
    add(&head3[winno],0,winno);
    add(&head4[winno],0,winno);
  }
}

void draw_qix(int winno)
{
  XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
            head1[winno].next->x,head1[winno].next->y,
            head2[winno].next->x,head2[winno].next->y);
  XDrawLine(display,window[winno],color_gcs[options.mono],
            head1[winno].prev->x,head1[winno].prev->y,
            head2[winno].prev->x,head2[winno].prev->y);
}

void draw_qix4(int winno)
{
  XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
            head1[winno].next->x,head1[winno].next->y,
            head2[winno].next->x,head2[winno].next->y);
  XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
            CX-head1[winno].next->x,head1[winno].next->y,
            CX-head2[winno].next->x,head2[winno].next->y);
  XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
            head1[winno].next->x,CY-head1[winno].next->y,
            head2[winno].next->x,CY-head2[winno].next->y);
  XDrawLine(display,window[winno],color_gcs[head1[winno].next->pixel],
            CX-head1[winno].next->x,CY-head1[winno].next->y,
            CX-head2[winno].next->x,CY-head2[winno].next->y);

  XDrawLine(display,window[winno],color_gcs[options.mono],
            head1[winno].prev->x,head1[winno].prev->y,
            head2[winno].prev->x,head2[winno].prev->y);
  XDrawLine(display,window[winno],color_gcs[options.mono],
            CX-head1[winno].prev->x,head1[winno].prev->y,
            CX-head2[winno].prev->x,head2[winno].prev->y);
  XDrawLine(display,window[winno],color_gcs[options.mono],
            head1[winno].prev->x,CY-head1[winno].prev->y,
            head2[winno].prev->x,CY-head2[winno].prev->y);
  XDrawLine(display,window[winno],color_gcs[options.mono],
            CX-head1[winno].prev->x,CY-head1[winno].prev->y,
            CX-head2[winno].prev->x,CY-head2[winno].prev->y);
}

void draw_bozo(int winno)
{
  /* draw the bozogon (actually just a quadrilateral,
   ** but that's not as fun a name as 'bozogon'
   */

  XDrawLines(display,window[winno],color_gcs[head1[winno].next->pixel],
             make_bozo(head1[winno].next->x,head1[winno].next->y,
                       head2[winno].next->x,head2[winno].next->y,
                       head3[winno].next->x,head3[winno].next->y,
                       head4[winno].next->x,head4[winno].next->y),
             5,CoordModeOrigin);
  /* and erase the last one */
  XDrawLines(display,window[winno],color_gcs[options.mono],
             make_bozo(head1[winno].prev->x,head1[winno].prev->y,
                       head2[winno].prev->x,head2[winno].prev->y,
                       head3[winno].prev->x,head3[winno].prev->y,
                       head4[winno].prev->x,head4[winno].prev->y),
             5,CoordModeOrigin);
}

void draw_bez(int winno)
{
  /* draw the Bezier curves
   */
  /* and erase the last one */
  XDrawBez(display,window[winno],color_gcs[options.mono],
             make_bozo(head1[winno].prev->x,head1[winno].prev->y,
                       head2[winno].prev->x,head2[winno].prev->y,
                       head3[winno].prev->x,head3[winno].prev->y,
                       head4[winno].prev->x,head4[winno].prev->y),
             4,CoordModeOrigin);

  XDrawBez(display,window[winno],color_gcs[head1[winno].next->pixel],
             make_bozo(head1[winno].next->x,head1[winno].next->y,
                       head2[winno].next->x,head2[winno].next->y,
                       head3[winno].next->x,head3[winno].next->y,
                       head4[winno].next->x,head4[winno].next->y),
             4,CoordModeOrigin);
}

void draw_circ(int winno)
{
  /* ok, not a circle, a 32-gon... close 'nuff */
  XDrawLines(display,window[winno],color_gcs[head1[winno].next->pixel],
             make_circle(head1[winno].next->x,head1[winno].next->y,
                         head2[winno].next->x,head2[winno].next->y),
             33,CoordModeOrigin);
  /* and erase the last one */
  XDrawLines(display,window[winno],color_gcs[options.mono],
             make_circle(head1[winno].prev->x,head1[winno].prev->y,
                         head2[winno].prev->x,head2[winno].prev->y),
             33,CoordModeOrigin);
}

void draw_boxes(int winno)
{
  /* draw the rectangles */

  XDrawRectangle(display,window[winno],color_gcs[head1[winno].next->pixel],
                 head1[winno].next->x,head1[winno].next->y,
                 head2[winno].next->x-head1[winno].next->x,
                 head2[winno].next->y-head1[winno].next->y );

  /* and erase the last one */
  XDrawRectangle(display,window[winno],color_gcs[options.mono],
                 head1[winno].prev->x,head1[winno].prev->y,
                 head2[winno].prev->x-head1[winno].prev->x,
                 head2[winno].prev->y-head1[winno].prev->y );
}

void draw_rose(int n)
{
  XPoint plotme,plotme2;
  float r,plusang;
  static float ang=0.0;
  static int clr=1;
  static int inited=0;
  int i,size;
  static int halfCX,halfCY;
  static int *X1,*Y1,*HC;

  if(!inited)
  {
    X1=(int *)calloc(options.number,sizeof(int));
    Y1=(int *)calloc(options.number,sizeof(int));
    HC=(int *)calloc(options.number,sizeof(int));
    HC[0]=rndm(numcolors);
    halfCX=CX>>1;
    halfCY=CY>>1;
    inited=1;
  }

/* 
  HC=rndm(numcolors);
*/
  size=min(CY,CX);

/*  plusang=(float)(M_PI/(n>>1)); */
  plusang=.01;

  r = sin(n*ang)*(size>>1);
/*      s = sin(m*ang)*size;*/
  plotme = PolartoRect(r,ang);
/*
      plotme2 = PolartoRect(s,ang);
      plotme.x+=plotme2.x;
      plotme.y+=plotme2.y;
*/
  ang=ang+plusang;

  if(ang>2*M_PI)
    ang-=2*M_PI;
  if(ang<0)
    ang+=2*M_PI;

  if(options.multi)
    clr=1;
  else
    clr=0;
  HC[0]=(HC[0]+clr)%numcolors;
  X1[0]=plotme.x;
  Y1[0]=plotme.y;

/*  XDrawPoint(display,window,color_gcs[HC[0]],plotme.x+halfCX,plotme.y+halfCY);*/
  XDrawLine(display,window[0],color_gcs[HC[0]],X1[0]+halfCX,Y1[0]+halfCY,
            X1[1]+halfCX,Y1[1]+halfCY);

  for(i=options.number-1;i>0;i--)
  {
    X1[i]=X1[i-1];
    Y1[i]=Y1[i-1];
    HC[i]=HC[i-1];
  }

/*
  XDrawPoint(display,window,color_gcs[0],X1[options.number-1]+(CX/2),
             Y1[options.number-1]+(CY/2)); 
*/
  XDrawLine(display,window[0],color_gcs[0],X1[options.number-1]+halfCX,
            Y1[options.number-1]+halfCY,
            X1[options.number-2]+halfCX,Y1[options.number-2]+halfCY);
}


