/* FSNBrowserCell.m
 *  
 * Copyright (C) 2004 Free Software Foundation, Inc.
 *
 * Author: Enrico Sersale <enrico@imago.ro>
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA.
 */

#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>
#include <math.h>
#include "FSNBrowserCell.h"
#include "FSNode.h"

#define DEFAULT_ISIZE (24)
#define HLIGHT_H_FACT (0.8125)

static id <DesktopApplication> desktopApp = nil;

static NSString *dots = @"...";
static float dtslenght = 0.0;  
static NSDictionary *fontAttr = nil;

static NSFont *infoFont = nil;
static int infoheight = 0;

static SEL cutTitleSel = NULL;
static cutIMP cutTitle = NULL;


@implementation FSNBrowserCell

- (void)dealloc
{
  TEST_RELEASE (selection);
  TEST_RELEASE (selectionTitle);
  TEST_RELEASE (uncuttedTitle);
  TEST_RELEASE (extInfoType);
  TEST_RELEASE (infoCell); 
  TEST_RELEASE (icon); 
  TEST_RELEASE (selectedicon); 
  RELEASE (dots);
  
  [super dealloc];
}

+ (void)initialize
{
  static BOOL initialized = NO;

  if (initialized == NO) {
    cutTitleSel = @selector(cutTitle:toFitWidth:);
    cutTitle = (cutIMP)[self instanceMethodForSelector: cutTitleSel];   
  
    if (desktopApp == nil) {
      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      NSString *appName = [defaults stringForKey: @"DesktopApplicationName"];
      NSString *selName = [defaults stringForKey: @"DesktopApplicationSelName"];

      if (appName && selName) {
		    Class desktopAppClass = [[NSBundle mainBundle] classNamed: appName];
        SEL sel = NSSelectorFromString(selName);
        desktopApp = [desktopAppClass performSelector: sel];
      }

      fontAttr = [NSDictionary dictionaryWithObject: [NSFont systemFontOfSize: 12]
                                             forKey: NSFontAttributeName];
      RETAIN (fontAttr);
      dtslenght = [dots sizeWithAttributes: fontAttr].width;     
      infoFont = [NSFont systemFontOfSize: 10];
      infoFont = [[NSFontManager sharedFontManager] convertFont: infoFont 
                                                    toHaveTrait: NSItalicFontMask];
      RETAIN (infoFont);
      infoheight = floor([[FSNodeRep sharedInstance] heighOfFont: infoFont]);
    }
   
    initialized = YES;
  }
}

- (id)init
{
  self = [super init];
  
  if (self) {       
    node = nil;
    selection = nil;
    selectionTitle = nil;
    showType = FSNInfoNameType;
    extInfoType = nil;
    icon = nil;
    selectedicon = nil;
    icnsize = DEFAULT_ISIZE;
    
    isLocked = NO;
    iconSelected = NO;
    isOpened = NO;
    nameEdited = NO;
    
    [self setAllowsMixedState: NO];
    
    fsnodeRep = [FSNodeRep sharedInstance];
  }

  return self;
}

- (void)setIcon
{
  if (node) {
    ASSIGN (icon, [fsnodeRep iconOfSize: icnsize forNode: node]);
    icnh = [icon size].height;
    DESTROY (selectedicon);
  }
}

- (NSString *)path
{
  if (node) {
    return [node path];
  }
  return nil;
}

- (BOOL)selectIcon
{
  if (iconSelected) {
    return NO;
  }
  
  if (selectedicon == nil) {
    NSImage *opicn = [fsnodeRep openFolderIconOfSize: icnsize forNode: node];

    if (opicn) {
      ASSIGN (selectedicon, opicn);
      icnh = [selectedicon size].height;
    }
  }
  
  iconSelected = YES;
  return YES;
}

- (BOOL)unselectIcon
{
  if (iconSelected == NO) {
    return NO;
  }
  iconSelected = NO;
  return YES;
}

- (NSString *)cutTitle:(NSString *)title 
            toFitWidth:(float)width
{
  if ([title sizeWithAttributes: fontAttr].width > 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;
}

- (void)drawInteriorWithFrame:(NSRect)cellFrame 
		                   inView:(NSView *)controlView
{
#define MARGIN (2.0)
#define LEAF_MARGIN (5.0)

  NSWindow *cvwin = [controlView window];

  if (cvwin) {
    NSColor *backcolor = [cvwin backgroundColor];
    float textlenght = cellFrame.size.width;
    BOOL showsFirstResponder = [self showsFirstResponder];
    NSString *cuttitle;  

    titleRect = cellFrame;

    if (icon) {
      textlenght -= ([icon size].width + (MARGIN * 2));
    }
    if ([self isLeaf]) {
      textlenght -= LEAF_MARGIN; 
    } else {
      textlenght -= (LEAF_MARGIN + 16); 
    }

    textlenght -= MARGIN;
    ASSIGN (uncuttedTitle, [self stringValue]);
    cuttitle = (*cutTitle)(self, cutTitleSel, uncuttedTitle, textlenght);
    [self setStringValue: cuttitle];        

    [self setShowsFirstResponder: NO];

    if (icon == nil) {
      if (nameEdited == NO) {
        if (infoCell) {
          if (([self isHighlighted] || [self state]) && (nameEdited == NO)) {
	          [[self highlightColorInView: controlView] set];
            NSRectFill(cellFrame);
          }

          titleRect.size.height -= infoheight;

          if ([controlView isFlipped]) {
            titleRect.origin.y += cellFrame.size.height;
            titleRect.origin.y -= (titleRect.size.height + infoheight);
          } else {
            titleRect.origin.y += infoheight;
          }

          [super drawInteriorWithFrame: titleRect inView: controlView];

        } else {
          [super drawInteriorWithFrame: titleRect inView: controlView];
        }

      } else {
        [backcolor set];
        NSRectFill(cellFrame);
      }

      if (infoCell) {
        infoRect = NSMakeRect(cellFrame.origin.x + 2, cellFrame.origin.y + 3,
                                        cellFrame.size.width - 2, infoheight);

        if ([controlView isFlipped]) {
	        infoRect.origin.y += (cellFrame.size.height - infoRect.size.height);
          infoRect.origin.y -= 6;
        }

        [infoCell drawInteriorWithFrame: infoRect inView: controlView];
      } 

    } else {
      NSRect icon_rect;    

      if (([self isHighlighted] || [self state]) && (nameEdited == NO)) {
	      [[self highlightColorInView: controlView] set];
        NSRectFill(cellFrame);
      } 
	    
      if (infoCell) {
        titleRect.size.height -= infoheight;

        if ([controlView isFlipped]) {
          titleRect.origin.y += cellFrame.size.height;
          titleRect.origin.y -= (titleRect.size.height + infoheight);
        } else {
          titleRect.origin.y += infoheight;
        }
      }

      icon_rect.origin = titleRect.origin;
      icon_rect.size = NSMakeSize(icnsize, icnh);
      icon_rect.origin.x += MARGIN;
      icon_rect.origin.y += ((titleRect.size.height - icon_rect.size.height) / 2.0);

      if ([controlView isFlipped]) {
        if (infoCell) {
          icon_rect.origin.y += cellFrame.size.height;
          icon_rect.origin.y -= (titleRect.size.height + infoheight);
        }

	      icon_rect.origin.y += icon_rect.size.height;
      }

      titleRect.origin.x += (icon_rect.size.width + (MARGIN * 2));	
      titleRect.size.width -= (icon_rect.size.width + (MARGIN * 2));	

      if (nameEdited == NO) {        
        [super drawInteriorWithFrame: titleRect inView: controlView];
      }

      if (infoCell) {
        infoRect = NSMakeRect(cellFrame.origin.x + 2, cellFrame.origin.y + 3,
                                        cellFrame.size.width - 2, infoheight);

        if ([controlView isFlipped]) {
	        infoRect.origin.y += (cellFrame.size.height - infoRect.size.height);
          infoRect.origin.y -= 6;
        }

        [infoCell drawInteriorWithFrame: infoRect inView: controlView];
      }

      [controlView lockFocus];

      if ([self isEnabled]) {
        if (iconSelected) {
          if (isOpened == NO) {	
            [selectedicon compositeToPoint: icon_rect.origin 
	                           operation: NSCompositeSourceOver];
          } else {
            [selectedicon dissolveToPoint: icon_rect.origin fraction: 0.5];
          }
        } else {
          if (isOpened == NO) {	
            [icon compositeToPoint: icon_rect.origin 
	                       operation: NSCompositeSourceOver];
          } else {              
            [icon dissolveToPoint: icon_rect.origin fraction: 0.5];
          }
        }
      } else {
			  [icon dissolveToPoint: icon_rect.origin fraction: 0.3];
      }

      [controlView unlockFocus];
    }

    if (showsFirstResponder) {
      [self setShowsFirstResponder: showsFirstResponder];
      NSDottedFrameRect(cellFrame);
    }

    [self setStringValue: uncuttedTitle]; 
  }         
}


//
// FSNodeRep protocol
//
- (void)setNode:(FSNode *)anode
{
  DESTROY (selection);
  DESTROY (selectionTitle);
  ASSIGN (node, anode);
  if (icon) {
    [self setIcon];
  }
  
  if (extInfoType) {
    [self setExtendedShowType: extInfoType];
  } else {
    [self setNodeInfoShowType: showType];  
  }
  
  [self setLocked: [node isLocked]];
}

- (void)setNode:(FSNode *)anode
   nodeInfoType:(FSNInfoType)type
   extendedType:(NSString *)exttype
{
  [self setNode: anode];

  if (exttype) {
    [self setExtendedShowType: exttype];
  } else {
    [self setNodeInfoShowType: type];  
  }
}

- (FSNode *)node
{
  return node;
}

- (void)showSelection:(NSArray *)selnodes
{
  int i;

  ASSIGN (node, [selnodes objectAtIndex: 0]);
  ASSIGN (selection, selnodes);
  if (icon) {
    ASSIGN (icon, [fsnodeRep multipleSelectionIconOfSize: icnsize]);
    icnh = [icon size].height;
  }  
  ASSIGN (selectionTitle, ([NSString stringWithFormat: @"%i %@", 
                  [selection count], NSLocalizedString(@"elements", @"")]));
  [self setStringValue: selectionTitle];

  [self setLocked: NO];
  for (i = 0; i < [selnodes count]; i++) {
    if ([fsnodeRep isNodeLocked: [selnodes objectAtIndex: i]]) {
      [self setLocked: YES];
      break;
    }
  }
}

- (BOOL)isShowingSelection
{
  return (selection != nil);
}

- (NSArray *)selection
{
  return selection;
}

- (NSArray *)pathsSelection
{
  if (selection) {
    NSMutableArray *selpaths = [NSMutableArray array];
    int i;

    for (i = 0; i < [selection count]; i++) {
      [selpaths addObject: [[selection objectAtIndex: i] path]];
    }

    return [NSArray arrayWithArray: selpaths];
  }

  return nil;
}

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

- (NSFont *)labelFont
{
  return [super font];
}

- (void)setLabelTextColor:(NSColor *)acolor
{
}

- (NSColor *)labelTextColor
{
  return [NSColor controlTextColor];
}

- (void)setIconSize:(int)isize
{
  icnsize = isize;
  [self setIcon];
}

- (int)iconSize
{
  return icnsize;
}

- (void)setIconPosition:(unsigned int)ipos
{
}

- (int)iconPosition
{
  return NSImageLeft;
}

- (NSRect)labelRect
{
  return titleRect;
}

- (void)setNodeInfoShowType:(FSNInfoType)type
{
  showType = type;
  DESTROY (extInfoType);
  
  if (selection) {
    [self setStringValue: selectionTitle];
    if (infoCell) {
      [infoCell setStringValue: @""];
    }
    return;
  }
  
  [self setStringValue: [node name]];
  
  if (showType == FSNInfoNameType) {
    DESTROY (infoCell);
  } else if (infoCell == nil) {
    infoCell = [NSCell new];
    [infoCell setFont: infoFont];
  }
  
  switch(showType) {
    case FSNInfoKindType:
      [infoCell setStringValue: [node typeDescription]];
      break;
    case FSNInfoDateType:
      [infoCell setStringValue: [node modDateDescription]];
      break;
    case FSNInfoSizeType:
      [infoCell setStringValue: [node sizeDescription]];
      break;
    case FSNInfoOwnerType:
      [infoCell setStringValue: [node owner]];
      break;
    default:
      break;
  }
}

- (BOOL)setExtendedShowType:(NSString *)type
{
  ASSIGN (extInfoType, type);
  showType = FSNInfoExtendedType;   

  [self setNodeInfoShowType: showType];

  if (selection == nil) {
    NSDictionary *info = [fsnodeRep extendedInfoOfType: type forNode: node];

    if (info) {
      [infoCell setStringValue: [info objectForKey: @"labelstr"]]; 
      return YES;
    }
  } 
  
  return NO;
}

- (FSNInfoType)nodeInfoShowType
{
  return showType;
}

- (NSString *)shownInfo
{
  return [self stringValue];
}

- (void)setNameEdited:(BOOL)value
{
  nameEdited = value;
}

- (void)setLeaf:(BOOL)flag
{
  [super setLeaf: flag];
}

- (BOOL)isLeaf
{
  return [super isLeaf];
}

- (void)select
{
}

- (void)unselect
{
}

- (BOOL)isSelected
{
  return NO;
}

- (void)setOpened:(BOOL)value
{
  /* This was commented. (To know if something goes wrong) */
  if (isOpened == value) {
    return;
  }
  isOpened = value;
}

- (BOOL)isOpened
{
  return isOpened;
}

- (void)setLocked:(BOOL)value
{
	if (isLocked == value) {
		return;
	}
	isLocked = value;
	[self setEnabled: isLocked];
}

- (void)checkLocked
{
  [self setLocked: [node isLocked]];
}

- (BOOL)isLocked
{
	return isLocked;
}

- (void)setGridIndex:(int)index
{
}

- (int)gridIndex
{
  return 0;
}

- (int)compareAccordingToName:(id)aCell
{
  return [node compareAccordingToName: [aCell node]];
}

- (int)compareAccordingToKind:(id)aCell
{
  return [node compareAccordingToKind: [aCell node]];
}

- (int)compareAccordingToDate:(id)aCell
{
  return [node compareAccordingToDate: [aCell node]];
}

- (int)compareAccordingToSize:(id)aCell
{
  return [node compareAccordingToSize: [aCell node]];
}

- (int)compareAccordingToOwner:(id)aCell
{
  return [node compareAccordingToOwner: [aCell node]];
}

- (int)compareAccordingToGroup:(id)aCell
{
  return [node compareAccordingToGroup: [aCell node]];
}

- (int)compareAccordingToIndex:(id)aCell
{
  return NSOrderedSame;
}

@end


@implementation FSNCellNameEditor

- (void)dealloc
{
  TEST_RELEASE (node);
  [super dealloc];
}

- (void)setNode:(FSNode *)anode 
    stringValue:(NSString *)str
          index:(int)idx
{
  DESTROY (node);
  if (anode) {
    ASSIGN (node, anode);
  } 
  [self setStringValue: str];
  index = idx;
}

- (FSNode *)node
{
  return node;
}

- (int)index
{
  return index;
}

- (void)mouseDown:(NSEvent *)theEvent
{
  if ([self isEditable]) {
	  [self setAlignment: NSLeftTextAlignment];
    [[self window] makeFirstResponder: self];
  }
  [super mouseDown: theEvent];
}

@end










