// FILE:      BrailleConverter.m
// AUTHOR:    Daniel Lee
// PURPOSE:   
// REFERENCE: None. 
// COMMENTS:  Required that the Braille Font is installed, or the program will not function
// REQUIRES:  BrailleConverter.h 
// Last Mod:  24-05-2006




#import "BrailleConverter.h"

@implementation BrailleConverter


// NAME: awakefromNib
// PURPOSE: To initilise the view for use
// IMPORTS: nil
// EXPORTS: nil
// AUTHOR: Daniel Lee
// REMARKS: Should be called after the object is started
// LAST MODIFIED: 23-05-2006

- (void) awakeFromNib
{
	
	// *******************
	// Initialise the data
	// *******************
	
	// Build up the language list and to set it to the interface so that
	// language switching is possible
	// Also, should be set to the current language of the system
    // ??

    // Set the boxes to set the delegate to this object
    [inputTextView setDelegate: self];
	[brailleTextView setDelegate: self];
	// asciiTextView does not needs a delegate since only braille is being sent there
	// There is no input that is allowed to be placed in that box

    // Set the font of the asciiTextView and brailleTextView to braille, size 16
    NSFont* braille = [NSFont fontWithName: @"Braille" size: 0.0];
    [brailleTextView setFont: braille];

    // create the tags
    [self loadTags];

    return;
}


// NAME: loadTags
// PURPOSE: To read the ini file and create the tags
// IMPORTS: nil
// EXPORTS: nil
// AUTHOR: Daniel Lee
// REMARKS: None
// LAST MODIFIED: 24-05-2006

- (void) loadTags
{
    NSFileManager *file = [NSFileManager defaultManager];
	NSData *dataFromFile;
    NSMutableArray *tagsArray = [[NSMutableArray alloc] init];
   	NSMutableArray *fileArray = [[NSMutableArray alloc] init];
		
    if( [file fileExistsAtPath: tagTable] )
	{
        dataFromFile = [file contentsAtPath: tagTable];
    	NSString *stringData = [NSString stringWithCString: (const char*) [dataFromFile bytes] encoding: NSASCIIStringEncoding];
		
		BOOL tags = FALSE;
		BOOL file = FALSE;
		BOOL lastItem_Tag = FALSE;
		NSRange range;
		int tagLocation = 0;
		int fileLocation = 0;
		
		int i;
		
		// Parsing the tags
		for( i = 0; i < [stringData length]; i++ )
		{
		    if( [stringData characterAtIndex: i] == '<' )
		    {
			    if( tags )
				{
				    NSLog( @"Aborted. Cannot have < in a tag." );
				}
				else if( lastItem_Tag )
				{
				    NSLog( @"Aborted. Cannot have two tags in a row." );
				}
				else if( file )
				{
				    NSLog( @"Aborted. Cannot have < in a file." );
				}
				else
				{
    			    tags = TRUE;
	    			tagLocation = i;
				}
			}
			else if( [stringData characterAtIndex: i] == '>' )
			{
			    // No need to check lastItem_Tag.
				// If there is no '<' found first, it is still an abort
			    if( file )
				{
				    NSLog( @"Aborted. Cannot have < in a file." );
				}
				else if( !tags )
				{
				    NSLog( @"Aborted. Cannot have > without a accopmanying <." );
				}
				else
				{
			        tags = FALSE;
				    lastItem_Tag = TRUE;
				    range.location = tagLocation;
			    	range.length = i - tagLocation + 1;
			        NSString* tagData = [stringData substringWithRange: range];
					
					[tagsArray addObject: tagData];
			    }
			}
			else if( [stringData characterAtIndex: i] == '\"' )
			{
			    // Should check is the tag is still set
				// No quotation marks in the tags at all

				// If there are a tag, then abort using a window

                if( tags )
				{
    				NSLog( @"Aborted, \" found between a tag." );
				    exit( 0 );
				}
				else
				{
				    // If lastItem_Tag and file are false
					// Then the last item was a file and this is
					// a new file. Violates the pair

				    if( !lastItem_Tag && !file )
					{
					    NSLog( @"Aborted, last tag was a file" );
					}
			        else if( file )    // If the file tag is set
				    {
    				    file = FALSE;
						lastItem_Tag = FALSE;
	    			    range.location = fileLocation + 1;
		    		    range.length = i - fileLocation - 1;
			    		NSString* fileName = [stringData substringWithRange: range];

						[fileArray addObject: fileName];
				    }
    				else
	    			{
		    		    file = TRUE;
			    		fileLocation = i;
				    }
				}
			}
			else if( ( [stringData characterAtIndex: i] == '\r' )
			       || ( [stringData characterAtIndex: i] == '\n' ) )
			{
			    // If there is a dangling tag or file name.
			    if( file || tags )
				{
				    NSLog( @"Aborted, new line character seen in between a tag or file." );
					exit( 0 );
				}
			}
		}
	}
	else
	{
	    // Need to make a window for this
	    NSLog( @"No ini file found at");
	    NSLog( tagTable );
	    exit( 0 );
    }
	
	//Test
	/*
	int i;
	for( i = 0; i < [fileArray count]; i++ )
	{
	    NSString *data = (NSString *) [fileArray objectAtIndex: i];
		NSLog( data );
	}
	*/
}


// NAME: setBrailleGrade
// PURPOSE: To get the new grade value and insert a tag.
// IMPORTS: nil
// EXPORTS: nil
// AUTHOR: Daniel Lee
// REMARKS: None
// LAST MODIFIED: 10-05-2006

- (IBAction) setBrailleGrade: (id) sender
{
    NSString* data = [brailleGradeMenu stringValue];
	NSString* speakingText;
	NSTextView *input, *output;
    int locationOfCursor = 0;

    // Set the input and output variables to the respective ones which are to be used
	// This is done because the code is very similar on a lot of places and that the
	// program should be a s compact as possible.
	
    if( translateToBraille )
	{
        input = inputTextView;
        output = brailleTextView;
	}
	else
	{
        input = brailleTextView;
        output = inputTextView;	
	}
	
    // Tests the string for a certain value and also if the grade it is going
	// into is also not the one which is already set
	
	if( [data isEqualToString: @"0"] )
	{
	    speakingText = @"Grade 0 braille tag inserted.";
		// Insert <g0> marker at cursor
		locationOfCursor = [input selectedRange].location;
	    [input insertText: @"<g0>"];
		// Insert into the array, location and grade of tag
	}
	else if( [data isEqualToString: @"1"] )
	{
	    speakingText = @"Grade 1 braille tag inserted.";
		// Insert <g1> marker at cursor
		locationOfCursor = [input selectedRange].location;
	    [input insertText: @"<g1>"];
		// Insert into the array, location and grade of tag
	}
	else if( [data isEqualToString: @"2"] )
	{
        speakingText = @"Grade 2 braille tag inserted.";
 		// Insert <g2> marker at cursor
		locationOfCursor = [input selectedRange].location;
	    [input insertText: @"<g2>"];
		// Insert into the array, location and grade of tag
	}
	else
	{
	    // Nothing here, all possibilities should have been covered.
		speakingText = @"";
	}

	// Output which grade had been changed
    if( ![speakingText isEqualToString: @""] )
	{
        [speechObject speak:speakingText];
    }
}


// NAME: setLanguage
// PURPOSE: To set the new tables for translating to and from the new language
// IMPORTS: nil
// EXPORTS: nil
// AUTHOR: Daniel Lee
// REMARKS: 
// LAST MODIFIED: 03-05-2006

- (IBAction) setLanguage: (id) sender;
{
    // Get data from langaugeMenu
    // Do some testing and then using BrailleGrade to do the switching.
}


// NAME: textDidChange
// PURPOSE: A delegate function to do the translation when the text is edited
// IMPORTS: NSNotification
// EXPORTS: nil
// AUTHOR: Daniel Lee
// REMARKS: 
// LAST MODIFIED: 18-05-2006

- (void) textDidChange: (NSNotification *) aNotification
{

	NSTextView *input, *output;
    NSRange range;

    // Set the input and output variables to the respective ones which are to be used
	// This is done because the code is very similar on a lot of places and that the
	// program should be a s compact as possible.

    // if the notification is coming from the inputTextView then it is the box to take
	// text from and modify
    if( [aNotification object] == inputTextView )
	{
        input = inputTextView;
        output = brailleTextView;
		translateToBraille = TRUE;
	}
	else
	{
        input = brailleTextView;
        output = inputTextView;	
		translateToBraille = FALSE;
	}

    NSTextStorage* textInputString = [input textStorage];
    NSMutableAttributedString* copiedString = ( NSMutableAttributedString* ) [textInputString mutableCopy];
	NSString* stringToCheckTags = [copiedString string];

	// Stripping tags,
	// Firstly, check the entire code and then convert sections  
	unsigned int i = 0;
    unsigned int last_Tag_Location = 0;
	unsigned int current_Tag_Location = 0;
	unsigned int lastBrailleGrade = 0;
	NSString* outputString = @"";
	
	if( [stringToCheckTags length] > 4 )   // string needs to be bigger than the tag to bother
    {
   	    // NSLog( @"Lenght : %i", [stringToCheckTags length]);

	    while( i <= ( [stringToCheckTags length] - 4) ) // i is not to close to the end
        {
	        range.location = i;    // Reusing the variable range for the tag searching
	        if( [stringToCheckTags characterAtIndex: i] == '<' )
	    	{
                range.location = i;    // Reusing the variable range for the tag searching
                range.length = 4;
                NSString *temp = [stringToCheckTags substringWithRange: range];

    			if( [temp isEqualToString: @"<g0>" ] )
	    		{
	    			current_Tag_Location = i + 4;    // End of the tag
                    range.location = last_Tag_Location;
			    	range.length = current_Tag_Location - last_Tag_Location - 4;    // To remove the tag
				
    				// Get substring from the text
	    			NSString* translationString = [stringToCheckTags substringWithRange: range];
	    			outputString = [outputString stringByAppendingString: [translatorObject translateLine: translationString grade: lastBrailleGrade]];

			        // Done last
			        last_Tag_Location = i + 4;    // To show the end of the tag
    				lastBrailleGrade = 0;
	    		}
		    	else if( [temp isEqualToString: @"<g1>" ] )
			    {
			    	current_Tag_Location = i + 4;    // End of the tag
				
                    range.location = last_Tag_Location;
			    	range.length = current_Tag_Location - last_Tag_Location - 4;    // To remove the tag
                
	    			// Get substring from the text
		    		NSString* translationString = [stringToCheckTags substringWithRange: range];
	    			outputString = [outputString stringByAppendingString: [translatorObject translateLine: translationString grade: lastBrailleGrade]];

		    	    // Done last
			        last_Tag_Location = i + 4;    // To show the end of the tag
				    lastBrailleGrade = 1;
    			}
	    		else if( [temp isEqualToString: @"<g2>" ] )
                {
			    	current_Tag_Location = i + 4;    // End of the tag
				
                    range.location = last_Tag_Location;
			    	range.length = current_Tag_Location - last_Tag_Location - 4;    // To remove the tag
                
	    			// Get substring from the text
		    		NSString* translationString = [stringToCheckTags substringWithRange: range];
	    			outputString = [outputString stringByAppendingString: [translatorObject translateLine: translationString grade: lastBrailleGrade]];

		    	    // Done last
			        last_Tag_Location = i + 4;    // To show the end of the tag
				    lastBrailleGrade = 2;
			    }
		    }
		    i++;
		}    // End of while loop

		// NSLog( @"End of tag checks" );
	
    	// Catch the last section of text which hasn't been translated yet
	    if( last_Tag_Location < [stringToCheckTags length] )    // If there isn't a tag at the end
    	{
	        range.location = last_Tag_Location;
		    range.length = [stringToCheckTags length] - last_Tag_Location;
		    // NSLog( @"Tag: %i length: %i", range.location, range.length );

            NSString* lastBit = [stringToCheckTags substringWithRange: range];
			outputString = [outputString stringByAppendingString: [translatorObject translateLine: lastBit grade: lastBrailleGrade]];
		}
    }
	else    // [stringToCheckTags length] < 4
	{
	    // NSLog( @"Grade 0 Assumed" );
		outputString = [outputString stringByAppendingString: [translatorObject translateLine: outputString grade: lastBrailleGrade]];
	}


    // Output to braille and ascii
	[output setString: outputString];
    [asciiTextView setString: outputString];

}


@end
