/*
 * NeXThextris Copyright 1994 Mark Gritter, mgritter@gac.edu
 *
 * hextris Copyright 1990 David Markley, dm3e@+andrew.cmu.edu, dam@cs.cmu.edu
 *
 * Permission to use, copy, modify, and distribute, this software and its
 * documentation for any purpose is hereby granted without fee, 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 copyright holders be used in
 * advertising or publicity pertaining to distribution of the software with
 * specific, written prior permission, and that no fee is charged for further
 * distribution of this software, or any modifications thereof.  The copyright
 * holder make no representations about the suitability of this software for
 * any purpose.  It is provided "as is" without express or implied warranty.
 *
 * THE COPYRIGHT HOLDER DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA, PROFITS, QPA OR GPA, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

/* This file contains the code for the control object, which calls the other
   hextris functions and manages I/O. */
   
#import "HextrisControl.h"
#import "HextrisView.h"
#import <appkit/TextField.h>
#import "TextView.h"
#import <dpsclient/dpsclient.h>
#import <appkit/Application.h>
#import <appkit/Button.h>

#include <libc.h>
#include <stdio.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/time.h>
#include <pwd.h>

#include "hextris.h"

extern id display, controller;
DPSTimedEntry teFall;

void TimedTick(DPSTimedEntry teNumber, double now, void *vmain) {
	DPSRemoveTimedEntry(teNumber);
	[controller tick];
}
	
void start_quickdrop(void) {
	[controller setQuickDrop:YES];
}

void stop_quickdrop(void) {
	[controller setQuickDrop:NO];
}

@implementation HextrisControl

- appDidInit:sender {
	struct passwd  *pwent;
	struct timeval tp;
    struct timezone tzp;

	score = 0;
	rows = 0;
	game_over = 1;
	game_view = 1;
	quickdrop = NO;
	paused = NO;
	pwent = getpwuid(getuid());
    if (pwent == (struct passwd *) NULL) {
    	if ((log_name = (char *)getenv("USER")) == NULL)
		log_name = "anon";
    } else log_name = pwent->pw_name;
	if ((name = (char *)getenv("XHEXNAME")) == NULL)
    	name = log_name;
    printf("\nWelcome, %s...\n",name);
	read_high_scores(high_scores);
    gettimeofday(&tp, &tzp);
    srandom((int)(tp.tv_usec));
	teFall = DPSAddTimedEntry(1.0, &TimedTick, NULL, NX_MODALRESPTHRESHOLD);
	display = hexView;
	controller = self;
	draw_borders();
	[mainWindow makeFirstResponder:hexView];
	[mainWindow makeKeyAndOrderFront:self];
	[mainWindow setMiniwindowIcon:"onehex.tiff"];
	new_game(grid, &npiece, &piece, &score, &rows);
	[hexView update];
	return self;
}

- showScores {
	[scoreText setIntValue:score];
	[rowText setIntValue:rows];
	return self;
}

- showHighScores:sender {
	int i;
	char *buffer, *bufp;
	buffer = malloc((MAXHIGHSCORES + 1) * 100);
	bufp = buffer;
	[highScoreWindow makeKeyAndOrderFront:self];
	sprintf(bufp, "#  Name                   UID   Score   Rows\n");
	bufp += strlen(bufp);
	for (i = 0; i < MAXHIGHSCORES; i++) {
		sprintf(bufp, "%2d %20s %7s %7d %4d\n", i, high_scores[i].name, high_scores[i].userid, high_scores[i].score, high_scores[i].rows);
		bufp += strlen(bufp);
	}
	[highScores setText:buffer];
	free(buffer);
	return self;
}

- showHelp {
	[helpWindow makeKeyAndOrderFront:self];
	return self;
}

- showNextPiece:(piece_t *)nextpiece {
	int base, form, i;
	base = (nextpiece->column % 2) ? 0 : 8;
    form = nextpiece->type * 6 + nextpiece->rotation;
	[nextPieceView clear];
    for (i = 0; i < 7; i += 2)
      [nextPieceView drawHexAt
	  	:nextpiece->row+shape[form][base+i]
	  	:nextpiece->column+shape[form][base+1+i]
		:1
		:nextpiece->type];
	return self;
}

- tick {
	int intvl;
	int oldscore;
	if (paused) return self;
	oldscore = score;
	if (quickdrop) {
		intvl = 5000;
		score += 10;
	}
	else intvl = 100000+(200000-((rows > 40) ? 20 : (rows/2))*10000);
	if (! game_over)
	  	if ((game_over = update_drop(grid,&npiece,&piece,&score,&rows))) {
	      	read_high_scores(high_scores);
			if (is_high_score(name, log_name, score, rows, high_scores))
			write_high_scores(high_scores,log_name);
			read_high_scores(high_scores);
			[self showHighScores:self];
		}
	if (score != oldscore) {
		[self showScores];
	    if (!quickdrop) intvl = 400000;
	}
	if (!game_over)
		teFall = DPSAddTimedEntry(intvl / 400000.0, &TimedTick,
									NULL, NX_MODALRESPTHRESHOLD);
	[hexView update];
	return self;
}

- keyDown:(NXEvent *)theEvent {
	int oldscore = score;
	if (paused || quickdrop || game_over) return self;
	do_choice(theEvent->data.key.charCode,grid,&npiece,&piece,&score,&rows,
			      &game_over, &game_view, high_scores);
	[hexView update];
	if (score != oldscore) {
		[self showScores];
		DPSRemoveTimedEntry(teFall);
		teFall = DPSAddTimedEntry(quickdrop ? 0.01 : 1.0, &TimedTick, NULL, NX_MODALRESPTHRESHOLD);
		}
	return self;
}

- pause:sender {
	if (paused) {
		[mainWindow makeKeyAndOrderFront:self];
		paused = NO;
		[pauseButton setTitle:"Pause!"];
		[pauseMenuItem setTitle:"Pause"];
		teFall = DPSAddTimedEntry(1.0, &TimedTick, NULL, NX_MODALRESPTHRESHOLD);
	} else {
		paused = YES;
		[pauseButton setTitle:"Resume"];
		[pauseMenuItem setTitle:"Resume"];
	}
	return self;
}

- newGame:sender {
	game_over = 0;
	quickdrop = NO;
	new_game(grid, &npiece, &piece, &score, &rows);
	[hexView clear];
	redraw_game(grid, &npiece, &piece, &score, &rows, 0, high_scores);
	teFall = DPSAddTimedEntry(1.0, &TimedTick, NULL, NX_MODALRESPTHRESHOLD);
 	return self;
}

- windowDidMiniaturize:sender {
	[self pause:self];
	return self;	
}

- windowDidResignMain:sender {
	[self pause:self];
	return self;
}

- windowDidBecomeMain:sender {
	[mainWindow makeFirstResponder:hexView];
	return self;
}

- setQuickDrop:(BOOL)on {
	quickdrop = on;
	return self;
}

@end
