CS193P Assignment 1 / Calculator / CalculatorViewController.m

//
//  CalculatorViewController.m
//  Calculator
//
//  Created by Jay Yu on 29/06/12.
//  Copyright (c) 2012 JayYu.com. All rights reserved.
//

#import "CalculatorViewController.h"
#import "CalculatorBrain.h"

@interface CalculatorViewController ()
@property (nonatomic, strong) CalculatorBrain *brain;
@property (nonatomic) BOOL userIsInTheMiddleOfEnteringANumber;
@property (nonatomic, strong) NSDictionary *testVariableValues;
@end

@implementation CalculatorViewController

@synthesize brain = _brain;
@synthesize display = _display;
@synthesize history = _history;
@synthesize variablesDisplay = _variablesDisplay;
@synthesize userIsInTheMiddleOfEnteringANumber = _userIsInTheMiddleOfEnteringANumber;
@synthesize testVariableValues = _testVariableValues;

- (CalculatorBrain *)brain
{
    if (!_brain) {
        _brain = [[CalculatorBrain alloc] init];
    }
    return _brain;
}

- (NSDictionary *)testVariableValues
{
    if (!_testVariableValues) {
        _testVariableValues = [[NSDictionary alloc] init];
    }
    return _testVariableValues;
}

- (void)appendHistory:(NSString *)aString;
{
    // Implements Required Task #4, Assignment 1
    if (! self.history.text) {
        self.history.text = @"";
    } else {
        self.history.text = [self.history.text stringByAppendingString:@" "];
    }

    if ([aString isEqualToString:@"="]) {
        // Extra Credit #2: put an "=" at the end of text label
        // Remove extraneous "=" already in history
        self.history.text = [self.history.text stringByReplacingOccurrencesOfString:@" ="
                                                                         withString:@""];
    }
    self.history.text = [self.history.text stringByAppendingString:aString];

    // Limit no. of characters in history so that font size of label will not
    // get smaller and smaller.
    NSUInteger length = [self.history.text length];
    NSUInteger limit = 38;
    if (length >= limit) {
        self.history.text = [self.history.text substringFromIndex:length - limit];
    }

}

- (IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [sender currentTitle];
    if ([digit isEqualToString:@"."]) {
        // handle special case for decimal point
        if (self.userIsInTheMiddleOfEnteringANumber) {
            NSRange range = [self.display.text rangeOfString:@"."];
            if (range.location == NSNotFound) {
                self.display.text = [self.display.text stringByAppendingString:digit];
            }
        } else {
            // shortcut for user: start entering an operand with "." will
            // automatically enter "0."
            self.display.text = @"0.";
            self.userIsInTheMiddleOfEnteringANumber = YES;
        }
    } else {
        if (self.userIsInTheMiddleOfEnteringANumber) {
            self.display.text = [self.display.text stringByAppendingString:digit];
        } else {
            self.display.text = digit;
            if (! [digit isEqualToString:@"0"]) {
                self.userIsInTheMiddleOfEnteringANumber = YES;
            }
        }
    }
}

- (IBAction)enterPressed
{
    [self.brain pushOperand:[self.display.text doubleValue]];
    self.history.text = [CalculatorBrain descriptionOfProgram:self.brain.program];
    self.userIsInTheMiddleOfEnteringANumber = NO;
}

- (IBAction)operationPressed:(UIButton *)sender
{
    if (self.userIsInTheMiddleOfEnteringANumber) {
        [self enterPressed];
    }
    NSString *operation = sender.currentTitle;
    double result = [self.brain performOperation:operation];
    self.history.text = [CalculatorBrain descriptionOfProgram:self.brain.program];
    self.display.text = [NSString stringWithFormat:@"%g", result];
}

- (IBAction)variablePressed:(UIButton *)sender
{
    if (self.userIsInTheMiddleOfEnteringANumber) {
        [self enterPressed];
    }
    NSString *variable = sender.currentTitle;
    [self.brain pushVariable:variable];
    self.history.text = [CalculatorBrain descriptionOfProgram:self.brain.program];
}

- (IBAction)allClear
{
    [self.brain clearStates];
    self.display.text = @"0";
    self.history.text = @"";
    self.userIsInTheMiddleOfEnteringANumber = NO;
}

- (IBAction)backspacePressed
{
    NSUInteger length = [self.display.text length];
    if (length > 0) {
        self.display.text = [self.display.text substringToIndex:length - 1];
    } else {
        self.userIsInTheMiddleOfEnteringANumber = NO;
        self.display.text = @"0";
    }
}

- (IBAction)invertSignPressed
{
    double result = 0;
    if (self.userIsInTheMiddleOfEnteringANumber) {
        // modify in-place the number currently in the display.
        result = [self.display.text doubleValue];
        if (result != 0) {
            result = result * -1;
        }
        self.display.text = [NSString stringWithFormat:@"%g", result];
    } else {
        // implement +/- as an operation
        [self.brain performOperation:@"+/-"];
    }
}

- (IBAction)testPressed:(UIButton *)sender
{
    NSString *testNumber = sender.currentTitle;

    if (self.userIsInTheMiddleOfEnteringANumber) {
        [self enterPressed];
    }

    if ([@"Test 1" isEqualToString:testNumber]) {
        self.testVariableValues = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [NSNumber numberWithDouble:9.23], @"x",
                                   [NSNumber numberWithDouble:-20], @"y",
                                   [NSNumber numberWithDouble:0], @"z", nil];
    }

    if ([@"Test 2" isEqualToString:testNumber]) {
        self.testVariableValues = [NSDictionary dictionaryWithObjectsAndKeys:
                                   [NSNumber numberWithDouble:-2.11], @"x",
                                   [NSNumber numberWithDouble:38.000], @"y",
                                   [NSNumber numberWithDouble:0.18], @"z", nil];
    }

    if ([@"Test 3" isEqualToString:testNumber]) {
        self.testVariableValues = nil;
    }

    [self updateDisplays];
}

- (void)updateDisplays
{
    [self updateDisplays:self.brain.program usingVariables:self.testVariableValues];
}

- (void)updateDisplays:(id)program
        usingVariables:(NSDictionary *)variables
{
    if (! program) {
        program = self.brain.program;
    }

    if (! variables) {
        variables = self.testVariableValues;
    }

    double result = [CalculatorBrain runProgram:program
                            usingVariableValues:self.testVariableValues];
    self.history.text = [CalculatorBrain descriptionOfProgram:program];
    self.display.text = [NSString stringWithFormat:@"%g", result];

    if (! variables) {
        self.variablesDisplay.text = @"Variables not set";

    } else {
        NSMutableArray *variableList = [[NSMutableArray alloc] init];
        for (id variable in [CalculatorBrain variablesUsedInProgram:program]) {
            id object = [self.testVariableValues objectForKey:variable];
            if (! object) {
                object = @"0";
            }
            [variableList addObject:[NSString stringWithFormat:@"%@ = %@", variable, object]];
        }
        self.variablesDisplay.text = [variableList componentsJoinedByString:@", "];
    }
}

- (IBAction)undoPressed
{
    if (self.userIsInTheMiddleOfEnteringANumber) {
        [self backspacePressed];
    }
    if (! self.userIsInTheMiddleOfEnteringANumber) {

    }
}

- (void)viewDidUnload {
    self.history = nil;
    self.variablesDisplay = nil;
    self.testVariableValues = nil;
    [self setVariablesDisplay:nil];
    [super viewDidUnload];
}
@end
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.