//
//  FileContentsViewController.m
//  FilesystemExplorer
//
//  Created by Chris Adamson on 11/5/08.
//  Copyright 2008 Subsequently and Furthermore, Inc.. All rights reserved.
//
//
//  Licensed with the Apache 2.0 License
//  http://apache.org/licenses/LICENSE-2.0
//


#import "FileContentsViewController.h"


@implementation FileContentsViewController

@synthesize filePath;
 
//START:code.FilesystemExplorer.append-text-to-view
-(void) appendTextToView: (NSString*) textToAppend
{
	fileContentsTextView.text = [NSString stringWithFormat:
		 @"%@%@", fileContentsTextView.text, textToAppend];
}
//END:code.FilesystemExplorer.append-text-to-view

- (void) loadFileContentsIntoTextViewViaNSData {
	NSData *fileData = [NSData dataWithContentsOfFile: filePath];
	NSString *fileDataString =
	[[NSString alloc] initWithData: fileData
						  encoding:NSUTF8StringEncoding];
	fileContentsTextView.text = fileDataString;
}

/* initWithContentsOfFile: is deprecated. use initWithContentsOfFile:encoding:error:
			or initWithContentsOfFile:usedEncoding:error: instead
- (void) loadFileContentsIntoTextViewString {
	fileContentsTextView.text =
		[[NSString alloc] initWithContentsOfFile: filePath];
}
*/


- (void) loadFileContentsIntoTextViewString {
	fileContentsTextView.text =
		[NSString stringWithContentsOfFile: filePath
					usedEncoding: NULL
					error: NULL];
}
 
//START:code.FilesystemExplorer.file-contents-read
- (void) loadFileContentsIntoTextView {
	// open a stream to filePath
	NSInputStream *inputStream = [[NSInputStream alloc]
		initWithFileAtPath: filePath];
	[inputStream open];
	// read and dump to NSTextView
	NSInteger maxLength = 128;
	uint8_t readBuffer [maxLength];
	BOOL endOfStreamReached = NO;
	// NOTE: this tight loop will block until stream ends
	while (! endOfStreamReached) {
		NSInteger bytesRead = [inputStream read: readBuffer
			 maxLength:maxLength];
		if (bytesRead == 0) {
			endOfStreamReached = YES;
		} else if (bytesRead == -1) {
			// TODO - should have an error dialog
			endOfStreamReached = YES; 
		} else {
			NSString *readBufferString =
			[[NSString alloc]
			 initWithBytesNoCopy: readBuffer
			 length: bytesRead
			 encoding: NSUTF8StringEncoding
			 freeWhenDone: NO];							   
			[self appendTextToView: readBufferString];
			[readBufferString release];
		}
	} // while ! endOfStreamReached
	[inputStream close];
	[inputStream release];
}
//END:code.FilesystemExplorer.file-contents-read


/* this is the first example from the book. unsafe because the input stream may
	keep going after you navigate back, leading to EXC_BAD_ACCESS when it finishes
//START:code.FilesystemExplorer.setup-async-file-read
- (void) setUpAsynchronousContentLoad {
	// open a stream to filePath
	NSInputStream *inputStream =
		[[NSInputStream alloc] initWithFileAtPath: filePath];
	[inputStream setDelegate: self];
	[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] //<label id="co.FilesystemExplorer.scheduleinrunloop"/>
		forMode:NSDefaultRunLoopMode];
	[inputStream open];
	[inputStream release];
}
//END:code.FilesystemExplorer.setup-async-file-read
*/

//START:code.FilesystemExplorer.setup-async-file-read-with-ivar
- (void) setUpAsynchronousContentLoad {
	[asyncInputStream release];
	// open a stream to filePath
	asyncInputStream =
		[[NSInputStream alloc] initWithFileAtPath: filePath];
	[asyncInputStream setDelegate: self];
	[asyncInputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
		forMode:NSDefaultRunLoopMode];
	[asyncInputStream open];
}	
//END:code.FilesystemExplorer.setup-async-file-read-with-ivar


//START:code.FilesystemExplorer.file-read-view-will-disappear
- (void) viewWillDisappear: (BOOL) animated {
	[asyncInputStream removeFromRunLoop:[NSRunLoop mainRunLoop]
		forMode:NSDefaultRunLoopMode];
	[asyncInputStream close];
	[super viewWillDisappear: animated];
}
//END:code.FilesystemExplorer.file-read-view-will-disappear

// delegate method for handling callbacks while reading stream, called by run lop
//START:code.FilesystemExplorer.async-file-delegate
- (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent {
	NSInputStream *inputStream = (NSInputStream*) theStream;
	switch (streamEvent) {
		case NSStreamEventHasBytesAvailable: { // <label id="code.FilesystemExplorer.async-file-delegate.bytesavailable.start"/>
			NSInteger maxLength = 128; 
			uint8_t readBuffer [maxLength]; // <label id="code.FilesystemExplorer.async-file-delegate.bytesavailable.buffer"/>
			NSInteger bytesRead = [inputStream read: readBuffer // <label id="code.FilesystemExplorer.async-file-delegate.bytesavailable.read"/>
					maxLength:maxLength];
			if (bytesRead > 0) {
				NSString *bufferString = [[NSString alloc] // <label id="code.FilesystemExplorer.async-file-delegate.bytesavailable.string"/>
				  initWithBytesNoCopy: readBuffer
				  length: bytesRead
				  encoding: NSUTF8StringEncoding
				  freeWhenDone: NO];							   
				[self appendTextToView: bufferString];
				[bufferString release];
			}
			break;
		} // case: bytes available // <label id="code.FilesystemExplorer.async-file-delegate.bytesavailable.end"/>
		case NSStreamEventErrorOccurred: {
			// dialog the error
			NSError *error = [theStream streamError];
			if (error != NULL) {
				UIAlertView *errorAlert = [[UIAlertView alloc]
				   initWithTitle: [error localizedDescription]
				   message: [error localizedFailureReason]
				   delegate:nil
				   cancelButtonTitle:@"OK"
				   otherButtonTitles:nil];
				[errorAlert show];
				[errorAlert release];
			}
			
			[inputStream removeFromRunLoop: [NSRunLoop currentRunLoop] 
					forMode:NSDefaultRunLoopMode];
			[theStream close];
			break;
		}
		case NSStreamEventEndEncountered: {
			[inputStream removeFromRunLoop: [NSRunLoop currentRunLoop] 
					forMode:NSDefaultRunLoopMode];
			[theStream close];
		}
	}
}
//END:code.FilesystemExplorer.async-file-delegate



/*
// Override initWithNibName:bundle: to load the view using a nib file then perform additional customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
        // Custom initialization
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically.
- (void)loadView {
}
*/

/*
// Implement viewDidLoad to do additional setup after loading the view.
*/
- (void)viewDidLoad {
    [super viewDidLoad];
	
	// load contents of file into text view
	//[self loadFileContentsIntoTextView];
	
	// or do it asynchronously
	[self setUpAsynchronousContentLoad];
		
	// or do it cheap
	// [self loadFileContentsIntoTextViewViaNSData];
	
	// or do it really cheap
	// [self loadFileContentsIntoTextViewString];
	
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
    // Release anything that's not essential, such as cached data
}


- (void)dealloc {
	[filePath release];
	[fileContentsTextView release];
	[asyncInputStream release];
    [super dealloc];
}


@end
