// Controller.m - Charmap application delegate implementation
// Copyright (C) 2003,2004 Christopher Culver <crculver@users.sourceforge.net>
//
// 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

#ifndef _CONTROLLER_H
#include "Controller.h"
#endif

@implementation Controller : NSObject
- (void) dealloc
{
  RELEASE(charDecimalInfo);
  RELEASE(charHexInfo);
  RELEASE(charOctalInfo);
  RELEASE(charUTF8Info);
  RELEASE(charmapCell);
  RELEASE(charmapMatrix); 
  RELEASE(charmapScroll);
  RELEASE(largeDict);
  RELEASE(cellDict);
  RELEASE(display);
  RELEASE(inspectorChar);
  RELEASE(inspectorPanel);
  RELEASE(unicodeData);
  [super dealloc];
}

- (id) init
{
  unicodeData = [[UnicodeData alloc] init];
  inspectorOpen = NO;
  return self;
}

- (void) awakeFromNib
{
  short int i;
  
  NSMutableParagraphStyle * paragraphStyle = [NSMutableParagraphStyle
					       defaultParagraphStyle];
  [paragraphStyle setAlignment: NSCenterTextAlignment];
  ASSIGN(cellDict, ([NSMutableDictionary dictionaryWithObjectsAndKeys:
					   [NSFont systemFontOfSize: 14],
					 NSFontAttributeName,
					 [NSColor blackColor],
					 NSForegroundColorAttributeName,
					 paragraphStyle,
					 NSParagraphStyleAttributeName,
					 nil]));
  ASSIGN(largeDict, ([NSMutableDictionary dictionaryWithObjectsAndKeys:
					    [NSFont systemFontOfSize: 48],
					  NSFontAttributeName,
					  [NSColor blueColor],
					  NSForegroundColorAttributeName,
					  paragraphStyle,
					  NSParagraphStyleAttributeName,
					  nil]));

  /* Set some main window graphical properties. */
  [blocksBrowser setMinColumnWidth: 250];
  [blocksBrowser setAction: @selector (generateCharmap)];
  [blocksBrowser setTarget: self];
  charmapCell = [[NSTextFieldCell alloc] init];
  [charmapCell setAllowsEditingTextAttributes: YES];
  [charmapCell setEditable: NO];
  [charmapCell setSelectable: NO];
  [charmapCell setBordered: NO];
  [charmapMatrix setAction: @selector (updateInspector:)];
  [charmapMatrix setAllowsEmptySelection: NO];
  [charmapMatrix setAutoscroll: YES];
  [charmapMatrix setCellSize: NSMakeSize (30, 35)];
  [charmapMatrix setAllowsEmptySelection: NO];
  [charmapMatrix setDoubleAction: @selector (putSelected:)];
  [charmapMatrix setMode: NSRadioModeMatrix];
  [charmapMatrix setPrototype: charmapCell];
  [charmapMatrix setSelectionByRect: NO];
  for (i = 0; i < 10; i++)
    [charmapMatrix addColumn];
  [copyButton setEnabled: NO];
  [display setFont: [cellDict objectForKey: NSFontAttributeName]];

  /* Set some inspector graphical properties. */
  inspectorOpen = NO;
  [inspectorChar setAlignment: NSLeftTextAlignment];
  [inspectorChar setDrawsBackground: NO];
  [inspectorChar setEditable: NO];
  [inspectorChar setRichText: YES];
  [inspectorChar setSelectable: NO];
  [inspectorChar setUsesFontPanel: NO];
  [charDecompInfo setDrawsBackground: NO];
  [charDecompInfo setEditable: NO];
  [charDecompInfo setSelectable: NO];
  [[charDecompInfo textContainer]
    setContainerSize: NSMakeSize([charNameInfo frame].size.width,
				 75)];
  [[charDecompInfo textContainer] setWidthTracksTextView: YES];
  [[charDecompInfo textStorage] setAttributedString:
				[[NSAttributedString alloc]
				  initWithString: @"No character selected"]];

  [charNameInfo setDrawsBackground: NO];
  [charNameInfo setEditable: NO];
  [charNameInfo setSelectable: NO];
  [[charNameInfo textContainer]
    setContainerSize: NSMakeSize([charNameInfo frame].size.width,
				 50)];
  [[charNameInfo textContainer] setWidthTracksTextView: YES];
  [[charNameInfo textStorage] setAttributedString:
				[[NSAttributedString alloc]
				  initWithString: @"No character selected"]];
  [charAliasInfo setDrawsBackground: NO];
  [charAliasInfo setEditable: NO];
  [charAliasInfo setSelectable: NO];
  [[charAliasInfo textContainer] setContainerSize:
				   NSMakeSize([charAliasInfo frame].size.width,
					      50)];
  [[charAliasInfo textContainer] setWidthTracksTextView: YES];
  [self generateCharmap];
}

- (void) generateCharmap
{
  NSString *tempString = nil;
  NSTextFieldCell *tempCell;
  unichar aChar;
  int i, j, k, block, blockSize;
  unsigned int blockStart, blockEnd;
  
  /* Remove all rows BUT ONE */
  for (i = [charmapMatrix numberOfRows]; i >= 1; i--)
    {
      if ([charmapMatrix cellAtRow: i column: 0])
	[charmapMatrix removeRow: i];
    }

  /*  Add the necessary rows */
  block = [blocksBrowser selectedRowInColumn: 0];
  if (block == -1)
    block = 0;
  blockSize = [unicodeData getBlockSize: block];
  blockStart = [unicodeData getBlockStart: block];
  blockEnd = [unicodeData getBlockEnd: block];
  for (i = 0; i < (blockSize / [charmapMatrix numberOfColumns]); i++)
      [charmapMatrix insertRow: 0];

  /* Fill the cells */
  for (i = 0, k = blockStart; k < (blockEnd); i++)
    {
      for (j = 0; j < [charmapMatrix numberOfColumns]; j++, k++)
	{
	  aChar = k;
	  tempString = [[NSString alloc] initWithCharacters: &aChar length: 1];
	  tempCell = [charmapMatrix cellAtRow: i column: j];
	  [charmapCell setAllowsEditingTextAttributes: YES];
	  [tempCell setDrawsBackground: YES];
	  [tempCell setTag: k];
	  [tempCell setAlignment: NSCenterTextAlignment];
	  [tempCell setAttributedStringValue: [[NSAttributedString alloc]
						initWithString: tempString
						attributes: cellDict]];
	  if ( [[unicodeData getName: k] isEqual: @"<not assigned>"] == NO)
	      [tempCell setBackgroundColor: [NSColor whiteColor]];
	  else // Gray out positions which are not assigned.
	    {
	      [tempCell setBackgroundColor: [NSColor darkGrayColor]];
	      [tempCell setAttributedStringValue: [[NSAttributedString alloc]
						   initWithString: @""
						   attributes: cellDict]];
	    }
	  RELEASE(tempString);
	}
    }
    
  /* Finish setting display. */
  [charmapMatrix sizeToCells];
  [charmapMatrix scrollCellToVisibleAtRow: 1 column: 1];
  [charmapMatrix selectCellAtRow: 0 column: 0];
  [charmapMatrix setNeedsDisplay: YES];
  if (inspectorOpen == YES)
    [self updateInspector: self];
}

- (void)controlTextDidChange:(NSNotification *)aNotification
{
  if ([[display stringValue] length] != 0)
    [copyButton setEnabled: YES];
  else
    [copyButton setEnabled: NO];
}

- (void) putSelected: (id) sender
{
  NSMutableString *selectedString;
  int charTag;

  charTag = [[charmapMatrix selectedCell] tag];
  selectedString = [[NSMutableString alloc] init];
  [selectedString appendString: [display stringValue]];
  [selectedString appendString: [[charmapMatrix selectedCell] stringValue]];
  [display setStringValue: selectedString];
  [self controlTextDidChange: (NSNotification *)
	NSControlTextDidChangeNotification];
}

- (void) copySelected: (id) sender
{
  NSPasteboard *pb = [NSPasteboard generalPasteboard];

  [display selectText: self];
  [pb declareTypes: [NSArray arrayWithObject: NSStringPboardType]
      owner: self];
  if ([[display stringValue] length] != 0)
    {
      [pb setString: [display stringValue] forType: NSStringPboardType];
      NSLog (_(@"Text copied."));
    }
  else
    NSLog (_(@"No text selected."));
}

- (void) updateInspector: (id) sender
{
  NSAttributedString *charAliasAttrString = nil;
  NSAttributedString *charNameAttrString = nil;
  NSDictionary *charDict;
  NSMutableString *charDecompString = nil;
  NSMutableString *tempString;
  NSString *character;
  NSString *charCategoryString = nil;
  NSString *name = nil;
  const unsigned char * cs;
  unichar charTag;

  charTag = [[charmapMatrix selectedCell] tag];
  character = [[NSString alloc] initWithCharacters: &charTag length: 1];
  charDict = [[NSDictionary alloc]
	       initWithDictionary: [unicodeData dictionaryForCharacter:
						  charTag]];

  if (![charDict objectForKey: @"Name"])
      name = [unicodeData getName: charTag];
  else name = [charDict objectForKey: @"Name"];

  [[inspectorChar textStorage] setAttributedString: nil];
  [[charAliasInfo textStorage] setAttributedString: nil];
  if ([name isEqual: @"<not assigned>"] == NO)
    {
      /* Show character "magnified". */
      [[inspectorChar textStorage] setAttributedString:
				     [[NSAttributedString alloc]
				       initWithString: character
				       attributes: largeDict]]; 
      /* Show name. */
      charNameAttrString = [[NSAttributedString alloc]
			     initWithString: name];
      [[charNameInfo textStorage] setAttributedString: charNameAttrString];
      /* Show alias. */
      if ([charDict objectForKey: @"Unicode1.0Name"])
	{
	  charAliasAttrString = [[NSAttributedString alloc]
				  initWithString:
				    [charDict objectForKey:
						@"Unicode1.0Name"]];
	  [[charAliasInfo textStorage]
	    setAttributedString: charAliasAttrString];
	}
    }
  else
    {
      // If position not assigned, don't show a character.
      [[inspectorChar textStorage] setAttributedString: nil];
      charNameAttrString = [[NSAttributedString alloc]
			     initWithString: name];
      [[charNameInfo textStorage] setAttributedString: charNameAttrString];  
      [[charAliasInfo textStorage] setAttributedString: nil]; 
    }
  
  /* Show general Unicode category. */
  if ([charDict objectForKey: @"GeneralCategory"])
    { 
      charCategoryString = [[NSString alloc]
			     initWithString: [charDict objectForKey:
							 @"GeneralCategory"]];
      [charCategoryInfo setStringValue: [unicodeData getFullCategoryName:
						       charCategoryString]];
    }
  else
    [charCategoryInfo setStringValue: nil];

  /* Show canonical decomposition. */
  [[charDecompInfo textStorage] setAttributedString: nil];
  if ([ [charDict objectForKey: @"Decomposition"] length] > 0)
    {
      charDecompString = [[NSString alloc] initWithString:
					     [unicodeData getFullDecomposition:
							    charTag]];
      [[charDecompInfo textStorage] setAttributedString:
				      [[NSAttributedString alloc]
					initWithString: charDecompString]];
    }

  /* Set various representations. */
  [charDecimalInfo setStringValue: [NSString stringWithFormat: @"&#%d;",
					     charTag]];
  [charHexInfo setStringValue: [NSString stringWithFormat: @"U+%004X",
					 charTag]];

  tempString = [[NSMutableString alloc] init];
  for (cs = [character UTF8String]; *cs != '\0'; cs++)
    [tempString appendString: [NSString stringWithFormat: @"0x%02X ", *cs]];
  [charUTF8Info setStringValue: tempString];
  RELEASE(tempString);

  tempString = [[NSMutableString alloc] init];
  for (cs = [character UTF8String]; *cs != '\0'; cs++)
      [tempString appendString: [NSString stringWithFormat: @"\\%02o", *cs]];
  [charOctalInfo setStringValue: tempString];

  RELEASE(character);
  RELEASE(charAliasAttrString);
  RELEASE(charCategoryString);
  RELEASE(charDecompString);
  RELEASE(charNameAttrString);
  RELEASE(name);
  RELEASE(tempString);
}

- (id) showInspector: (id)sender
{
  [self updateInspector: self];
  [inspectorPanel center];
  [inspectorPanel orderFront: self];
  inspectorOpen = YES; 
  return self;
}

- (void) changeFont: (id)fontManager
{
  NSFont *newCellFont;
  NSFont *newLargeFont;

  /* Create new fonts */
  newCellFont = [fontManager convertFont: [cellDict objectForKey:
						 NSFontAttributeName]];
  [cellDict setObject: newCellFont forKey: NSFontAttributeName];

  newLargeFont = [fontManager convertFont: [largeDict objectForKey: 
						   NSFontAttributeName]];

  [largeDict setObject: [fontManager convertFont: newLargeFont toSize: 48] 
	     forKey: NSFontAttributeName];
  
  /* Update display */
  [display setFont: newCellFont];
  [display setNeedsDisplay: YES];
  [self generateCharmap];
  if (inspectorOpen == YES)
    {
      [self updateInspector: self];
      [inspectorChar setNeedsDisplay: YES];
    }
}

- (void) windowWillClose: (NSNotification *) theNotification
{
  inspectorOpen = NO;
}

- (void) browser: (NSBrowser *)sender
createRowsForColumn: (int)column
	inMatrix: (NSMatrix *)matrix
{
  short int i;
  int count;
  NSBrowserCell *cell;
  NSString *category;
  blockNames = [unicodeData getBlockNames];
  count = [blockNames count];
  if (count)
    {
      [matrix addColumn];
      for (i = 0; i < count; i++)
	{
	  if (i > 0)
	    [matrix addRow];
	  category = [blockNames objectAtIndex: i];
	  cell = [matrix cellAtRow: i
			 column: 0];
	  [cell setStringValue: category];
	  [cell setLeaf: YES];
	}
    }
}
@end
