/*
**  RenderHandler.m
**
**  Copyright (c) 2003, 2004
**
**  Author: Yen-Ju  <yjchenx@hotmail.com>
**
**  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
*/

#include "HRCell.h"
#include "NoteCell.h"
#include "RenderHandler.h"
#include "GNUstep.h"
#include <AppKit/AppKit.h>

@interface NSString (RenderHandlerAddition)
- (NSString *) substringWithinQuotation;
@end

@implementation NSString (RenderHandlerAddition)

- (NSString *) substringWithinQuotation
{
  NSString *substring;
  NSRange resultRange, searchRange, finalRange;;
  resultRange = [self rangeOfString: @"\""];
  if (resultRange.location == NSNotFound)
    {
      NSLog(@"Error: can't find symbol \"");
      return nil;
    }
  finalRange = resultRange;
  searchRange = NSMakeRange(NSMaxRange(resultRange),
                            [self length]-NSMaxRange(resultRange));
  resultRange = [self rangeOfString: @"\""
                            options: 0
                              range: searchRange];
		      
  if (resultRange.location == NSNotFound)
    {
      NSLog(@"Error: can't find symbol \"");
      return nil;
    }
  finalRange.location++; /* take off the first '"' symbol */
  finalRange.length = resultRange.location - finalRange.location;
  substring = [self substringWithRange: finalRange];
  return AUTORELEASE([substring copy]);
}

@end


@implementation RenderHandler

- (void) addNote: (NSAttributedString *) string
       withImage: (NSImage *) img
       withColor: (NSColor *) color
{
  NSTextAttachment *at = [[NSTextAttachment alloc] init];
  NoteCell *attachCell = [[NoteCell alloc] init];
  [attachCell setImage: img];
  [attachCell setColor: color];
  [attachCell setText: string];

  [at setAttachmentCell: attachCell];
  NSAttributedString *as = [NSAttributedString attributedStringWithAttachment: at];
  //NSAttributedString *astring = [[NSAttributedString alloc] initWithString: @"\n"];
  //[_result appendAttributedString: astring];
  [_result appendAttributedString: as];
  RELEASE(attachCell);
  RELEASE(at);
}

- (void) addStringWithAttributes: (NSString *) element
{
  {
    // Handle font type
    NSFont* font;
    NSFontTraitMask fontMask = 0;
    if (fontType & BoldFontType) fontMask |= NSBoldFontMask;
    if (fontType & ItalicFontType) fontMask |= NSItalicFontMask;
    if (fontType & FixedPitchFontType)
      {
        font = [[NSFontManager sharedFontManager] 
   	          convertFont: [NSFont userFixedPitchFontOfSize: 12]
		  toHaveTrait: fontMask];
      }
    else
      {
        font = [[NSFontManager sharedFontManager]
	          convertFont: [NSFont userFontOfSize: 12]
		  toHaveTrait: fontMask];
      }
    // NSLog(@"font %@, %d", font, [[NSFontManager sharedFontManager] traitsOfFont: font]);
    [attributes setValue: font forKey: NSFontAttributeName];
  }

  if (tagType != CodeTagType)
    {
      if (tagType == UrefTagType)
        {
          [contentOfTag appendString: element];
#ifdef GNUSTEP
          [attributes setValue: [NSColor blueColor]
                        forKey: NSForegroundColorAttributeName];
#endif
        }

      if (tagType == NoteTagType)
        {
          [contentOfTag appendString: element];
          return; // Don't append string 
	}
    }

  NSAttributedString *as; 
  as = [[NSAttributedString alloc] initWithString: element 
                                       attributes: attributes]; 
  [_result appendAttributedString: as]; 
  [as release];
}

- (void) special: (NSString *) element
{
  NSString *s;

  if (tagType == CodeTagType)
    s = AUTORELEASE([element copy]);
  else if ([element isEqualToString: @"<<"])
    s = @"<";
  else if ([element isEqualToString: @">>"])
    s = @">";
  else
    s = AUTORELEASE([element copy]);

  [self addStringWithAttributes: s];
}

- (void) content: (NSString *) element
{
  [self addStringWithAttributes: element];
}

- (void) tag: (NSString *) element 
{
  NS_DURING

  if ([element isEqualToString: @"code"])
    {
      fontType |= FixedPitchFontType;
      tagType = CodeTagType;
    }
  else if ([element isEqualToString: @"/code"])
    {
      fontType &= ~FixedPitchFontType;
      tagType = OtherTagType;
    }
  else if (tagType == CodeTagType)
    {
      [self addStringWithAttributes: [NSString stringWithFormat: @"<%@>", element]];
      //return;
      NS_VOIDRETURN;
    }

  if ([element isEqualToString: @"b"])
    {
      fontType |= BoldFontType;
    }
  else if ([element isEqualToString: @"/b"])
    {
      fontType &= ~BoldFontType;
    }
  else if ([element isEqualToString: @"i"])
    {
      fontType |= ItalicFontType;
    }
  else if ([element isEqualToString: @"/i"])
    {
      fontType &= ~ItalicFontType;
    }
  else if ([element isEqualToString: @"link"])
    {
      tagType = LinkTagType;
      rangeOfTag.location = [_result length];
    }
  else if ([element isEqualToString: @"/link"])
    {
      tagType = OtherTagType;
      rangeOfTag.length = [_result length] - rangeOfTag.location;
      [_result addAttribute: NSLinkAttributeName
                      value: @"Link"
                      range: rangeOfTag];
#ifdef GNUSTEP
      [_result addAttribute: NSForegroundColorAttributeName
                      value: [NSColor blueColor]
                      range: rangeOfTag];
      [_result addAttribute: NSUnderlineStyleAttributeName
                      value: [NSNumber numberWithInt: NSSingleUnderlineStyle]
                      range: rangeOfTag];
#endif

    }
  else if ([element isEqualToString: @"hr/"])
    {
      NSTextAttachment *ta = [[NSTextAttachment alloc] init];
      HRCell *hr = [HRCell sharedHRCell];
      [ta setAttachmentCell: hr];
      NSAttributedString *as = [NSAttributedString attributedStringWithAttachment: ta];
      [_result appendAttributedString: as];
      RELEASE(ta);
    }
  else if (([element isEqualToString: @"note"]) ||
	   ([element isEqualToString: @"caution"]) ||
	   ([element isEqualToString: @"information"]))
    {
      tagType = NoteTagType;
    }
  else if ([element isEqualToString: @"/note"])
    {
      tagType = OtherTagType;

      // Put up the graphics
      [self addNote: AUTORELEASE([[NSAttributedString alloc] initWithString: contentOfTag])
 	    withImage: [NSImage imageNamed: @"note48.png"]
	    withColor: [NSColor colorWithCalibratedRed: 0.81 green: 0.84 blue: 0.88 alpha: 1.0]];
      [contentOfTag setString: @""];
    }
  else if ([element isEqualToString: @"/caution"])
    {
      tagType = OtherTagType;

      // Put up the graphics
      [self addNote: AUTORELEASE([[NSAttributedString alloc] initWithString: contentOfTag])
	    withImage: [NSImage imageNamed: @"caution48.png"]
  	    withColor: [NSColor colorWithCalibratedRed: 0.88 green: 0.78 blue: 0.78 alpha: 1.0]];
      [contentOfTag setString: @""];
    }
  else if ([element isEqualToString: @"/information"])
    {
      tagType = OtherTagType;

      // Put up the graphics
      [self addNote: AUTORELEASE([[NSAttributedString alloc] initWithString: contentOfTag])
 	    withImage: [NSImage imageNamed: @"information48.png"]
	    withColor: [NSColor colorWithCalibratedRed: 0.79 green: 0.89 blue: 0.78 alpha: 1.0]];
      [contentOfTag setString: @""];
    }
  else if (([element isEqualToString: @"uref"]) ||
	   ([element isEqualToString: @"email"]))
    {
      tagType = UrefTagType;
      rangeOfTag.location = [_result length];
    }
  else if ([element isEqualToString: @"/uref"])
    {
      tagType = OtherTagType;
      rangeOfTag.length = [_result length] - rangeOfTag.location;
      if ([value isEqualToString: @""])
        [value setString: AUTORELEASE([contentOfTag copy])];

      NSURL *url = [NSURL URLWithString: value];
      if (url == nil)
        {
          NSRunAlertPanel(sInvalidURL,
                     [NSString stringWithFormat: sInvalidURLDescription_, value],
                          sOK, nil, nil, nil);
        }
      else
        {
          [_result addAttribute: NSLinkAttributeName
   	                  value: [NSURL URLWithString: value]
		          range: rangeOfTag];
#ifdef GNUSTEP
          [_result addAttribute: NSForegroundColorAttributeName
                          value: [NSColor blueColor]
                          range: rangeOfTag];
          [_result addAttribute: NSUnderlineStyleAttributeName
                          value: [NSNumber numberWithInt: NSSingleUnderlineStyle]
                          range: rangeOfTag];
#endif
        }
      [contentOfTag setString: @""];
      [value setString: @""];
    }
  else if ([element isEqualToString: @"/email"])
    {
      tagType = OtherTagType;
      rangeOfTag.length = [_result length] - rangeOfTag.location;
      if ([value isEqualToString: @""])
        [value setString: AUTORELEASE([contentOfTag copy])];

      [_result addAttribute: NSLinkAttributeName
		      value: [NSString stringWithFormat: @"<%@>", value]
		      range: rangeOfTag];
#ifdef GNUSTEP
      [_result addAttribute: NSForegroundColorAttributeName
                      value: [NSColor blueColor]
                      range: rangeOfTag];
      [_result addAttribute: NSUnderlineStyleAttributeName
                      value: [NSNumber numberWithInt: NSSingleUnderlineStyle]
                      range: rangeOfTag];
#endif
      [contentOfTag setString: @""];
      [value setString: @""];
    }
  else
    {
      // Digest tag to get value of attributes
      if ([element hasPrefix: @"uref"])
        {
          // Search string between '"' symbol
          tagType = UrefTagType;
          rangeOfTag.location = [_result length];
	      
          [value setString: [element substringWithinQuotation]];
          if ([element hasSuffix: @"/"])
   	    {
	      [self addStringWithAttributes: value];
	      rangeOfTag.length = [_result length] - rangeOfTag.location;
	      [contentOfTag setString: AUTORELEASE([value copy])];
              [_result addAttribute: NSLinkAttributeName
                              value: [NSURL URLWithString: value]
                              range: rangeOfTag];
              [value setString: @""];
	      [contentOfTag setString: @""];
	      tagType = OtherTagType;
     	    }
	}
      else if ([element hasPrefix: @"email"])
        {
          // Search string between '"' symbol
          tagType = UrefTagType;
          rangeOfTag.location = [_result length];
	      
          [value setString: [element substringWithinQuotation]];
          if ([element hasSuffix: @"/"])
   	    {
	      [self addStringWithAttributes: value];
	      rangeOfTag.length = [_result length] - rangeOfTag.location;
	      [contentOfTag setString: AUTORELEASE([value copy])];
              [_result addAttribute: NSLinkAttributeName
                              value: [NSString stringWithFormat: @"<%@>", value]
                              range: rangeOfTag];
              [value setString: @""];
	      [contentOfTag setString: @""];
	      tagType = OtherTagType;
	    }
	}
    }
  
  NS_HANDLER
    NSLog(@"RenderHandler: Exception");
    NSException *ex = [NSException exceptionWithName: RenderTextExceptionName
	                           reason: GeneralError
	 		           userInfo: nil];
    [ex raise];
  NS_ENDHANDLER
 
}

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

  _result = [[NSMutableAttributedString alloc] init];
  attributes = [[NSMutableDictionary alloc] init];
  [attributes setValue: [NSFont userFontOfSize: 12]
	        forKey: NSFontAttributeName];
  [attributes setValue: [NSColor blackColor]
	        forKey: NSForegroundColorAttributeName];
  value = [[NSMutableString alloc] init];

  fontType = NormalFontType;;
  tagType = OtherTagType;

  rangeOfTag = NSMakeRange(NSNotFound,0);
  contentOfTag = [[NSMutableString alloc] init];

  return self;
}

- (void) dealloc
{
  RELEASE(_result);
  RELEASE(attributes);
  RELEASE(value);
  RELEASE(contentOfTag);
  [super dealloc];
}

- (NSAttributedString *) renderedString
{
  [_result fixAttributesInRange: NSMakeRange(0, [_result length])];
  return _result;
}

@end
