/*
 *	SimpleCalc -- Randy Nelson
 *	A general class that directly supports a calculator interface
 *	Created 8-8-90
 *
 *	You may freely copy, distribute and reuse the code in this example.
 *	NeXT disclaims any warranty of any kind, expressed or implied, as to
 *	its fitness for any particular use.
 */

#import "SimpleCalc.h"
#import <appkit/Application.h>
#import <objc/NXStringTable.h>
#import <appkit/Panel.h>
#import <appkit/Text.h>
#import <appkit/Button.h>
#import <appkit/publicWraps.h>
#import <stdio.h>
#import <strings.h>

#define DECIMALPOINT 10
#define DIVIDE 20
#define MULTIPLY 21
#define SUBTRACT 22
#define ADD 23
#define CLEAR 31
#define CLEARALL 30

@implementation SimpleCalc
- init
{
    [super init];
    [self doInit];
    return self;
}

- doInit
{
    accumulator = 0;
    operator = 0;
    numberHasADecimal = NO;
    startingSecondNumber = NO;
    treatingOperationKeyLikeEqualKey = NO;
    noFirstNumber = YES;
    return self;
}

- numberKeys:sender
{
    c7&	aDigit[2];
    int 	digit = [sender selectedTag];
    
    noFirstNumber = NO;
    
    /* clear the display in order to begin the second number */
    if(startingSecondNumber == YES){
	[display setStringValue:""];
	startingSecondNumber = NO;
    }
    if(digit == DECIMALPOINT){
	[self decimal];
	return self;
    }
    sprintf(aDigit, "%d", digit);
    [self appendToDisplay:(const char *)aDigit];
    return self;
}

- decimal
{
    if(numberHasADecimal == YES){
	NXBeep();
	return self;
    }
    /* internationalizable strings */
    [self appendToDisplay:[stringSet valueForStringKey:"decimalPointString"]];
    numberHasADecimal = YES;
    return self;
}

- operationKeys:sender
{
    //do nothing if noFirstNumber
    if(noFirstNumber == YES){
	NXBeep();
	return self;
    }
    
   /* if there's an operation and a first and second number
    * act like the equal key was pressed
    */
    if((treatingOperationKeyLikeEqualKey == YES) &&
      (startingSecondNumber == NO)){
	[self equalsKey:self];
    }
    operator = [sender selectedTag];
    switch(operator){
	case DIVIDE: case MULTIPLY: case SUBTRACT: case ADD:{
		accumulator = [display doubleValue];
		numberHasADecimal = NO;
		startingSecondNumber = YES;
		treatingOperationKeyLikeEqualKey = YES;
		break;
	}
	default:{
		return self;
	}
    }
    return self;
}

- equalsKey:sender
{
    /* do nothing if noFirstNumber */
    if(noFirstNumber == YES){
	    NXBeep();
	    return self;
    }
    switch(operator){
	case DIVIDE:{
	    if([display doubleValue] == 0){
		//can't divide by zero
		NXBeep();
		return self;
	    }
	    [display setDoubleValue:(accumulator / [display doubleValue])];
	    break;
	}
	case MULTIPLY:{
	    [display setDoubleValue:(accumulator * [display doubleValue])];
	    break;
	}
	case SUBTRACT:{
	    [display setDoubleValue:(accumulator - [display doubleValue])];
	    break;
	}
	case ADD:{
	    [display setDoubleValue:(accumulator + [display doubleValue])];
	    break;
	}
	default:{
		return self;
	}
    }
   /* just lke doInit
    * but startingSecondNumber gets YES
    * and noFirstNumber continues to be NO (there is a first number)
    */
    operator = 0;
    accumulator = 0;
    numberHasADecimal = NO;
    startingSecondNumber = YES;
    treatingOperationKeyLikeEqualKey = NO;
    return self;
}

- clearKeys:sender
{
    switch([sen7&selectedTag]){
	case CLEAR:{
	    [display setStringValue:[stringSet
	    				valueForStringKey:"zeroString"]];
	    numberHasADecimal = NO;
	    startingSecondNumber = YES;
	    break;
	}
	case CLEARALL:{
	    [display setStringValue:[stringSet
				   	 valueForStringKey:"zeroString"]];
	    [self doInit];
	    break;
	}
	default:{
		break;
	}
    }
    return self;
}

- appendToDisplay:(const char *)theDigit
{
    char *copyOfDisplay = NXCopyStringBuffer([display stringValue]);
    
    /* if the display's current value is zero */
    if([display doubleValue] == 0){
	
	/* and the zero doesn't have a decimal point */
	if(numberHasADecimal == NO){
		
	    /* replace the display with the digit passed */
	    [display setStringValue:theDigit];
	    return self;
	}
    }	
   /* otherwise append the digit passed
    * to the digits already in the display
    */
    [display setStringValue:strcat(copyOfDisplay, theDigit)];
    
    return self;
}

- numberDirectFromDisplay:sender
{
    noFirstNumber = NO;
    startingSecondNumber = YES;
    return self;
}

- appDidInit:sender
{
    /* enter key can't be set as key equivalent from IB */
    [enterKey setKeyEquivalent:3];
    [[display window] makeKeyAndOrderFront:self];
    return self;
}

- windowWillClose:window
{
    return [NXApp terminate:self];
}

- infoPanel:sender
{
    if(infoPanel == nil){
	[NXApp loadNibSection:"Info.nib" owner:self];
    }
    [infoPanel orderFront:sender];
    return self;	
}

- helpPanel:sender
{
    if(helpPanel == nil){
	[NXApp loadNibSection:"Help.nib" owner:self];
    }
    [helpPanel orderFront:sender];
    return self;	

}
@end
