/*****************************************************************************/
/*									     */
/*									     */
/*	X patience - xpat.h						     */
/*									     */
/*	Copyright (C) 1993, 1994 by Heiko Eissfeldt and Michael Bischoff     */
/*									     */
/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details. (The file COPYRIGHT.GNU)

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
/*									     */
/*									     */
/*	This file is included by all source files of xpat.		     */
/*	24-Feb-1993: First release (0.1)				     */
/*	04-May-1993: starting to work on 0.7				     */
/*			file renamed to xpat.h from gpat.h		     */
/*	29-Jan-1994: Release 1.0              				     */
/*									     */
/*									     */
/*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <assert.h>

#ifndef max
#define max(a, b)     ((a) > (b) ? (a) : (b))
#define min(a, b)     ((a) < (b) ? (a) : (b))
#endif

/* xpat.h -- generic patience include file */

typedef int boolean;            /* just one bit of information           */
typedef int Cardindex;		/* range from 0 to MAXCARDS-1            */
typedef int Pileindex;		/* range from 0 to MAXPILES              */
typedef int Card;		/* range from 0 to 51, plus CARDBACK...  */
typedef unsigned int XSize_t;   /* type used by X for width and height   */
                                /* this is not consistent used by X11R5  */
/* in X11R3, XSize_t was int, since R4 we seem to have a mixture of int  */
/* and unsigned int! (complain!)					 */

typedef enum { Club, Spade, Heart, Diamond } Suit;
typedef enum { Ace, Deuce, Three, Four, Five, Six, Seven, Eight, Nine,	Ten,
		Jack, Queen, King } Rank;

typedef enum { Stack, Slot, FaceupDeck, FacedownDeck, Tmp } Pile;

#define MAXCARDS	(Cardindex)504
#define MAXPILES	(Pileindex)63
#define MAXBUTTONS	32

extern struct graphic {
    boolean enable;             /* if zero, don't do any graphics        */
    boolean is_color;           /* True, if more than one bit per pixel  */ 
    boolean autolayout;         /* automatic new layout at resize events */
    XSize_t width;              /* the width of the root window          */
    XSize_t height;             /* the height of the root window         */
    XSize_t xgap;		/* room between two cards horizontally   */
    XSize_t ygap;		/* room between two cards vertically     */
    int yoff;			/* space for buttons                     */
    struct pile {
	int x;			/* x position of this pile               */
	int y;			/* y position of this pile               */
	int totalheight;	/* current height of pile in pixels      */
	int maxheight;		/* maximum y-pos of card on this pile    */
	int delta;		/* delta value of this pile              */
    } pile[MAXPILES];
    int cardy[MAXCARDS];	/* y-offset of card relative to pile     */
    Cardindex zoomed_card;      /* -1 or the index of an exposed card    */
    int ya_w, ya_h, xa_w, xa_h;	/* arrow head dimension, set by init 	 */
    int aw, ah;			/* width and height of an arrow 	 */
} graphic;

#define NOT_DISPLAYED(p)       ((p)->x == -1 && (p)->y == -1)

extern struct card {
    const char *cardset;        /* name of file for cards, or NULL for internals */
    int rx;			/* round edge, x */
    int ry;			/* round edge, y */
    XSize_t w;			/* width of a card */
    XSize_t h;			/* height of a card */
    int stddelta;		/* standard delta */
    int back_delta_x;		/* from spider */
    int back_delta_y;		/* (how much to modify the TS origin by) */
} card;

typedef unsigned long Move;
#define NEW_CARDS_MOVE	0xffff8000UL
#define MOVE(srcind, dstpile)	((Move)(srcind) | (Move)((dstpile) << 9))
#define MOVE_TURNED	(Move)0x8000
#define DSTPILE(m)	(int)((m >> 9) & 63)
#define SRCIND(m)	(int)(m & 511)

extern struct game {
    long seed;
    boolean finished;
    int numpiles;		/* number of piles in this game		     */
    Card cards[MAXCARDS];
    Pile piletype[MAXPILES];	/* what sort of pile this is             */
    Cardindex ind[MAXPILES+1];	/* stacks + slots + deck + terminator      */
    boolean visible[MAXCARDS];  /* True, if a card is face-up              */
    int numalloc;		/* space allocated for stored moves        */
    int n_moves;		/* currently used moves                    */
    int stored_moves;		/* >= n_moves, for redo                    */
    int cheat_count;		/* number of undos which turned back cards */
    int flipnum;		/* (Klondike only: current flip number)    */
    Move *move;			/* pointer to moves                        */
    Cardindex srcind;
    Cardindex arrow_srcind;
    Pileindex arrow_dstpile;
} game;

#define CUSTOM_DECKS	1
#define CUSTOM_SLOTS	2
#define CUSTOM_FACEUP	4
#define CUSTOM_FACEDOWN	8
#define CUSTOM_JOKERS	16
#define CUSTOM_TURNS	32
#define CUSTOM_FLIPS	64

#if 0
/* 0x100 to 0x800 are reserved for the following types, shiftet */
#define EXACT_MATCH	0
#define ALTERNATE_COLOR 1
#define XX_RESERVED	2
#define ALL_VALID	3
/* now the shift values: */
#define PLACE_SHIFT	8	/* cards may be placed on another */
#define MOVE_SHIFT	10 	/* cards may be moved together */
#endif

#define FORCE_SLOTS	0x0800	/* distribute extra cards on slots (FreeCell) */
#define STACK_SINGLE	0x1000	/* move single cards to stacks? */
#define EMPTY_KINGS	0x2000	/* only kings can go to empty slots */
#define DECK_SOURCE	0x4000	/* has visible deck from which single cards */
				/* can be moved (Klondike)		    */
#define STACK_SOURCE	0x8000	/* stack can be source of move (only in HM) */

extern struct rules {
    const char *shortname;	/* identifier to select rule set */
    const char *longname;	/* characterization of rule set */
    const char *description;    /* description of game variant (how to play) */
    int variant;		/* storage of modified parameters */
    Cardindex numcards;		/* usually 104 */
    Pileindex numstacks;	/* usually 8 */
    Pileindex numslots;		/* up to ten */
    Pileindex numtmps;		/* number of temporary storages */
    int numdecks;		/* usually 2 */
    int cards_per_color;	/* usually 13 */
    int numjokers;		/* usually 0 */
    int numflips;		/* (Klondike only: number of times the deck  */
                                /* may be flipped)                           */
    int numturns;		/* (Klondike only: number of cards which are */
                                /* turned each time you hit the deck)        */
    void (*new_game)(void);	/* initialize the game 			     */
    int (*relaxed_valid)(Card, Card); /* check, if a move is valid    */
    int (*valid)(Card, Card);	/* two cards are together movable            */
    int (*new_cards)(void);	/* check, if possible to give new cards      */
    int (*stackable)(Pileindex);/* returns index of card(s) movable to stack */
				/* -1 if not possible */
    int (*good_hint)(Cardindex, Pileindex); /* check, if a (hint)move is constructive */
    int facedown;		/* number of cards facedown in each slot at */
				/* beginning of game (rounded down) */
    int faceup;			/* number of cards faceup */
    int (*score)(void);		/* optional: score routine */
    int maxscore;		/* maximum score reachable */
    int (*automove)(Cardindex);	/* auto-select destination pile */
    int (*layout)(int, int, int, int, int);	/* auto-layout selection */
    void (*minwindow)(XSize_t *, XSize_t *);
} rules;

/* definition of a card: */
/* bits 0 and 1 give the color: 0 = diamond, 1 = heart, 2 = spades, 3 = club */
#define SUITSYMBOL	52	/* for empty stacks */
#define CARDBACK	56
#define OUTLINE         58
#define NOTHING         59
#define JOKER		60
#define IS_JOKER(i)	((i) >= JOKER)

#define SUIT(i)			((i) & 3)
#define RANK(i)			((i) >> 2)
#define NO_MOVE			0xffffffffUL
#define DIFFERENT_COLOR(i, j)	(((i) ^ (j)) & 2)
#define INDEX_OF_LAST_CARD(i)	(game.ind[(i)+1]-1)
#define	INDEX_OF_FIRST_CARD(i)	game.ind[i]
#define STACK(i)		(i)
#define SLOT(i)			((i) + rules.numstacks)
#define IDECK			(game.numpiles-1)
#define VDECK			(game.numpiles-2)
#define IS_STACK(i)		((i) < rules.numstacks)
#define CARDS_ON_PILE(i)	(game.ind[(i)+1] - game.ind[(i)])
#define EMPTY(i)		(!CARDS_ON_PILE(i))
#define FIRST_SLOT		(rules.numstacks)
#define LAST_SLOT		(rules.numstacks+rules.numslots-1)
#define FIRST_STACK		0
#define LAST_STACK		(rules.numstacks-1)
#define CARDS_ON_DECK		(rules.numcards - game.ind[IDECK])

/* more abbrevs */
#define ROUND_W		(card.rx)
#define ROUND_H		(card.ry)
#define CARD_WIDTH	(card.w)
#define CARD_HEIGHT	(card.h)
#define STD_DELTA	(card.stddelta)
#define True		1
#define False		0

/* Prototypes: */
/* main.c */
int main(int, char **);

/* windows.c */
void init_display(const char *);
void init_gfx(const char *, const char *, const char *);
void init_windows(int, char **, const char *, int, int, int, int,
   int, int, int);
void do_show_rules(void);
/* layout.c */
void init_layout(void);
void generic_minwindow(XSize_t *, XSize_t *);
void FreeCell_minwindow(XSize_t *x, XSize_t *y);
int FreeCell_layout(int, int, int, int, int);
boolean pile_resize(Pileindex);

/* markcard.c */
void init_mark(const char *, int);
void show_mark(boolean);

/* arrows.c */
void init_arrow(const char *, int, int);
void show_arrow(boolean);

/* expose.c */
void init_exposed_card(void);
void show_exposed_card(boolean);

/* rules.c */
void mem_alloc(int);
void store_move(Move);
int undo_move(void);		/* returns 1, if undo possible */
int redo_move(void);		/* returns 1, is redo possible */
Pileindex getpile(Cardindex);
Cardindex getblock(Cardindex, int);
Cardindex select_max(Pileindex, int);		/* -1 = invalid */
Move do_move(Cardindex, Pileindex);
int move_valid(int, int );
int move_to_stack(Pileindex);
int all_to_stack(void);
int Spider_alternate(Card, Card);
int Spider_relaxed_alternate(Card, Card);
int HM_alternate(Card, Card);
void new_rules(const char *, int, Pileindex, int, int, int, int, int);
Move give_new_cards(void);
void newgame(long);

/* hints.c */
const char *rank_name(int);
const char *suit_name(int);
void do_last_hint(void);
void do_all_moves(void);
int generic_automove(Cardindex);
int hint(Cardindex ind);         /* 0 = no moves */
#define RESET_HINTS        (-2)
#define ALL_HINTS          (-1)

/* events.c */
void do_give_hints(void);
void do_give_prev_hint(void);
void do_move_to_stack(void);
void event_loop(void);
void show_message(const char *);

/* gfx.c */
void init_cards(const char *, int, int, const char *, int, const char *);
void PaintCard(int, int, int, int);

/* cards.c */
/* void redraw_buttons(int, int, int, int, Window, int, struct singlebutton *); */
void redraw_one_pile(int, int, int, int, int);
void draw_pileupdate(Pileindex, int);


/* buttons.c */
void try_undo_move(void);
void try_redo_move(void);
void try_give_cards(void);
void leave_pat(void);
void show_score(void);
void do_another_game(void);
void do_restart_game(void);
void do_layout(void);
void do_replay_game(void);

/* loadsave.c */
void save_game(const char *);
void load_game(const char *);
void write_log_file(void);

/* tools.c */
#define PRANDMAX 1000000000L
void sprand(long);
long prand(void);

void sun_sound(const char *);
