/*
 * the import directive, below, serves the same purpose
 * as include, with a twist: import automatically
 * guarantees that you can't get multiple inclusions of
 * the same file, so there's no need for ifndef blocks
 * in your header files.
 */

#import <stdio.h>
#import <stdlib.h>
#import <ctype.h>
#import "Equeue.h"

/*
 * A note on file names:
 *
 * Whereas C uses .h and .c files, and C++ uses .h and .cpp,
 * Objective-C files are either .h or .m. .h files are still
 * used for class headers (called 'interfaces' here), while
 * .m files hold the actual implementation. Incidentally, the 
 * '.m' extension stems from those being the files holding
 * 'messages'.
 */

/*
 * A note on memory management:
 *
 * Objective-C possesses a garbage collector, but it is designed
 * to be much simpler than the one used by Java. Rather than be
 * completely automatic, the GC system makes use of a technique
 * called reference counting. Effectively, each object has a
 * reference count associated with it. When a block of code wants
 * to use the object, it increments the count (using 'retain').
 * When the code is done with an object, it decrements the count
 * (using 'release'). When the reference count hits zero, the
 * garbage collector knows the object is no longer in use and can
 * be freed.
 *
 * Objects are automatically retained when they are alloc'd, so
 * a brand new object will have a reference count of 1.
 *
 * Good coding practice is to clean up after yourself, but to also
 * never release anything you didn't either retain or alloc.
 */


/***********************************************************************
 * int main()
 *
 * main function for the program. deals with accepting/parsing
 * user input and generally keeping things running
 *
 * no parameters / always returns 0
 ***********************************************************************/
int main () {
	/*
	 * Rather can using the familiar dot and function call
	 * syntax from C++, Objective-C uses Smalltalk-style
	 * message passing. The syntax is as follows:
	 *  [recipient message];
	 * which is equivalent to the C++ code:
	 *  recipient.message();
	 */
	
	/*
	 * Objective-C makes allocating memory for an object and 
	 * initializing it two separate steps. These are normally
	 * handled as below, by sending 'alloc' to the class in
	 * question, and then send 'init' (or some variant thereof)
	 * to the object returned by alloc.
	 */
    Equeue *equeue = [[Equeue alloc] init];
	
    char cmd;
    int  value;
	
    scanf("%c", &cmd);          // read in an intial command
    
    /*
     * scanf will return whatever character it finds, so we need some way
     * to weed out the whitespaces while looking for characters
     */
    while(isspace(cmd)) { scanf("%c", &cmd); }
    
    while(cmd != 'q') {         // dump out if we get a q
        switch (cmd) {          // figure out what we're doing
            case 'i':           // insert into queue
                scanf("%d", &value);   // get the value to insert
				
				/* 
				 * Messages can also contain parameters. In this
				 * case, the below message is equivalent to this C++:
				 *  equeue->enqueueValue(value);
				 */
				
                if([equeue enqueueValue:value]) {
					printf("enqueued %d\n", value);
				}
				else {
					printf("failed to enqueeu %d\n", value); 
				}
                break;
				
            case 'e':           // empty the queue
                [equeue empty];
				printf("emptied equeue\n");
                break;
				
            case 'r':           // dequeue and print last value
                if([equeue dequeueInto:&value]) { 
					printf("dequeued value %d\n", value); 
				}
                else { 
					printf("equeue is empty\n"); 
				}
                break;
				
            default:            // here for giggles
                printf("Oi! That's not a legal command\n");
        }
        
        scanf("%c", &cmd);      // get the next command
        while(isspace(cmd)) { scanf("%c", &cmd); }    
    }
    
	/*
	 * If you allocated something, you're responsible for releasing
	 * it, in the same way you have to delete anything you create
	 * with new.
	 */
	[equeue release];
    
    return 0;
}

