/*
    EditorRulerView.h

    Implementation of the EditorRulerView class for the
    ProjectManager application.

    Copyright (C) 2005  Saso Kiselkov

    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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

#import "EditorRulerView.h"

#import <AppKit/NSColor.h>
#import <AppKit/NSEvent.h>
#import <AppKit/NSFont.h>
#import <AppKit/NSGraphics.h>
#import <AppKit/NSScrollView.h>
#import <AppKit/NSStringDrawing.h>
#import <AppKit/NSWindow.h>
#import <AppKit/PSOperators.h>

#import <Foundation/NSKeyedArchiver.h>
#import <Foundation/NSUserDefaults.h>

#import "EditorTextView.h"

static inline float my_abs(float x)
{
  if (x >= 0)
    return x;
  else
    return -x;
}

static inline NSRect
ComputeHighlightedRect(NSRect selectionRect,
                       NSRect documentVisibleRect,
                       NSRect myRect,
                       float margin,
                       float originOffset,
                       float unitSize,
                       NSRulerOrientation orientation)
{
  if (orientation == NSHorizontalRuler)
    {
      return NSMakeRect(selectionRect.origin.x - documentVisibleRect.origin.x +
        originOffset, 0, unitSize, myRect.size.height - margin);
    }
  else
    {
      return NSMakeRect(0, selectionRect.origin.y -
        documentVisibleRect.origin.y + originOffset,
        myRect.size.width - margin, unitSize);
    }
}

@implementation EditorRulerView

- (void) dealloc
{
  TEST_RELEASE(highlightColor);

  [super dealloc];
}

- initWithScrollView: (NSScrollView *) sv
         orientation: (NSRulerOrientation) or
{
  if ([super initWithScrollView: sv orientation: or])
    {
      NSUserDefaults * df = [NSUserDefaults standardUserDefaults];
      NSData * data;

      data = [df dataForKey: @"RulerHighlightColor"];
      if (data == nil || (highlightColor = [NSKeyedUnarchiver
        unarchiveObjectWithData: data]) == nil)
        {
          highlightColor = [NSColor colorWithCalibratedRed: 0.6
                                                     green: 0.6
                                                      blue: 1.0
                                                     alpha: 1.0];
        }
      [highlightColor retain];

      return self;
    }
  else
    {
      return nil;
    }
}

- (void) drawRect: (NSRect) r
{
  NSRect visibleRect = [[self enclosingScrollView] documentVisibleRect];
  NSFont * font = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
  NSDictionary * attrs = [NSDictionary
    dictionaryWithObject: font forKey: NSFontAttributeName];
  NSRect myFrame = [self frame];
  float thickness = [self ruleThickness] - margin;
  float originOffset = [self originOffset];

  [[NSColor whiteColor] set];
  NSRectFill(r);

  if (unitSize <= 0)
    {
      return;
    }

  [[NSColor blackColor] set];

  highlightedRect = ComputeHighlightedRect(selectionRect,
                                           visibleRect,
                                           myFrame,
                                           margin,
                                           [self originOffset],
                                           unitSize,
                                           [self orientation]);

  if ([self orientation] == NSHorizontalRuler)
    {
      int start, i, length;

      start = NSMinX(visibleRect);
      if (NSMinX(r) > 0)
        {
          start += NSMinX(r) - originOffset;
        }
      start /= unitSize;

      length = r.size.width / unitSize;

      PSsetgray(0.9);
      for (i=0; i <= length; i++)
        {
          if ((start + i) % 5 == 0)
            {
              NSRectFill(NSMakeRect(((start+i) * unitSize) - visibleRect.origin.x +
                originOffset, 0, unitSize, thickness));
            }
          else
            {
              PSmoveto(((start+i) * unitSize) - visibleRect.origin.x +
                originOffset, 0);
              PSrlineto(0, thickness);
              PSstroke();
            }
        }

      if (!NSEqualRects(selectionRect, NSZeroRect))
        {
          [highlightColor set];
          NSRectFill(highlightedRect);
        }

      PSsetgray(0.0);
      for (i = -(start % 5); i <= length; i += 5)
        {
          NSAttributedString * string = [[[NSAttributedString alloc]
            initWithString: [NSString stringWithFormat: @"%i", start + i]
                attributes: attrs]
            autorelease];

          [string drawAtPoint:
            NSMakePoint((((start + i) * unitSize) + 1) - visibleRect.origin.x +
            originOffset, 3)];
        }

      [[NSColor lightGrayColor] set];
      PSmoveto(NSMinX(r), thickness - 1);
      PSrlineto(r.size.width, 0);
      PSstroke();
    }
  else
    {
      int start, i, length;

      start = NSMinY(visibleRect);
      if (NSMinY(r) > 0)
        {
          start += NSMinY(r) - originOffset;
        }
      start /= unitSize;

      length = r.size.height / unitSize;

      for (i = 0; i <= length; i++)
        {
          NSAttributedString * string = [[[NSAttributedString alloc]
            initWithString: [NSString stringWithFormat: @"%i", start + i + 1]
                attributes: attrs]
            autorelease];
          NSSize s;

          if (NSPointInRect(NSMakePoint(myFrame.size.width / 2,
                                        ((start + i) * unitSize) -
                                        visibleRect.origin.y +
                                        originOffset + unitSize / 2),
                            highlightedRect))
            {
              [highlightColor set];
              NSRectFill(highlightedRect);
            }
          else if ((start + i) % 2)
            {
              PSsetgray(0.9);
              PSrectfill(0, ((start + i) * unitSize) - visibleRect.origin.y +
                originOffset, thickness, unitSize);
            }

          PSsetgray(0.0);
          s = [string size];
          [string drawAtPoint: NSMakePoint(2,
            (((start + i) * unitSize) + unitSize / 2 - s.height / 2) -
            visibleRect.origin.y + originOffset)];
        }

      [[NSColor lightGrayColor] set];
      PSmoveto(thickness - 1, NSMinY(r));
      PSrlineto(0, r.size.height);
      PSstroke();
    }
}

- (void) mouseDown: (NSEvent *) ev
{
  EditorGuideStyle style;
  int flags = [ev modifierFlags];

  if ((flags & NSShiftKeyMask) && (flags & NSControlKeyMask))
    style = DottedGuideStyle;
  else if (flags & NSShiftKeyMask)
    style = SolidGuideStyle;
  else if (flags & NSControlKeyMask)
    style = DashedGuideStyle;
  else
    style = AnyGuideStyle;

  // should we start dragging a guide?
  ev = [[self window] nextEventMatchingMask: NSAnyEventMask];
  if ([ev type] == NSLeftMouseDragged)
    {
      [(EditorTextView *) [[self enclosingScrollView] documentView]
        createAndBeginDraggingNewGuide:
        ([self orientation] == NSHorizontalRuler)
                             withStyle: style];
    }
}

- (void) setUnitSize: (float) aSize
{
  unitSize = aSize;
  [self setNeedsDisplay: YES];
}

- (float) unitSize
{
  return unitSize;
}

- (void) refreshHighlightedArea
{
  NSRect visibleRect = [[self enclosingScrollView] documentVisibleRect];
  NSRect myFrame = [self frame];
  id documentView;

  if (!NSEqualRects(selectionRect, NSZeroRect))
    {
      [self setNeedsDisplayInRect: highlightedRect];
    }

  documentView = [[self enclosingScrollView] documentView];
  if ([documentView respondsToSelector: @selector(selectionRect)])
    {
      selectionRect = [documentView selectionRect];
    }
  else
    {
      selectionRect = NSZeroRect;
    }

  if (!NSEqualRects(selectionRect, NSZeroRect))
    {
      highlightedRect = ComputeHighlightedRect(selectionRect,
                                               visibleRect,
                                               myFrame,
                                               margin,
                                               [self originOffset],
                                               unitSize,
                                               [self orientation]);

      [self setNeedsDisplayInRect: highlightedRect];
    }
}

/**
 * Adds a margin to the right side (if the ruler is vertical) or bottom
 * side (if the ruler is horizontal). This is added to the ruler's
 * thickness automatically.
 */
- (void) setMargin: (float) aMargin
{
  float originalThickness = [self ruleThickness] - margin;

  margin = aMargin;

  [self setRuleThickness: originalThickness + margin];
}

- (float) margin
{
  return margin;
}

@end
