/*
    EditorGuide.m

    Implementation of the EditorGuide 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 "EditorGuide.h"

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

#import <AppKit/NSColor.h>
#import <AppKit/PSOperators.h>

/**
 * Draws a guideline.
 *
 * @arg startPoint The point at which the line starts.
 * @arg lineSize The size of the line in each direction.
 * @arg color The color of the line.
 * @arg style Guide line style.
 */
static inline void
DrawGuideLine (NSPoint startPoint,
               NSSize lineSize,
               NSColor * color,
               EditorGuideStyle style)
{
  [color set];

  switch (style)
    {
    case AnyGuideStyle:
    case DottedGuideStyle:
      {
        float pattern[] = {1.0, 1.0};

        PSsetdash(pattern, 2, 0.0);
      }
      break;
    case DashedGuideStyle:
      {
        float pattern[] = {5.0, 5.0};

        PSsetdash(pattern, 2, 0.0);
      }
      break;
    case SolidGuideStyle:
      PSsetdash(NULL, 0, 0.0);
      break;
    }

  PSmoveto(startPoint.x, startPoint.y);
  PSrlineto(lineSize.width, lineSize.height);
  PSstroke();

  // reset the dashing back to filled
  PSsetdash(NULL, 0, 0.0);
}

/**
 * Computes the modulus of diving a and b and returns it.
 */
static inline float
float_mod(float a, float b)
{
  int x = a / b;

  return a - (x * b);
}

static inline void
ComputeDrawingStartAndLength(float originalStart,
                             float originalLength,
                             EditorGuideStyle style,
                             float * start,
                             float * length)
{
  switch (style)
    {
    case AnyGuideStyle:
    case DottedGuideStyle:
      {
        float diff = float_mod(originalStart, 2.0);

        *start = originalStart - diff;
        *length = originalLength + diff;
      }
      break;
    case DashedGuideStyle:
      {
        float diff = float_mod(originalStart, 10.0);

        *start = originalStart - diff;
        *length = originalLength + diff;
      }
      break;
    case SolidGuideStyle:
      *start = originalStart;
      *length = originalLength;
      break;
    }
}

/**
 * A guide is a line (either horizontal or vertical) which draws itself
 * inside a view at a specified offset.
 */
@implementation EditorGuide

- init
{
  if ([super init])
    {
      NSUserDefaults * df = [NSUserDefaults standardUserDefaults];
      NSData * data;

      if ((data = [df dataForKey: @"GuidelinesColor"]) == nil ||
        (color = [NSKeyedUnarchiver unarchiveObjectWithData: data]) == nil)
        {
          color = [NSColor darkGrayColor];
        }
      [color retain];

      if ((data = [df dataForKey: @"SelectedGuidelinesColor"]) == nil ||
        (selectedColor = [NSKeyedUnarchiver unarchiveObjectWithData: data])
        == nil)
        {
          selectedColor = [NSColor blueColor];
        }
      [selectedColor retain];

      style = [df integerForKey: @"GuidelinesStyle"];

      return self;
    }
  else
    {
      return nil;
    }
}

- (void) dealloc
{
  TEST_RELEASE(color);
  TEST_RELEASE(selectedColor);

  [super dealloc];
}

/**
 * Instructs the guide to draw itself in `r'.
 */
- (void) drawRect: (NSRect) r
{
  if (isHorizontal)
    {
      if (NSMinY(r) <= offset && NSMaxY(r) >= offset)
        {
          float start = 0, length = 0;

          ComputeDrawingStartAndLength(r.origin.x, r.size.width, style,
            &start, &length);

          DrawGuideLine(NSMakePoint(start, offset),
                        NSMakeSize(length, 0),
                        isSelected ? selectedColor : color,
                        style);
        }
    }
  else
    {
      if (NSMinX(r) <= offset && NSMaxX(r) >= offset)
        {
          float start = 0, length = 0;

          ComputeDrawingStartAndLength(r.origin.y, r.size.height, style,
            &start, &length);

          DrawGuideLine(NSMakePoint(offset, start),
                        NSMakeSize(0, length),
                        isSelected ? selectedColor : color,
                        style);
        }
    }
}

- (void) setOffset: (float) anOffset
{
  offset = anOffset;
}

- (float) offset
{
  return offset;
}

- (void) setHorizontal: (BOOL) flag
{
  isHorizontal = flag;
}

- (BOOL) isHorizontal
{
  return isHorizontal;
}

- (void) setSelected: (BOOL) flag
{
  isSelected = flag;
}

- (BOOL) isSelected
{
  return isSelected;
}

- (void) setGuideStyle: (EditorGuideStyle) aStyle
{
  style = aStyle;
}

- (EditorGuideStyle) guideStyle
{
  return style;
}

- (void) setColor: (NSColor *) aColor
{
  ASSIGN(color, aColor);
}

- (NSColor *) color
{
  return color;
}

@end
