/* -*-ObjC-*-
*******************************************************************************
*
* File:         SmileyPrefs.m
* RCS:          /usr/local/sources/CVS/EnhanceMail/SmileyPrefs.m,v 1.1 1997/09/14 22:42:12 tom Exp
* Description:  
* Author:       Tom Hageman
* Created:      Fri Sep  5 18:48:41 1997
* Modified:     
* Language:     Objective-C
* Package:      N/A
* Status:       Experimental
*
* (C) Copyright 1997, but otherwise this file is perfect freeware.
*
*******************************************************************************
*/

#import "SmileyPrefs.h"
#import <dbkit/dbkit.h>
#import "SimpleString.h"
#import "XImageURL.h"
#import <regex.h> // NOT "regexp.h" since DisplayFilter uses system regex routines.

@interface EnhanceSmileyTableViewController (TableViewDataSource)
- (void)_setupTableView;
- (void)_reloadTableView;
@end


@implementation EnhanceSmileyTableViewController

- awakeFromNib
{
   [self _setupTableView];
   [self setAction:@selector(noteChange:)];
   // Kludge: cannot set action in IB for custom object.
   return self;
}

- target		   { return target; }
- setTarget:anObject	   { target = anObject;  return self; }
- (SEL)action		   { return action; }
- setAction:(SEL)aSelector { action = aSelector;  return self; }

/* contentsList contains alternating regex / smileyName string pairs.
   i.e. contentsList[2*n] = regex[n], contenstList[2*n+1] = smileyName[n]. */

- (const char *)stringValue
{
   if (contentsString == nil)
   {
      unsigned i, count = [contentsList count];

      contentsString = [[SimpleString alloc] init];

      for (i = 0;  i < count; i++)
      {
	 SimpleString *ss = [contentsList objectAt:i];

	 // XXX Clean this up.
	 /* Ignore if either regex or name is an empty string.
	    -- in effect, remove this entry. */
	 if ([ss length] && [[contentsList objectAt:(i^1)] length])
	 {
	    [contentsString appendSimpleString:ss];
	    [contentsString appendChar:'\n'];
	 }
      }
   }
   return [contentsString string];
}

- setStringValue:(const char *)aValue
{
   if (aValue && (!contentsString || strcmp([contentsString string], aValue) != 0))
   {
      [contentsString free];
      contentsString = [[SimpleString allocFromZone:[self zone]] init];
      [contentsString appendString:aValue];
      [contentsList freeObjects];
      [self _reloadTableView];
   }
   return self;
}

@end // EnhanceSmileyTableViewController


@implementation EnhanceSmileyTableViewController (TableViewDataSource)

#define COL_REGEX	1
#define COL_NAME	2
#define COL_IMAGE	3

- (void)_setupTableView
{
   [tableView setDataSource:self];
   [[tableView columnAt:0] setIdentifier:(id)COL_REGEX];
   [[tableView columnAt:1] setIdentifier:(id)COL_NAME];
   [[tableView columnAt:2] setIdentifier:(id)COL_IMAGE];
   [[tableView columnAt:2] setFormatter:[[DBImageFormatter alloc] init]]; 
}

- (void)_reloadTableView
{
   int oldSelectedRow = [tableView selectedRow];

   if (!contentsList) contentsList = [[List allocFromZone:[self zone]] init];
   if ([contentsList count] == 0)
   {
      const char *c, *d, *e;
      SimpleString *ss;

      for (c = [contentsString string];  *c;  c = d)
      {
	 for (d = c;  *d && *d != '\n';  d++) ;
	 if (!*d) break;
	 e = d;
	 for (d = e + 1;  *d && *d != '\n';  d++) ;
	 if (e > c && d > e+1)
	 {
	    [ss = [[SimpleString allocFromZone:[self zone]] init] appendString:c length:(e-c)];
	    [contentsList addObject:ss];
	    [ss = [[SimpleString allocFromZone:[self zone]] init] appendString:(e+1) length:(d-(e+1))];
	    [contentsList addObject:ss];
	    if (*d) d++;
	 }
      }
   }

   [tableView reloadData:self];
   if (oldSelectedRow >= 0 && oldSelectedRow < [tableView rowCount])
   {
      [tableView selectRow:oldSelectedRow byExtension:NO];
      [tableView scrollRowToVisible:oldSelectedRow];
   }
   else
   {
      [tableView deselectAll:self];
   }
}

- (unsigned)rowCount
{
   return [contentsList count] / 2 + 1;
}

- getValueFor:identifier at:(unsigned)aPosition into:aValue
{
   unsigned i = aPosition * 2;
   const char *s, *ext;
   NXImage *image = nil;

   switch ((int)identifier)
   {
   case COL_REGEX:
      s = (i < [contentsList count]) ? [[contentsList objectAt:i] string] : "";
      [aValue setStringValue:s];
      break;
   case COL_NAME:
      s = (i+1 < [contentsList count]) ? [[contentsList objectAt:i+1] string] : "";
      // Strip .tiff extension.
      if ((ext = strrchr(s, '.')) && strcmp(ext, ".tiff") == 0)
      {
	 char *t = strncpy(alloca(ext-s+1), s, (ext-s));
	 t[ext-s] = '\0';
	 s = t;
      }
      [aValue setStringValue:s];
      break;
   case COL_IMAGE:
      if (i+1 < [contentsList count])
      {
	 s = [[contentsList objectAt:i+1] string];
	 image = [[NXImage allocFromZone:[self zone]] initNameInPath:s];
      }
      [aValue setObjectValue:image];
      [image free];
      break;
   }
   return self;
}

- setValueFor:identifier at:(unsigned)aPosition from:aValue
{
   unsigned i = aPosition * 2;
   const char *s, *ext, *re_sult;
   SimpleString *ss;

   // Add empty row if last empty line is filled.
   while (i >= [contentsList count])
   {
      [contentsList addObject:[[SimpleString allocFromZone:[self zone]] init]];
      [contentsList addObject:[[SimpleString allocFromZone:[self zone]] init]];
   }
   switch ((int)identifier)
   {
   case COL_REGEX:
      s = [aValue stringValue];
      if ((re_sult = re_comp(s)) != NULL)
      {
	 NXRunLocalizedAlertPanel("Alerts", "Regular Expression Error", re_sult, NULL, NULL, NULL); // XXX Localization
	 return nil;
      }
      [ss = [[SimpleString allocFromZone:[self zone]] init] appendString:s];
      [[contentsList replaceObjectAt:i with:ss] free];
      break;
   case COL_NAME:
      s = [aValue stringValue];
      [ss = [[SimpleString allocFromZone:[self zone]] init] appendString:s];
      if (s[0] && (ext = strrchr(s, '.')) == NULL) [ss appendString:".tiff"];
      [[contentsList replaceObjectAt:(i+1) with:ss] free];
      break;
   case COL_IMAGE:
      /* Shouldn't happen -- ignore. */
      return nil;
   }

   if (contentsString) [contentsString free], contentsString = nil;

   // Remove empty row.
   // XXX The following does not work yet for some reason...
   if ([[contentsList objectAt:i] length] == 0 &&
       [[contentsList objectAt:i+1] length] == 0)
   {
      [[contentsList removeObjectAt:i+1] free];
      [[contentsList removeObjectAt:i] free];
   }
   [self _reloadTableView]; // XXX brute-force approach.
   if ([self action] && [self target])
   {
      [NXApp sendAction:[self action] to:[self target] from:self];
   }
   return self;
}

@end // EnhanceSmileyTableViewController (TableViewDataSource)
