/* FSNTextCell.m
 *
 * Copyright (C) 2004-2021 Free Software Foundation, Inc.
 *
 * Authors: Enrico Sersale <enrico@imago.ro>
 *          Riccardo Mottola <rm@gnu.org>
 * Date: March 2004
 *
 * This file is part of the GNUstep FSNode framework
 *
 * 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., 31 Milk Street #960789 Boston, MA 02196 USA.
 */

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import "FSNTextCell.h"
#import "FSNFunctions.h"
#import "FSNMetadataProvider.h"
#import "FSNodeRep.h"


@implementation FSNTextCell

- (void)dealloc
{
  RELEASE (uncutTitle);
  RELEASE (fontAttr);
  RELEASE (dots);
  RELEASE (icon);
  RELEASE (displayIcon);
  RELEASE (tagColor);
  RELEASE (nodePath);
  [super dealloc];
}

/*
 * Build an icon image with the label coloured dot composited
 * directly onto it. Because the badge is part of the image
 * pixels it can never be obscured by selection highlights
 * or any later drawing.
 */
- (void)rebuildDisplayIcon
{
  DESTROY (displayIcon);

  if (icon == nil)
    return;

  if (tagColor == nil)
    {
      displayIcon = [icon retain];
      return;
    }

  NSSize sz = [icon size];
  displayIcon = [[NSImage alloc] initWithSize: sz];
  [displayIcon lockFocus];
  [icon compositeToPoint: NSZeroPoint operation: NSCompositeSourceOver];

  CGFloat dotSize = (sz.width >= 48) ? 10.0 : 8.0;
  CGFloat dotMargin = 2.0;
  CGFloat dotTop = (sz.width >= 48) ? dotMargin : 12.0;
  NSRect dotRect = NSMakeRect(sz.width - dotSize - dotMargin,
                               dotTop, dotSize, dotSize);

  FSNDrawLabelDot(dotRect, tagColor);

  [displayIcon unlockFocus];
}

- (id)init
{
  self = [super init];

  if (self)
    {
      ASSIGN (fontAttr, [NSDictionary dictionaryWithObject: [self font]
					      forKey: NSFontAttributeName]);
      ASSIGN (dots, @"...");
      titlesize = NSMakeSize(0, 0);
      icon = nil;
      displayIcon = nil;
      dateCell = NO;
    }

  return self;
}

- (id)copyWithZone:(NSZone *)zone
{
  FSNTextCell *c = [super copyWithZone: zone];

  c->fontAttr = [fontAttr copyWithZone: zone];
  c->dots = [dots copyWithZone: zone];

  c->dateCell = dateCell;

  if (uncutTitle) {
    c->uncutTitle = [uncutTitle copyWithZone: zone];
  } else {
    c->uncutTitle = nil;
  }

  c->icon = [icon retain];
  c->displayIcon = [displayIcon retain];
  c->tagColor = [tagColor retain];
  c->nodePath = [nodePath retain];

  return c;
}

- (void)setStringValue:(NSString *)aString
{
  [super setStringValue: aString];
  titlesize = [[self stringValue] sizeWithAttributes: fontAttr];
}

- (void)setFont:(NSFont *)fontObj
{
  [super setFont: fontObj];
  ASSIGN (fontAttr, [NSDictionary dictionaryWithObject: [self font]
                                                forKey: NSFontAttributeName]);
  titlesize = [[self stringValue] sizeWithAttributes: fontAttr];
}

- (void)setIcon:(NSImage *)icn
{
  ASSIGN (icon, icn);
  [self rebuildDisplayIcon];
}

- (NSImage *)icon
{
  return icon;
}

- (void)setTagColor:(NSColor *)color
{
  ASSIGN (tagColor, color);
  [self rebuildDisplayIcon];
}

- (NSColor *)tagColor
{
  return tagColor;
}

- (void)setNodePath:(NSString *)path
{
  ASSIGN (nodePath, path);
}

- (float)uncutTitleLenght
{
  return titlesize.width;
}

- (void)setDateCell:(BOOL)value
{
  dateCell = value;
}

- (BOOL)isDateCell
{
  return dateCell;
}

- (NSString *)cutTitle:(NSString *)title
            toFitWidth:(float)width
{
  int tl = [title length];

  if (tl <= 5)
    {
      return dots;
    }
  else
    {
      int fpto = (tl / 2) - 2;
      int spfr = fpto + 3;
      NSString *fp = [title substringToIndex: fpto];
      NSString *sp = [title substringFromIndex: spfr];
      NSString *dotted = [NSString stringWithFormat: @"%@%@%@", fp, dots, sp];
      int dl = [dotted length];
      float dotl = [dotted sizeWithAttributes: fontAttr].width;
      int p = 0;

      while (dotl > width) {
        if (dl <= 5) {
          return dots;
        }

        if (p) {
          fpto--;
        } else {
          spfr++;
        }
        p = !p;

        fp = [title substringToIndex: fpto];
        sp = [title substringFromIndex: spfr];
        dotted = [NSString stringWithFormat: @"%@%@%@", fp, dots, sp];
        dotl = [dotted sizeWithAttributes: fontAttr].width;
        dl = [dotted length];
      }

      return dotted;
    }

  return title;
}

- (NSString *)cutDateTitle:(NSString *)title
                toFitWidth:(float)width
{
  NSUInteger tl = [title length];

  if (tl <= 5)
    {
      return dots;
    }
  else
    {
      NSString *format = @"%b %d %Y";
      NSCalendarDate *date = [NSCalendarDate dateWithString: title
                                             calendarFormat: format];
      if (date)
        {
          NSString *descr;

          format = @"%m/%d/%y";
          descr = [date descriptionWithCalendarFormat: format
                                             timeZone: [NSTimeZone localTimeZone] locale: nil];

          if ([descr sizeWithAttributes: fontAttr].width > width) {
            return [self cutTitle: descr toFitWidth: width];
          } else {
            return descr;
          }

        }
      else
        {
          return [self cutTitle: title toFitWidth: width];
        }
    }

  return title;
}

- (void)drawInteriorWithFrame:(NSRect)cellFrame
                       inView:(NSView *)controlView
{
  NSRect title_rect = cellFrame;
  CGFloat textlength;
  NSString *cutTitle;

#define LEFT_MARGIN (2.0)
#define ICON_TEXT_SPACING (8.0)

  textlength = title_rect.size.width - LEFT_MARGIN;
  if (icon)
    textlength -= ([icon size].width + ICON_TEXT_SPACING);

  ASSIGN (uncutTitle, [self stringValue]);
  cutTitle = nil;
  if ([uncutTitle sizeWithAttributes: fontAttr].width > textlength)
    {
      if (dateCell)
        cutTitle = [self cutDateTitle:uncutTitle toFitWidth:textlength];
      else
        cutTitle = [self cutTitle:uncutTitle toFitWidth:textlength];
      [self setStringValue: cutTitle];
    }
  else
    {
      [self setStringValue: uncutTitle];
    }

  title_rect.size.height = titlesize.height;
  title_rect.origin.y += ((cellFrame.size.height - titlesize.height) / 2.0);

  if (icon == nil) {
    [super drawInteriorWithFrame: title_rect inView: controlView];
  } else {
    NSRect icon_rect;

    icon_rect.origin = cellFrame.origin;
    icon_rect.size = [icon size];
    icon_rect.origin.x += LEFT_MARGIN;
    icon_rect.origin.y += ((cellFrame.size.height - icon_rect.size.height) / 2.0);
    if ([controlView isFlipped]) {
      icon_rect.origin.y += icon_rect.size.height;
    }

    title_rect.origin.x += (icon_rect.size.width + ICON_TEXT_SPACING);
    title_rect.size.width -= (icon_rect.size.width + ICON_TEXT_SPACING);
    title_rect = NSIntegralRect(title_rect);

    [super drawInteriorWithFrame: title_rect inView: controlView];

    /* Lazily load tag colour from the metadata provider if not already set */
    if (tagColor == nil && nodePath != nil)
      {
        NSColor *color = [[[FSNodeRep sharedInstance] metadataProvider]
                           labelColorForPath: nodePath];
        if (color)
          [self setTagColor: color];
      }

    /* Draw the (possibly badged) icon. If a label is set the icon
     * already has the badge baked into its pixels. */
    [displayIcon compositeToPoint: icon_rect.origin
			operation: NSCompositeSourceOver];
  }

  /* we reset the title to the orginal string */
  if (cutTitle)
    [self setStringValue: uncutTitle];
}

- (BOOL)startTrackingAt:(NSPoint)startPoint inView:(NSView *)controlView
{
  return NO;
}

@end
