/*
**  CEView+BlockMarking.m
**
**  Copyright (c) 2002, 2003
**
**  Author: Yen-Ju Chen <yjchenx@hotmail.com>
**          Bjoern Giesler <bjoern@giesler.de>
**
**  This program 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 program 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 General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this program; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

// #include <ctype.h>
#include "CodeEditorViewPreference.h"
#include "CEView+BlockMarking.h"
#include "CEView+TextUtils.h"
#include "CodeParser.h"
#include "FontificationHandler.h"
#include "BlockHandler.h"
#include "BundleLoader.h"
#include <AppKit/AppKit.h>

@implementation CodeEditorView (BlockMarking)

- (void)unmarkPreviouslyMarkedBlock
{
  NSRange effRange;
  id attr;

  hasSideMarked = NO;
  fontifying = YES;

  // Did we have something marked before?
  if(markedStartRange.location != NSNotFound)
    {
      attr = [[self textStorage]
	       attribute: NSBackgroundColorAttributeName
	       atIndex: markedStartRange.location
	       effectiveRange: &effRange];

      [[self textStorage] beginEditing];

      [[self textStorage]
	removeAttribute: NSBackgroundColorAttributeName
	range: effRange];

      if(startColor)
	{
	  [[self textStorage] 
	    addAttribute: NSBackgroundColorAttributeName
	    value: startColor
	    range: markedStartRange];
	}

      [[self textStorage] endEditing];
      markedStartRange.location = NSNotFound;
    }

  if(markedEndRange.location != NSNotFound)
    {
      attr = [[self textStorage]
	       attribute: NSBackgroundColorAttributeName
	       atIndex: markedEndRange.location
	       effectiveRange: &effRange];

      [[self textStorage] beginEditing];

      [[self textStorage]
	removeAttribute: NSBackgroundColorAttributeName
	range: effRange];

      if(endColor)
	{
	  [[self textStorage] 
	    addAttribute: NSBackgroundColorAttributeName
	    value: endColor
	    range: markedEndRange];
	}

      [[self textStorage] endEditing];

      markedEndRange.location = NSNotFound;
    }

  lastMarkedRange.location = NSNotFound;
  fontifying = NO;
}

- (void)findAndMarkBlockAtPosition: (int)position
{
  NSString *wordAtCursor; 
  NSRange wordAtCursorRange;
  NSRange beginRange, endRange;
  BOOL found;
  NSRange inRange;
  CodeParser *parser;
  id <BlockHandler> handler;
  unsigned int index;
  NSRect beginRect, endRect;

  NSLog(@"findAndMarkBlockAtPosition");
  // Is the cursor at a block delimiter?

  wordAtCursor = [self wordAtPosition: position inRange: &wordAtCursorRange];

  if(wordAtCursorRange.location == NSNotFound)
    return;
  if((wordAtCursorRange.location == lastMarkedRange.location) &&
     (wordAtCursorRange.length == lastMarkedRange.length))
    return;

  lastMarkedRange = wordAtCursorRange;

  found = NO;

  /* Use CodeParser */

  index = [bundleLanguages indexOfObject: languageName];
  if (index == NSNotFound)
    return;

  if (blockHandlerClass)
    {
      handler = [[blockHandlerClass alloc] init];
      if (handler == nil) 
        {
          NSLog(@"Can't load block handler");
          return;
        }
    }
  else
    {
      return;
    }

  [handler setDelimiter: wordAtCursor];

  if([handler searchBackward: wordAtCursor])
    {
      /* Backward search */
      position = 0;
      inRange = NSMakeRange(position, wordAtCursorRange.location);
      endRange = wordAtCursorRange;
      [handler setBackward: YES];
    }
  else
    {
      /* Forward search */
      position = NSMaxRange(wordAtCursorRange);
      inRange = NSMakeRange(position, [[self string] length] - position);
      beginRange = wordAtCursorRange;
      [handler setBackward: NO];
    }

  parser = [[CodeParser alloc] initWithCodeHandler: handler
                               withString: [[self string] substringWithRange:inRange ]];
  NSLog(@"BlockMarking parse begin");
  [parser parse];
  NSLog(@"BlockMarking parse end");

  if([handler searchBackward: wordAtCursor])
    {
      /* Backward search */
      beginRange = [handler result];
      if (beginRange.location != NSNotFound)
        found = YES;
    }
  else
    {
      /* Forward search */
      endRange = [handler result];
      if (endRange.location != NSNotFound)
        found = YES;
      endRange.location = endRange.location+beginRange.location;

      /* Since we don't know whether the delimiter starts in comment
         or in string, we need to do a backward search.
         If the result from backward search is not the same,
         it is in comment or string */
      if (found)
        {
          NSString *endWord;
          id <BlockHandler> endHandler;
          CodeParser *endParser;
          NSRange endResult;

          endWord = [[self string] substringWithRange: endRange];
          endHandler = [[blockHandlerClass alloc] init];
          [endHandler setDelimiter: endWord];
          [endHandler setBackward: YES];
          endParser = [[CodeParser alloc] initWithCodeHandler: endHandler
                                          withString: [[self string] substringWithRange: NSMakeRange(0, endRange.location)]];
          [endParser parse];
          endResult = [endHandler result];
          if ( !NSEqualRanges(endResult, wordAtCursorRange))
            found = NO;

          RELEASE(endHandler);
          RELEASE(endParser);
        }
    }

  RELEASE(handler);
  RELEASE(parser);

  if(!found)
    {
      lastMarkedRange = NSMakeRange(0, 0);
    }
  else
    {
      NSLog(@"beginRange %@", NSStringFromRange(beginRange));
      NSLog(@"endRange %@", NSStringFromRange(endRange));
      NSLog(@"length %d", [[self textStorage] length]);

      fontifying = YES;
      ASSIGN(startColor, [[self textStorage]
                           attribute: NSBackgroundColorAttributeName
                             atIndex: beginRange.location
		      effectiveRange: (NSRange *)nil]);

      ASSIGN(endColor, [[self textStorage]  
                          attribute: NSBackgroundColorAttributeName
                            atIndex: endRange.location
                     effectiveRange: (NSRange *)nil]);

      NSLog(@"BeginEditing");
      [[self textStorage] beginEditing];
      NSLog(@"1");
      [[self textStorage] 
            addAttribute: NSBackgroundColorAttributeName
            value: [NSColor colorWithCalibratedRed: 0.5
                    green: 1
                    blue: 0.5
                    alpha: 1.0]
            range: beginRange];
      NSLog(@"2");
      [[self textStorage] 
            addAttribute: NSBackgroundColorAttributeName
            value: [NSColor colorWithCalibratedRed: 0.5
                    green: 1
                    blue: 0.5
                    alpha: 1.0]
            range: endRange];
      NSLog(@"3");
      [[self textStorage] endEditing];
      NSLog(@"End editing");

      markedStartRange = beginRange;
      markedEndRange = endRange;

      /* Calcaulte the rect for side text */
      if (hasSideTextView)
        {
          layoutManager = [self layoutManager];
          beginRect = [layoutManager lineFragmentRectForGlyphAtIndex: beginRange.location
                                                      effectiveRange: NULL];
          endRect = [layoutManager lineFragmentRectForGlyphAtIndex: endRange.location
                                                    effectiveRange: NULL];
          sideMarkedRect = NSMakeRect(0, beginRect.origin.y, 40, 
                           endRect.origin.y - beginRect.origin.y + endRect.size.height);
          hasSideMarked = YES;

          fontifying = NO;
        }
    }
}

- (void)findAndMarkBlockAtCursor
{
  [self findAndMarkBlockAtPosition: [self selectedRange].location-1];
}

@end
