/* 
 *  The Rules to Life, as explained to me by Duane Morin
 *   If a Dead cell has 3 neighbors, it becomes alive. Otherwise, it stays
 *      dead.
 *   If a alive cell has 2 or 3 neighbors, it stays alive.
 */

#ifdef X
  #include <X11/X.h>
  #include <X11/Xlib.h>
#else
  #ifdef DJGPP
    #include <grx.h>
  #else
//  #include <metawndo.h>
//  #include "fakex.h"
  #endif
#endif

#include <stdlib.h>
#include <stdio.h>
#include "trippy.h"
#include <windowsx.h>
#include "color.h"

static char FAR * neighbors; /* 0 to 8 , plus an extra bit to tell status*/
static short FAR * age;      /* 0 to numcolors */

#define ON 0x10
static void findNeighbors(int,int,int);
static void kAA(int,int,HDC);

extern foo options;
extern HPALETTE hPal;
static int initd=0;

void
getALife(int winno)
{
  int i,x,y;

  XClearWindow(display,window[winno]);
  if(!initd)
  {
#ifdef X    
    age=(short **)calloc(options.windows,sizeof(short *));
    neighbors=(char **)calloc(options.windows,sizeof(char *));
#else
  age=(short FAR *)GlobalAllocPtr(GPTR,(sizeof(short FAR)*128*128));
  neighbors=(char FAR *)GlobalAllocPtr(GPTR,(sizeof(char FAR)*128*128));
#endif
    initd=1;
  }

  if(neighbors==NULL)
  {
    MessageBox(window[winno],"Barf","Barfo on Memory",MB_OK);
    exit(1);
  }
    for(y=0;y<128;y++)
    {
     for(x=0;x<128;x++)
     {
        if(rndm(100)<options.number)
        {
         int here = y*128+x;
          neighbors[here]=ON;
          XDrawPoint(display,window[winno],
                     color_gcs[age[here]=1], x,y);
      }
    }
  }
}

void
exitLife()
{
  GlobalFreePtr(neighbors);
  GlobalFreePtr(age);
  initd=0;
}

void
dropACell(int winno, int x,int y)
{
  neighbors[y*128+x]^=ON; /* flip it on */
}

void
drawLife(int winno)
{
  int x,y;
  HDC hdc=GetDC(window[winno]);
  HDC hdcMem= CreateCompatibleDC(hdc);
  HBITMAP hBit = CreateCompatibleBitmap(hdc,128,128);
  SelectObject(hdcMem,hBit);

  for(y=0;y<128+2;y++)
  {
    for(x=0;x<128;x++)
    {
      if(y<128)
      {
        if(neighbors[y*128+x]&ON)
        {
          findNeighbors(x,y,winno);
        }
      }
/*      findNeighbors((x+100)%(128),y); */
      if(y-2>=0)      kAA(x,y-2,hdcMem);
/*      if((x+98)%(128)>0) kAA((x+98)%(128),y); */
    }
  }
  BitBlt(hdc,0,0,128,128,hdcMem,0,0,SRCCOPY);
  DeleteDC(hdcMem);
  DeleteObject(hBit);
  ReleaseDC(window[winno],hdc);
}

void
findNeighbors(int x,int y, int winno)
{
  int foo,bar;
  
  for(bar=y-1;bar<=y+1;bar++)
    for(foo=x-1;foo<=x+1;foo++)
    {
      if( (foo<0) || (bar<0) || (foo>=128) || (bar>=128) ||
          (foo==x&&bar==y)) 
        continue;
      else
      {
        neighbors[bar*128+foo]++; /* tell everyone around you
                                           that they have a neighbor*/
      }     
    }
}

void
kAA(int x, int y, HDC hdc) /* it's alive... it's dead... */
{ 
  int nov;
  int here = y*128+x;
  if(((nov=neighbors[here]&0x000f)==3)||
     ((nov==2)&&(neighbors[here]&ON)))
  {
    neighbors[here]=ON;
    if(++age[here]>=numcolors)
      age[here]=1;

  }
  else
  {
    if(neighbors[here]==0) return; /* already dead,
                                               don't bother */
    age[here]=0;
    neighbors[here]=0;
  }
 /* XDrawPoint(display,window[winno],color_gcs[age[y*128+x]],x,y); */
 SelectPalette(hdc,hPal,TRUE);
  SetPixel(hdc,x,y,PALETTEINDEX(age[here]));
}
