/*-
# X-BASED BARREL(tm)
#
#  BarrelP.h
#
###
#
#  Copyright (c) 1994 - 2005	David Albert Bagley, bagleyd@tux.org
#
#                   All Rights Reserved
#
#  Permission to use, copy, modify, and distribute this software and
#  its documentation for any purpose and without fee is hereby granted,
#  provided that the above copyright notice appear in all copies and
#  that both that copyright notice and this permission notice appear in
#  supporting documentation, and that the name of the author not be
#  used in advertising or publicity pertaining to distribution of the
#  software without specific, written prior permission.
#
#  This program is distributed in the hope that it will be "playable",
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
*/

/* Private header file for Barrel */

#ifndef _BarrelP_h
#define _BarrelP_h

#ifdef WINVER
#define STRICT

#include <windows.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Barrel.h"

#ifndef BUMPSOUND
#define BUMPSOUND "c:/windows/bump.wav"
#endif
#ifndef MOVESOUND
#define MOVESOUND "c:/windows/move.wav"
#endif

#if ((WINVER > 0x030a) && !defined(GCL_HBRBACKGROUND))
#undef WINVER
#define WINVER 0x030a
#endif
#if (WINVER <= 0x030a)		/* if WINDOWS 3.1 or less */
#define POS int
#define SETBACK(h,b) (void)SetClassWord(h,GCW_HBRBACKGROUND,(WORD)b);
#define MoveTO(h,x,y,lp) MoveTo(h,x,y);
#else
#define POS long
#define SETBACK(h,b) (void)SetClassLong(h,GCL_HBRBACKGROUND,(LONG)b);
#define MoveTO(h,x,y,lp) MoveToEx(h,x,y,lp);
#endif
#ifndef Point
#define Point POINT
#endif
#ifndef Boolean
#define Boolean BOOL
#endif
#ifndef True
#define True TRUE
#endif
#ifndef False
#define False FALSE
#endif
#define GC COLORREF  /* Equate apples to oranges */
#define Pixmap HBITMAP

#define DC(w,dr) ((dr==0)?w->core.hDC:w->barrel.memDC)
#define RECTANGLE(w,x,y,l,h) (void)Rectangle(w,x,y,x+l,y+h)
#define DRAWRECTANGLE(w,dr,c,x,y,l,h) \
  if (dr) w->barrel.hOldBitmap = (HBITMAP) SelectObject(w->barrel.memDC,dr); \
  w->barrel.hPen = CreatePen(PS_SOLID,1,c); \
  w->barrel.hOldPen = (HPEN) SelectObject(DC(w,dr),w->barrel.hPen); \
  RECTANGLE(DC(w,dr),x,y,l,h); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldPen); \
  (void) DeleteObject(w->barrel.hPen); \
  if (dr) (void) SelectObject(w->barrel.memDC,w->barrel.hOldBitmap)
#define FILLRECTANGLE(w,dr,c,x,y,l,h) \
  if (dr) w->barrel.hOldBitmap = (HBITMAP) SelectObject(w->barrel.memDC,dr); \
  w->barrel.hPen = CreatePen(PS_SOLID,1,c); \
  w->barrel.hOldPen = (HPEN) SelectObject(DC(w,dr),w->barrel.hPen); \
  w->barrel.hBrush = CreateSolidBrush(c); \
  w->barrel.hOldBrush = (HBRUSH) SelectObject(DC(w,dr),w->barrel.hBrush); \
  RECTANGLE(DC(w,dr),x,y,l,h); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldBrush); \
  (void) DeleteObject(w->barrel.hBrush); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldPen); \
  (void) DeleteObject(w->barrel.hPen); \
  if (dr) (void) SelectObject(w->barrel.memDC,w->barrel.hOldBitmap)
#define CIRCLE(w,r,x,y) if(r>0) \
 (void)Ellipse(w,x-r+1,y-r+1,x+r,y+r)
#define DRAWCIRCLE(w,dr,c,d,x,y) \
  if (dr) w->barrel.hOldBitmap = (HBITMAP) SelectObject(w->barrel.memDC,dr); \
  w->barrel.hPen = CreatePen(PS_SOLID,1,c); \
  w->barrel.hOldPen = (HPEN) SelectObject(DC(w,dr),w->barrel.hPen); \
  w->barrel.hBrush = CreateSolidBrush(c); \
  w->barrel.hOldBrush = (HBRUSH) SelectObject(DC(w,dr),w->barrel.hBrush); \
  CIRCLE(DC(w,dr),((d+2)>>1),(x)+(d)%2,(y)+(d)%2); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldBrush); \
  (void) DeleteObject(w->barrel.hBrush); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldPen); \
  (void) DeleteObject(w->barrel.hPen); \
  if (dr) (void) SelectObject(w->barrel.memDC,w->barrel.hOldBitmap)
#define FILLCIRCLE(w,dr,c,d,x,y) \
  w->barrel.hOldBitmap = (HBITMAP) SelectObject(w->barrel.memDC,dr); \
  w->barrel.hPen = CreatePen(PS_SOLID,1,c); \
  w->barrel.hOldPen = (HPEN) SelectObject(DC(w,dr),w->barrel.hPen); \
  w->barrel.hBrush = CreateSolidBrush(c); \
  w->barrel.hOldBrush = (HBRUSH) SelectObject(DC(w,dr),w->barrel.hBrush); \
  CIRCLE(DC(w,dr),((d+2)>>1),(x)+(d)%2,(y)+(d)%2); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldBrush); \
  (void) DeleteObject(w->barrel.hBrush); \
  (void) SelectObject(DC(w,dr),w->barrel.hOldPen); \
  (void) DeleteObject(w->barrel.hPen); \
  if (dr) (void) SelectObject(w->barrel.memDC,w->barrel.hOldBitmap)
#define DRAWTEXT(w,dr,c,x,y,s,l) \
  if (dr) w->barrel.hOldBitmap = (HBITMAP) SelectObject(w->barrel.memDC,dr); \
  (void) SetTextColor(DC(w,dr), c); \
  (void) SetBkMode(DC(w,dr), TRANSPARENT); \
  (void) TextOut(DC(w,dr), (x)-3, (y)-11, (LPCSTR) s, l); \
  if (dr) (void) SelectObject(w->barrel.memDC,w->barrel.hOldBitmap)

#if 0
#define DISPLAY_WARNING(s) (void) fprintf(stderr, s)
#else
#define DISPLAY_WARNING(s) (void) MessageBox(w->core.hWnd, (LPCSTR) s, \
  "Warning", MB_OK)
#endif
#define DISPLAY_ERROR(s) (void) fprintf(stderr, "%s\n", s); exit(1)

typedef struct _CorePart {
	HWND        hWnd;
	HDC         hDC;
	HINSTANCE   hInstance;
	POS         width, height;
} CorePart;

extern void DestroyBarrel(HBRUSH brush);
extern void ResizeBarrel(BarrelWidget w);
extern void SizeBarrel(BarrelWidget w);
extern void InitializeBarrel(BarrelWidget w, HBRUSH brush);
extern void ExposeBarrel(const BarrelWidget w);
extern void HideBarrel(const BarrelWidget w);
extern void SelectBarrel(BarrelWidget w,
	const int x, const int y, const int shift);
extern void MotionBarrel(BarrelWidget w,
	const int x, const int y, const int shift);
extern void ReleaseBarrel(BarrelWidget w,
	const int x, const int y, const int shift);
extern void PracticeBarrel(BarrelWidget w);
extern void PracticeBarrelMaybe(BarrelWidget w);
extern void PracticeBarrel2(BarrelWidget w);
extern void RandomizeBarrel(BarrelWidget w);
extern void RandomizeBarrelMaybe(BarrelWidget w);
extern void RandomizeBarrel2(BarrelWidget w);
extern void ClearBarrel(BarrelWidget w);
extern void GetBarrel(BarrelWidget w);
extern void WriteBarrel(BarrelWidget w);
extern void UndoBarrel(BarrelWidget w);
extern void SolveBarrel(BarrelWidget w);
extern void OrientizeBarrel(BarrelWidget w);
extern void PairsBarrel(BarrelWidget w);
extern void SpeedBarrel(BarrelWidget w);
extern void SlowBarrel(BarrelWidget w);
extern void SoundBarrel(BarrelWidget w);
extern void EnterBarrel(BarrelWidget w);
extern void LeaveBarrel(BarrelWidget w);
extern void MoveBarrelInput(BarrelWidget w, int x, int direction, int shift);
extern int  MoveBarrelDir(BarrelWidget w, const int direction);

#else

#include <stdlib.h>
#include <stdio.h>
#ifdef VMS
#include <unixlib.h>
#else
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#endif
#include <X11/IntrinsicP.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/CoreP.h>
#include <X11/Xos.h>
#include "Barrel.h"

#ifdef VMS
#ifndef BUMPSOUND
#define BUMPSOUND "[.]bump.wav"
#endif
#ifndef MOVESOUND
#define MOVESOUND "[.]move.wav"
#endif
#else
#ifndef BUMPSOUND
#if 0
#define BUMPSOUND "/usr/share/games/xbarrel/bump.au"
#endif
#define BUMPSOUND "/usr/local/share/games/xbarrel/bump.au"
#endif
#ifndef MOVESOUND
#if 0
#define MOVESOUND "/usr/share/games/xbarrel/move.au"
#endif
#define MOVESOUND "/usr/local/share/games/xbarrel/move.au"
#endif
#endif

#ifndef Pos
#define Pos Position
#endif
#ifndef Point
#define Point XPoint
#endif
#define NUM_DEGREES 360
#define MULT 64
#define FULLCIRCLE (NUM_DEGREES*MULT)
#define DR(w,dr) ((dr==0)?XtWindow(w):dr)
#define DRAWRECTANGLE(w,dr,c,i,j,l,h) XDrawRectangle(XtDisplay(w),DR(w,dr),\
  c,i,j,l,h)
#define FILLRECTANGLE(w,dr,c,i,j,l,h) XFillRectangle(XtDisplay(w),DR(w,dr),\
  c,i,j,l,h)
#define DRAWCIRCLE(w,dr,c,d,x,y) if(d>0) XDrawArc(XtDisplay(w),DR(w,dr),\
        c,x-((d)>>1),y-((d)>>1),d,d,0,FULLCIRCLE)
#define FILLCIRCLE(w,dr,c,d,x,y) if(d>0) XFillArc(XtDisplay(w),DR(w,dr),\
        c,x-((d)>>1),y-((d)>>1),d,d,0,FULLCIRCLE)
#define DRAWTEXT(w,dr,c,x,y,s,l) (void) XDrawString(XtDisplay(w),DR(w,dr),\
  c,x,y,s,l)

#define DISPLAY_WARNING(s) XtWarning(s)
#define DISPLAY_ERROR(s) XtError(s)

/* This gets around C's inability to do inheritance */
typedef struct _BarrelClassPart {
	int         ignore;
} BarrelClassPart;

typedef struct _BarrelClassRec {
	CoreClassPart core_class;
	BarrelClassPart barrel_class;
} BarrelClassRec;

extern BarrelClassRec barrelClassRec;
#endif

#define SYMBOL ':'

#define TOP 0
#define RIGHT 1
#define BOTTOM 2
#define LEFT 3
#define COORD 4
#define MAXCOLORS (MAXFACES+1)
#define NUMPLUNGERS 3

#define MAXSLICES 10

#define NORMAL 1
#define DOUBLE 2
#define INSTANT 3

#define ABS(a) (((a)<0)?(-(a)):(a))
#define SIGN(a) (((a)<0)?(-1):1)
#define MIN(a,b) (((int)(a)<(int)(b))?(int)(a):(int)(b))
#define MAX(a,b) (((int)(a)>(int)(b))?(int)(a):(int)(b))

/*** random number generator ***/
#if HAVE_RAND48
#define SRAND srand48
#define LRAND lrand48
#else /* HAVE_RAND48 */
#if HAVE_RANDOM
#define SRAND srandom
#define LRAND random
#else /* HAVE_RANDOM */
#if HAVE_RAND
#define SRAND srand
#define LRAND rand
#endif /* HAVE_RAND */
#endif /* HAVE_RANDOM */
#endif /* HAVE_RAND48 */
#ifndef SRAND
extern void SetRNG(long s);
#define SRAND(X) SetRNG((long) X)
#endif
#ifndef LRAND
extern long LongRNG(void);
#define LRAND() LongRNG()
#endif
#define NRAND(X) ((int)(LRAND()%(X)))

typedef struct _BarrelPart {
	int        *tileOfPosition, spacePosition[NUMPLUNGERS];
	int         currentTile, currentFace, currentRef;
	Boolean     started, cheat, sound, motion;
	Boolean     practice, orient, mono, reverse, pairs, focus;
	int         delay, numSlices, motionDiff, shiftDiff;
	int         base;
	int         tiles, faces, tileFaces;
	Point       offset, tileSize, faceSize, puzzleSize;
	Point       delta, puzzleOffset, digitOffset;
	GC          frameGC, borderGC, inverseGC;
	GC          tileGC, tileBrighterGC, tileDarkerGC;
	GC          faceGC[MAXCOLORS];
	Pixmap      bufferTiles[2];
#ifdef WINVER
	long        oldTime;
	char        username[81], bumpSound[81], moveSound[81], picture[81];
	HDC         memDC;
	HPEN        hOldPen, hPen;
	HBRUSH      hOldBrush, hBrush;
	HBITMAP     hOldBitmap;
	char        faceChar[MAXCOLORS];
#else
	struct timeval oldTime;
	int         menu, graphicsFormat;
	char       *username, *bumpSound, *moveSound, *picture, *font;
	Boolean     install;
	Colormap    colormap, oldColormap;
	XImage     *image;
	XFontStruct *fontInfo;
	char       *faceName[MAXCOLORS];
	Pixel       foreground, background;
	Pixel       frameColor, tileColor, borderColor;
	Pixel       faceColor[MAXCOLORS];
	XtCallbackList select;
#endif
} BarrelPart;

typedef struct _BarrelRec {
	CorePart    core;
	BarrelPart   barrel;
} BarrelRec;

extern int *startPosition;
extern void SetBarrel(BarrelWidget w, int reason);
extern Boolean MoveBarrel(BarrelWidget w,
	const int direction, const int tile, const int shift,
	const Boolean motion, const int speed);
extern void MoveBarrelDelay(BarrelWidget w,
	const int direction, const int tile, const Boolean all);

extern void SolveSomeTiles(BarrelWidget w);
extern void DrawAllTiles(const BarrelWidget w);
extern Boolean CheckSolved(const BarrelWidget w);
extern void InitMoves(void);
extern void PutMove(int direction, int tile, int control);
extern void GetMove(int *direction, int *tile, int *control);
extern int  MadeMoves(void);
extern void FlushMoves(BarrelWidget w);
extern int  NumMoves(void);
extern void ScanMoves(FILE * fp, BarrelWidget w, int moves);
extern void PrintMoves(FILE * fp);
extern void ScanStartPosition(FILE * fp, BarrelWidget w);
extern void PrintStartPosition(FILE * fp, BarrelWidget w);
extern void SetStartPosition(BarrelWidget w);

#endif /* _BarrelP_h */
