//
//  TDSourceCodeTextView.m
//  TextTest
//
//  Created by Todd Ditchendorf on 9/9/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "TDSourceCodeTextView.h"
#import "TDGutterView.h"

@interface TDSourceCodeTextView ()
- (void)registerForNotifications;
- (void)getRectsOfVisibleLines:(NSArray **)outRects startingLineNumber:(NSUInteger *)outRect;
- (NSUInteger)lineNumberForIndex:(NSUInteger)inIndex;
@end

@implementation TDSourceCodeTextView

- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    self.gutterView = nil;
    [super dealloc];
}


- (void)awakeFromNib {
    [self registerForNotifications];
    [self renderGutter];
}


- (void)textDidChange:(NSNotification *)n {
    [self renderGutter];
}


- (void)viewBoundsChanged:(NSNotification *)n {
    [self renderGutter];
}


- (void)renderGutter {
    if (![[self window] isVisible]) return;
    NSArray *rects = nil;
    NSUInteger start = 0;
    [self getRectsOfVisibleLines:&rects startingLineNumber:&start];
    gutterView.lineNumberRects = rects;
    gutterView.startLineNumber = start;
    [gutterView setNeedsDisplay:YES];        
}


- (void)registerForNotifications {
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(textDidChange:)
                                                 name:NSTextDidChangeNotification
                                               object:self];
    
    [scrollView.contentView setPostsBoundsChangedNotifications:YES];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(viewBoundsChanged:)
                                                 name:NSViewBoundsDidChangeNotification
                                               object:scrollView.contentView];
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(viewBoundsChanged:)
                                                 name:NSWindowDidResizeNotification
                                               object:self.window];
}


//- (void)showFindIndicatorForRange:(NSRange)charRange;

- (void)getRectsOfVisibleLines:(NSArray **)outRects startingLineNumber:(NSUInteger *)outStart {
    NSMutableArray *result = [NSMutableArray array];
    NSString *s = self.string;
    
    NSLayoutManager *layoutMgr = self.textContainer.layoutManager;
    NSRect boundingRect = [scrollView.contentView documentVisibleRect];
    CGFloat scrollY = boundingRect.origin.y;
    NSRange visibleGlyphRange = [layoutMgr glyphRangeForBoundingRect:boundingRect inTextContainer:self.textContainer];
        
    NSUInteger index = visibleGlyphRange.location;
    NSUInteger length = index + visibleGlyphRange.length;

    (*outStart) = [self lineNumberForIndex:index + 1];
    
    while (index < length) {
        NSRange r = [s lineRangeForRange:NSMakeRange(index, 0)];
        index = NSMaxRange(r);
        NSRect rect = [layoutMgr lineFragmentRectForGlyphAtIndex:r.location effectiveRange:NULL withoutAdditionalLayout:YES];
        rect.origin.y -= scrollY;
        [result addObject:[NSValue valueWithRect:rect]];
    }
    
    (*outRects) = result;
}


- (NSUInteger)lineNumberForIndex:(NSUInteger)inIndex {
    NSString *s = self.string;
    NSUInteger numberOfLines, index, stringLength = [s length];
    
    for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++) {
        NSRange r = [s lineRangeForRange:NSMakeRange(index, 0)];
        index = NSMaxRange(r);
        if (inIndex <= index) {
            break;
        }
    }
    
    return numberOfLines;
}

@synthesize gutterView;
@end