/*
   GNUstep ProjectCenter - http://www.gnustep.org

   Copyright (C) 2000-2002 Free Software Foundation

   Authors: Philippe C.D. Robert

   This file is part of GNUstep.

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This application is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "PCEditorView.h"
#include "PCDefines.h"
#include "PCEditorView+Highlighting.h"

#define SCANLOC [scanner scanLocation]

@implementation PCEditorView (Highlighting)

static NSColor *commentColor = nil;
static NSColor *keywordColor = nil;
static NSColor *cppCommentColor = nil;
static NSColor *stringColor = nil;
static NSColor *cStringColor = nil;
static NSFont *editorFont = nil;

+ (void)initialize
{
    static BOOL initialised = NO;

    if( !initialised )
    {
        initialised = YES;

#define CALIBRATED_COL(r, g, b, a) RETAIN([NSColor colorWithCalibratedRed:r green:g blue:b alpha:a]);
	commentColor = CALIBRATED_COL(0.0,0.5,0.0,1.0);
	keywordColor = CALIBRATED_COL(0.0,0.5,0.0,1.0);
	cppCommentColor = CALIBRATED_COL(0.8,0.0,0.0,1.0);
	stringColor = CALIBRATED_COL(0.0,0.0,0.8,1.0);
	cStringColor = CALIBRATED_COL(0.0,0.0,0.8,1.0);
	editorFont = RETAIN([NSFont userFixedPitchFontOfSize:12]);
#undef CALIBRATED_COL
    }
}

- (void)colouriseStrings
{
  BOOL foundRange;
  id aDict = [NSDictionary dictionaryWithObjectsAndKeys:
			     stringColor, NSForegroundColorAttributeName,
			   @"StringConstantCodeType", @"PCCodeTypeAttributeName", nil ];

  [scanner setScanLocation:0];
  
  while( ![scanner isAtEnd] )  {
    foundRange = NO;

    [scanner scanUpToString:@"\"" intoString:NULL];
    range.location = SCANLOC;
    [scanner scanString:@"\"" intoString:NULL];
      
    if( ![scanner isAtEnd] &&
	range.location > 0 &&
	[[_textStorage string] characterAtIndex:(SCANLOC - 2)] == '@' ) {
      range.location -= 1;
    }

    while( ![scanner isAtEnd] ) {
      [scanner scanUpToString:@"\"" intoString:NULL];
      [scanner scanString:@"\"" intoString:NULL];
      
      // If there is no escape char before then we are done..
      
      if( [[scanner string] characterAtIndex:(SCANLOC - 2)] != '\\' ||
	  [[scanner string] characterAtIndex:(SCANLOC - 3)] == '\\' ) {
	range.length = SCANLOC - range.location;
	foundRange = YES;
	break;
      }      
    }

    if( foundRange ) {
      NS_DURING
	[_textStorage addAttributes:aDict range:range];
      NS_HANDLER
	NSLog(@"<%@ %x> raised (-scanForStrings):\n%@",[self class],self,[localException description]);
      NS_ENDHANDLER
    }
  }
}

- (void)colouriseCharStrings
{
  BOOL foundRange;
  id aDict = [NSDictionary dictionaryWithObjectsAndKeys:
			     cStringColor,NSForegroundColorAttributeName,
			   @"StringConstantCodeType", @"PCCodeTypeAttributeName", nil ];
  
  [scanner setScanLocation:0];

  while( ![scanner isAtEnd] ) {
    foundRange = NO;
    [scanner scanUpToString:@"'" intoString:NULL];
    range.location = SCANLOC;
    [scanner scanString:@"'" intoString:NULL];
      
    while( ![scanner isAtEnd] ) {
      [scanner scanUpToString:@"'" intoString:NULL];
      [scanner scanString:@"'" intoString:NULL];
      
      // No escape => we are done! (ugly hack...)	  
      if( [[scanner string] characterAtIndex:(SCANLOC - 2)] != '\\' ||
	  [[scanner string] characterAtIndex:(SCANLOC - 3)] == '\\' ) {

	range.length = SCANLOC - range.location;

	// Ranges are not longer than 8 chars! (ugly hack...)	
	if( range.length > 8 ) {
	  [scanner setScanLocation:SCANLOC - 1];
	}
	else {
	  foundRange = YES;
	}
	break;
      }  
    }

    if( foundRange ) {
      NS_DURING
	[_textStorage addAttributes:aDict range:range];
      NS_HANDLER
	NSLog(@"<%@ %x> raised (-colouriseCharStrings):\n%@",[self class],self,[localException description]);
      NS_ENDHANDLER
    }
  }
}

- (void)colouriseComments
{
  NSRange tmpRange;
  BOOL foundRange;
  id aDict = [NSDictionary dictionaryWithObjectsAndKeys:
			     commentColor,NSForegroundColorAttributeName,
			   @"CommentCodeType", @"PCCodeTypeAttributeName", 
			   nil ];

  [scanner setScanLocation:0];
  
  while( ![scanner isAtEnd] ) {
    foundRange = NO;
      
    while( ![scanner isAtEnd] ) {
      [scanner scanUpToString:@"/*" intoString:NULL];
      range.location = SCANLOC;
      [scanner scanString:@"/*" intoString:NULL];
      
      if(![scanner isAtEnd] &&
	 [[_textStorage attribute:@"PCCodeTypeAttributeName"
			atIndex:range.location
			effectiveRange:&tmpRange] isEqual:@"UnknownCodeType"]){
	foundRange = YES;
	break;
      }
    }  
 
    [scanner scanUpToString:@"*/" intoString:NULL];
    [scanner scanString:@"*/" intoString:NULL];
    range.length = SCANLOC - range.location;
    
    if( foundRange ) {
      NS_DURING
	/*
	 * BIG HACK!!!
	 */
	if (range.location == 0) {range.location = 1;range.length--;}
        [_textStorage addAttributes:aDict range:range];
      NS_HANDLER
	NSLog(@"<%@ %x> raised (-colouriseComments):\n%@",[self class],self,[localException description]);
      NS_ENDHANDLER
    }
  }
}

- (void)colouriseCPPComments
{
  NSRange tmpRange;
  BOOL foundRange;
  id aDict = [NSDictionary dictionaryWithObjectsAndKeys:
			    cppCommentColor, NSForegroundColorAttributeName,
			   @"CommentCodeType", @"PCCodeTypeAttributeName", nil ];
  
  [scanner setScanLocation:0];
  
  while( ![scanner isAtEnd] ) {
    foundRange = NO;
    
    while( ![scanner isAtEnd] ) {
      [scanner scanUpToString:@"//" intoString:NULL];
      range.location = SCANLOC;
      [scanner scanString:@"//" intoString:NULL];
      
      if( ![scanner isAtEnd] &&
	  [[_textStorage attribute:@"PCCodeTypeAttributeName"
			 atIndex:range.location
			 effectiveRange:&tmpRange] isEqual:@"UnknownCodeType"]){
	foundRange = YES;
	break;
      }
    }
    
    [scanner scanUpToString:@"\n" intoString:NULL];
    [scanner scanString:@"\n" intoString:NULL];
    range.length = SCANLOC - range.location;
    
    if( foundRange ) {
      NS_DURING
	[_textStorage addAttributes:aDict range:range];
      NS_HANDLER
	NSLog(@"<%@ %x> raised (-colouriseCPPComments):\n%@",[self class],self,[localException description]);
      NS_ENDHANDLER
    }
  }
}

- (void)colouriseKeyword:(NSString *)keyword
{
  NSRange tmpRange;
  
  id keywordDict = [NSDictionary dictionaryWithObjectsAndKeys:
				   keywordColor,NSForegroundColorAttributeName,
				 @"KeywordCodeType", @"PCCodeTypeAttributeName", nil ];
  
  // First scan for docu style comments
  [scanner setScanLocation:0];
  
  while( ![scanner isAtEnd] ) {
    
    [scanner scanUpToString:keyword intoString:NULL];
    range.location = SCANLOC;
    
    if( ![scanner isAtEnd] &&
	[[_textStorage attribute:@"PCCodeTypeAttributeName"
		      atIndex:range.location
		      effectiveRange:&tmpRange] isEqual:@"UnknownCodeType"] ) {
      NS_DURING
	[_textStorage addAttributes:keywordDict range:NSMakeRange( range.location, [keyword length])];
      NS_HANDLER
	NSLog(@"<%@ %x> raised (-colouriseKeyword:):\n%@",[self class],self,[localException description]);
      NS_ENDHANDLER
    }
    [scanner scanString:keyword intoString:NULL];
  }
}

- (void)colouriseKeywords:(NSArray *)keywords
{
  NSEnumerator *enumerator = [keywords objectEnumerator];
  id object;

  while ((object = [enumerator nextObject])) {
    [self colouriseKeyword:object];
  }
}

@end
