#import "Card.h"
#import <appkit/nextstd.h>

#define MAXDATA 1024
#define FACE_PTR(F) ((CardFace *)dataPtr+F)
#define FACE_DATA(F) FACE_PTR(F)->data

static int  activeFace;		/* which field to Find / Search on */
static int  sortFlag;		/* flag for sorting */
#define VALID_FACE(f) (f >= 0 && f < numElements)
#define NOUGHT '\0'

extern int  re_exec(char *s);
@implementation Card

+ initialize
{
    [self setVersion:CARD_VERSION];
    return self;
}

+ new
{
    return[self newCount:2];
}

+ newCount:(unsigned)numSlots
{
    return[self newCount:numSlots elementSize:sizeof(CardFace)
	   description:cardDescription];
}

/* Set Global Parameters */

+ (int)activeFace
{
    return activeFace;
}

+ setActiveFace:(int)face
{
    activeFace = face;
    return self;
}

+ (int)sortFlag
{
    return sortFlag;
}

+ setSortFlag:(int)flag
{
    sortFlag = flag;
    return self;
}

/* Get data in and Out */

- printStream:(NXStream *)stream
{
    char        *tmp;
    int         i;

    for (i = 0; i < numElements; i++)
	NXPrintf(stream, "\"%s\"%c", FACE_PTR(i)->data,
		 (i < (numElements-1)) ? ',' : '\n');

    return self;
}

static CardFace *getString(NXStream *stream)
{
	static char temp[MAXDATA];
	int i=0;
	char c;
	CardFace    *face;
	
	while ((c=NXGetc(stream)) != '"')
		temp[i++] = c;
	NX_MALLOC(face,CardFace,1);
	NX_MALLOC(face->data,char,i+1);
	strncpy(face->data,temp,i);
	(face->data)[i]=NOUGHT;
	face->length = i;
	return face;
}
 
- scanStream:(NXStream *)stream
{
    int count=0;
    char c;

    while ((c=NXGetc(stream)) != '\n')
	switch (c) {
	  case '"':  [self addElement:getString(stream)];
	    break;
	  case ',':
	  default: break;
	} 	

    return self;
}

- setFace:(int)face string:(STR) string
{
    if (VALID_FACE(face)) {
	FACE_DATA(face) = string;
	FACE_PTR(face)->length = strlen(string);
	return self;
    }
    return nil;
}

- setFace:(int)face stream:(NXStream *) stream
{
    char       *buf;
    int         len, maxlen;
    if (VALID_FACE(face)) {
		NXGetMemoryBuffer(stream, &buf, &len, &maxlen);
		NX_MALLOC(FACE_DATA(face), char, len + 1);
		strncpy(FACE_DATA(face), buf, len);
		FACE_DATA(face)[len] = NOUGHT;
		FACE_PTR(face)->length = len;
		return self;
    }
    return nil;
}

- (NXStream *) faceStream:(int)face;
{
    if (VALID_FACE(face))
	return NXOpenMemory(FACE_DATA(face), FACE_PTR(face)->length - 1,
			    NX_READONLY);
    return NULL;
}

- (STR) faceString:(int)face;
{
    if (VALID_FACE(face))
	return FACE_DATA(face);
    return NULL;
}

- setFace:(int)face tag:(int)tag
{
    FACE_PTR(face)->tag = tag;
    return self;
}

- (int)faceTag:(int)face
{
    return FACE_PTR(face)->tag;
}

- setFace:(int)face object:anObject;
{
    FACE_PTR(face)->object = anObject;
    return self;
}

- faceObject:(int)face;
{
    return FACE_PTR(face)->object;
}

/* Find and Sort Methods */

- findSTR:(STR) aString
{
    if (re_exec(FACE_DATA(activeFace)))
	return self;
    return nil;
}

static STR  invert(STR s, int len)
{
    STR         temp;
    STR         tptr;
    tptr = NX_MALLOC(temp, char, len + 1)+len;
    *tptr = NOUGHT;
    while (tptr > temp)
	*(--tptr) = *(s++);	/* up to Null */

    return temp;
}

- (int)compare:aCard	/* (-, 0, +if self <, =, >aCard) */
{
    STR         them, me;
    them = [aCard faceString:activeFace];
    switch (sortFlag) {
    case CARDSORT_Tag:
	return FACE_PTR(activeFace)->tag - [aCard faceTag:activeFace];
    case CARDSORT_InvFace:
	me = invert(FACE_DATA(activeFace), FACE_PTR(activeFace)->length);
	them = invert(them, strlen(them));
	return strcmp(me, them);
    case CARDSORT_Face:
    default:
	return strcmp(FACE_DATA(activeFace), them);
    }
}
/* Target action methods */

- flip
{
    CardFace    face;
    face = *(CardFace *)[self elementAt:0];
    [[self removeAt:0] addElement:(void *)&face];
    return self;
}

@end
