/*
 * DiffTextView.m
 *
 * Copyright (c) 2002 Pierre-Yves Rivaille <pyrivail@ens-lyon.fr>
 *
 * This file is part of EasyDiff.app.
 *
 * EasyDiff.app 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.
 *
 * EasyDiff.app 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 EasyDiff.app; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */


#import "DiffTextView.h"
#include <math.h>

static NSRect rectsToFill[500];

@implementation DiffTextView

- (id) initWithFrame: (NSRect) aRect
{
  [super initWithFrame: aRect];

  lineRangesArray = nil;
  blockCharacterRangesArray = [[NSMutableArray alloc] init];
  blockRectsArray = NSZoneMalloc([self zone], sizeof(NSRect)*10);
  blockRectsArraySize = 10;
  blockRectsArrayFirstFree = 0;
  lastLine = 0;
  firstCharOfLastLine = 0;

  [self setEditable: NO];
  [self setSelectable: NO];
  [self setDrawsBackground: NO];

  return self;
}

- (void) setChanges: (NSArray *)anArray
{
  if (changes)
    RELEASE(changes);
  changes = RETAIN(anArray);
  
}

- (void) computeLineRangesFromUpTo: (int) number
{
  NSArray *array;
  int count;
  int realEnd;

  NSLayoutManager *lm = [self layoutManager];
  NSTextContainer *tc = [self textContainer];


  array = changes;

  count = [array count];

  //  NSLog(@"%d", count);
  {
    NSString *internalString = [self string];
    int startLine;
    int endLine;
    int currentLine;
    int firstCharOfLine = firstCharOfLastLine;
    int firstCharOfNextLine;
    int len = [internalString length];
    int i, j;
    int a, b;

    currentLine = lastLine;
    for (i = 0; i < count; i += 2)
      {
	startLine = [[array objectAtIndex: i] intValue];
	endLine = [[array objectAtIndex: i+1] intValue] - 1;

	while (currentLine < startLine)
	  {
	    [internalString getLineStart: NULL
			    end: &firstCharOfNextLine
			    contentsEnd: NULL
			    forRange: NSMakeRange(firstCharOfLine, 0)];
	    currentLine ++;
	    firstCharOfLine = firstCharOfNextLine;
	  }

	a = firstCharOfLine;
	[blockCharacterRangesArray 
	  addObject: [NSNumber numberWithInt: firstCharOfLine]];
			
	while (currentLine <= endLine)
	  {
	    [internalString getLineStart: NULL
			    end: &firstCharOfNextLine
			    contentsEnd: NULL
			    forRange: NSMakeRange(firstCharOfLine, 0)];
	    currentLine ++;
	    firstCharOfLine = firstCharOfNextLine;
	  }

	b = firstCharOfLine - 1;

	[blockCharacterRangesArray 
	   addObject: [NSNumber numberWithInt: firstCharOfLine - 1]];

	//	NSLog(@"%d %d", blockRectsArraySize, blockRectsArrayFirstFree);
	if (blockRectsArraySize == blockRectsArrayFirstFree)
	  {
	    blockRectsArray = 
	      NSZoneRealloc([self zone], 
			    blockRectsArray,
			    blockRectsArraySize * 2 * sizeof(NSRect));
	    blockRectsArraySize *= 2;
	  }

	//	NSLog(@"a=%d b=%d", a, b);

	if (a > b)
	  {
	    blockRectsArray[blockRectsArrayFirstFree++] =
	      [lm boundingRectForGlyphRange:
		    [lm glyphRangeForCharacterRange:
			  NSMakeRange(a, a)
			actualCharacterRange:NULL]
		  inTextContainer:tc];
	    blockRectsArray[blockRectsArrayFirstFree - 1].size.height =
	      2;
	    blockRectsArray[blockRectsArrayFirstFree - 1].origin.y--;
	  }
	else
	  {
	    blockRectsArray[blockRectsArrayFirstFree++] =
	      [lm boundingRectForGlyphRange:
		    [lm glyphRangeForCharacterRange:
			  NSMakeRange(a, b - a)
			actualCharacterRange:NULL]
		  inTextContainer:tc];
	  }


	//	NSLog(@"%@", NSStringFromRect
	//	      (blockRectsArray[blockRectsArrayFirstFree-1]));

      }

    firstCharOfLastLine = firstCharOfLine;
    lastLine = currentLine;

    
    //    NSLog(@"%d %@", [blockCharacterRangesArray count],
    //	  [blockCharacterRangesArray description]);
  }
  
}

- (void) computeAllLineRanges
{
  NSString *internalString = [self string];
  int end;
  int len = [internalString length];

  lineRangesArray = [[NSMutableArray alloc] init];
  [lineRangesArray addObject:
		     [NSNumber numberWithInt: -1]];

  end = -1;
  while (end < len - 1)
    {
      [internalString getLineStart: NULL
		      end: NULL
		      contentsEnd: &end
		      forRange: NSMakeRange(end + 1, 0)];
      if (end >= len)
	{
	  [lineRangesArray addObject: 
			     [NSNumber numberWithInt: len - 1]];
	}
      else
	{
	  [lineRangesArray addObject: 
			     [NSNumber numberWithInt: end]];
	}
    }
}

- (NSRange) lineRangesForRect: (NSRect) aRect
{
  int i, count;
  int startLine = -1;
  int endLine = -1;

  NSRange glyphRange, characterRange;
  NSLayoutManager *lm = [self layoutManager];
  NSTextContainer *tc = [self textContainer];
  
  glyphRange = [lm glyphRangeForBoundingRect: aRect
		   inTextContainer: tc];
  characterRange = [lm characterRangeForGlyphRange: glyphRange
		       actualGlyphRange: NULL];
  
  count = [lineRangesArray count];
  i = 0;
  while (i < count)
    {
      if ((int) characterRange.location <=
	  [[lineRangesArray objectAtIndex: i] intValue] + 1)
	{
	  startLine = i;
	  break;
	}
      i++;
    }

  while (i < count)
    {
      if ((int) NSMaxRange(characterRange) <=
	  [[lineRangesArray objectAtIndex: i] intValue] + 1)
	{
	  endLine = i;
	  break;
	}
      i++;
    }

  /*
  NSLog(@"glyphRange    : %@", NSStringFromRange(glyphRange));
  NSLog(@"characterRange: %@", NSStringFromRange(characterRange));
  */

  return NSMakeRange(startLine, endLine - startLine);
}

/*
- (void) highlightLinesInRange: (NSRange)aRange
{
  unsigned end;
  unsigned len = [string length];

  end = -1;
  for (i = 0; i < aRange.start; i++)
    {
      [string getLineStart: nil
	      end: nil
	      contentsEnd: &end
	      forRange: NSMakeRange(end + 1, 0)];
    }
}
*/

- (void) drawRect: (NSRect) aRect
{
  int i = 0;
  int j = 0;
  int temp;
  int length;
  int state = 0;
  NSMutableArray *rectArray = [[NSMutableArray alloc] init];
  NSString *string;
  NSRange glyphRange, characterRange;
    
  //  NSLog(@"%@", NSStringFromRect(aRect));
  NSRange range;

  {
    NSLayoutManager *lm = [self layoutManager];
    NSTextContainer *tc = [self textContainer];

    glyphRange = [lm glyphRangeForBoundingRect:aRect
		     inTextContainer: tc];
    characterRange = [lm characterRangeForGlyphRange: glyphRange
			 actualGlyphRange: NULL];
    /*
    NSLog(@"glyphRange    : %@", NSStringFromRange(glyphRange));
    NSLog(@"characterRange: %@", NSStringFromRange(characterRange));
    */
  }

  string = [self string];
  length = [string length];

  [[NSColor whiteColor] set];

  range.location = 0;
  range.length = 0;


  {
    NSLayoutManager *lm = [self layoutManager];
    NSTextContainer *tc = [self textContainer];

    int i = 0;
    int j = 0;
    int count = [blockCharacterRangesArray count];
    int charStart, charEnd;

    for (i = 0; i < count; i += 2)
      {
	charStart = [[blockCharacterRangesArray objectAtIndex: i]
		      intValue];
	charEnd = [[blockCharacterRangesArray objectAtIndex: i+1]
		    intValue];
	if (charEnd >= characterRange.location)
	  {
	    break;
	  }
      }
    
    for (; i < count; i += 2)
      {
	charStart = [[blockCharacterRangesArray objectAtIndex: i]
		      intValue];
	charEnd = [[blockCharacterRangesArray objectAtIndex: i+1]
		    intValue];
	if (charStart > NSMaxRange(characterRange))
	  {
	    break;
	  }

	blockRectsArray[i/2].size.width = aRect.size.width;
	blockRectsArray[i/2].origin.x = aRect.origin.x;
	//	NSLog(@"rect %@", NSStringFromRect(blockRectsArray[i/2]));
	rectsToFill[j++] =
	  NSIntersectionRect(aRect,
			     blockRectsArray[i/2]);

      }
    NSRectFillList(rectsToFill, j);

  }

  [super drawRect: aRect];
}

- (void) superviewFrameChanged: (NSNotification *)aNotification
{
  NSSize size;
  float superWidth, selfWidth;

  superWidth = [self convertRect: [_super_view bounds]
	       fromView: _super_view].size.width;
  selfWidth = [_layoutManager 
		usedRectForTextContainer: _textContainer].size.width;

  if (superWidth > selfWidth)
    size.width = superWidth;
  else
    size.width = selfWidth;

  size.height = [self frame].size.height;

  [self setFrameSize: size];
}
@end


