// (C) Copyright 1992 Jim Patterson
#import <objc/Object.h>
#import <appkit/appkit.h>
#import <sys/time.h>
#import "LessonPlan.h"

#define TA_HOME "asdfjkl;"
#define TA_PUNCT "!,.'?\";:"
#define TA_SYMBOL "@#$%^&=*()_+-+[]{}\\|/><"

long random(void);
void srandom(int);

@implementation LessonPlan


+ new
{
	self = [super new];
	lessonNum = 1;
	srandom(5);
	return self;
}

- postInitialize 
{
	int i;
	for (i=0; i < 128; i++)
		keyboardKey[i] = [keyboardBox findViewWithTag:i];
	compactedCapsToo = 0;
	[self flushKeyboard];
	return self;
}

- setKeyboardBox:anObject { keyboardBox = anObject; return self; }
- setLessonNumMatrix:anObject {lessonNumMatrix = anObject; return self; }
- setLessonPlanWindow:anObject {lessonPlanWindow = anObject; return self; }
- lessonNumMatrix {return lessonNumMatrix; }
- setLessonNum:(int) newLessonNum {lessonNum = newLessonNum; return self; }

- keyChanged:sender
{
	int senderWasSelected = [sender state];
	int key = [sender tag];
		
	// key shift keys in parity
	if (key == TA_KEY_LEFTSHIFT) {
		[keyboardKey[TA_KEY_RIGHTSHIFT] setState:senderWasSelected];
		keyIsIncluded[TA_KEY_RIGHTSHIFT] = senderWasSelected;
		}
	else if (key == TA_KEY_RIGHTSHIFT) {
		[keyboardKey[TA_KEY_LEFTSHIFT] setState:senderWasSelected];
		keyIsIncluded[TA_KEY_LEFTSHIFT] = senderWasSelected;
		}		
 	keyIsIncluded[key] = senderWasSelected;	// keep track of user changes
	if (lessonNum != 14) {			
		lessonNum = 14;		// automatically become custom lesson
		[lessonNumMatrix  selectCellAt:6:1];
		}
	[lessonPlanWindow setDocEdited:YES];
	return self;
}


- (BOOL) keyIsSelected:(int) key { return keyIsIncluded[key];}

- selectKey: (int) key
 { 
 	keyIsIncluded[key] = YES;
	[keyboardKey[key] setState:1];
	return self;
}

- deselectKey: (int) key
{
	keyIsIncluded[key] = NO;
	[keyboardKey[key] setState:1];
	return self;
}

- selectKeysInStr :(char *) str
{
	char *p = str;
	while (*p != '\0') keyIsIncluded[(int) *p++] = YES;
	// user must flushKeyboard
	return self;
}

- selectKeysBetween :(int) start :(int) finish	// inclusive
{
	int i;
	for (i=start; i<=finish; i++) keyIsIncluded[i] = YES;
	// user must flushKeyboard
	return self;
} 

- deselectAll
{
	int i;
	for (i=32; i<128; i++) keyIsIncluded[i] = NO;
	keyIsIncluded[TA_KEY_LEFTSHIFT] = keyIsIncluded[TA_KEY_RIGHTSHIFT] = NO;
	return self;
}

- flushKeyboard
{
	int i,row,column;
	for (i=0; i<128; i++) {
		[keyboardKey[i] setState:keyIsIncluded[i]];
		row = ((lessonNum -1) % 7);
		column = (lessonNum >=8);		
		[lessonNumMatrix  selectCellAt:row:column];
		}
	return self;
}
					

// Methods to set and query lesson selections
- lessonChanged:sender
{
	// òBy the way, this is inlined to help optimized for speed
	//  at the expense of code length, since otherwise changing huge
	// blocks of keys and redisplaying is very slow
	int oldLessonNum = lessonNum;
	lessonNum = [[sender selectedCell] tag];
	if (lessonNum == oldLessonNum) return self;
	switch (lessonNum) {
		case 1:	[self deselectAll];	// home keys 
				[self selectKeysInStr:TA_HOME];
				break;
		case 2:	[self deselectAll];	// lower case
				[self selectKeysBetween:'a' :'z'];
				break;
		case 3:	if (oldLessonNum != 2) [self deselectAll];	// upper & lower
				[self selectKeysBetween:'a' :'z'];	// lower case
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				break;
		case 4:	[self deselectAll];		// punctuation
				[self selectKeysInStr:TA_PUNCT];
				break;
		case 5:	if ((oldLessonNum < 2) || (oldLessonNum > 4))	// lower & punct
					[self deselectAll];
				[self selectKeysBetween:'a' :'z'];
				[self selectKeysInStr:TA_PUNCT];
				break;
		case 6:	if ((oldLessonNum <2) || (oldLessonNum >5))	// upper, lower, punct
					[self deselectAll];
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				[self selectKeysBetween:'a' :'z'];
				[self selectKeysInStr:TA_PUNCT];
				break;
		case 7:	[self deselectAll];	// digits
				[self selectKeysBetween:'0':'9'];
				break;
		case 8:	if ((oldLessonNum != 7) && ((oldLessonNum <2 || oldLessonNum > 3)))
					[self deselectAll];		// dig, lett
				[self selectKeysBetween:'0':'9'];		
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				[self selectKeysBetween:'a':'z'];
				break;
		case 9:	if (oldLessonNum > 9) [self deselectAll];		// dig, lett,punct
				[self selectKeysBetween:'0':'9'];		
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				[self selectKeysBetween:'a':'z'];
				[self selectKeysInStr:TA_PUNCT];
				break;
		case 10:	[self deselectAll];
				[self selectKeysInStr:TA_SYMBOL];	// symbols
				break;
		case 11:	if  ((oldLessonNum != 10) && (oldLessonNum<2 || oldLessonNum>3))
					[self deselectAll];	// sym, lett
				[self selectKeysInStr:TA_SYMBOL];
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				[self selectKeysBetween:'a':'z'];
				break;
		case 12:	if ((oldLessonNum == 13) || (oldLessonNum = 14) || (oldLessonNum = 9) ||
					((oldLessonNum >=4) && (oldLessonNum <=6)))
						[self deselectAll];
				[self selectKeysBetween:'0':'9'];	// sym, let, digits
				[self selectKeysInStr:TA_SYMBOL];
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				[self selectKeysBetween:'a':'z'];
				break;				
		case 13:	[self selectKeysInStr:TA_PUNCT]; // punct, sym, let, digits		
				[self selectKeysBetween:'0':'9'];
				[self selectKeysInStr:TA_SYMBOL];
				keyIsIncluded[TA_KEY_LEFTSHIFT] = YES;
				keyIsIncluded[TA_KEY_RIGHTSHIFT] = YES;
				[self selectKeysBetween:'a':'z'];
				break;				
		case 14: break;	// custom
		}
	if (lessonNum !=14) [self flushKeyboard];
	[lessonPlanWindow setDocEdited:YES];				
	return self;
} 

- compactKeyList
{
	int i,ch;
	numCompactedKeys=0;
	compactedCapsToo=0;
	for (i=32; i<128; i++)
		if (keyIsIncluded[i])
			compactedKeyList[numCompactedKeys++] = (char) i;
	if (keyIsIncluded[TA_KEY_LEFTSHIFT])	// include caps if necessary
		for (ch=(int) 'a'; ch< ((int) 'z') + 1; ch++)
			if (keyIsIncluded[ch])
				compactedKeyList[numCompactedKeys++] = (char) ch-32;
	return self;
}

- (int) randomBetween:(int) lowBound :(int) highBound
{
	int temp = (int) random();
	return  ((temp % (highBound - lowBound +1)) + lowBound);
}

-(char) chooseChar	// from compacted key List
{
	if (!numCompactedKeys) return 'a';	// if no selected keys, return something at least
	return (compactedKeyList[[self randomBetween:0:numCompactedKeys-1]]);
}

- readInfo:(NXTypedStream *) tstream
{
	int i;
	NXReadType(tstream,"i",&lessonNum);
	NXReadArray(tstream, "i", 128, keyIsIncluded);
	[lessonPlanWindow setDocEdited:NO];
	[self flushKeyboard];
	return self;
}

- writeInfo:(NXTypedStream *) tstream
{
	NXWriteType(tstream,"i",&lessonNum);
	NXWriteArray(tstream, "i", 128, keyIsIncluded);
	[lessonPlanWindow setDocEdited:NO];
	return self;
}


@end
