/*
**  ObjCBlockHandler.m
**
**  Copyright (c) 2003
**
**  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 "ObjCBlockHandler.h"
#include <AppKit/AppKit.h>

@implementation ObjCBlockHandler

+ (BOOL) isDelimiter: (NSString *) de
{
  if ( ([de isEqualToString: @"["]) ||
       ([de isEqualToString: @"]"]) ||
       ([de isEqualToString: @"{"]) ||
       ([de isEqualToString: @"}"]) ||
       ([de isEqualToString: @"("]) ||
       ([de isEqualToString: @")"])
     )
    return YES;
  else 
    return NO;
}

- (BOOL) searchBackward: (NSString *) de
{
  if ([_delimiter isEqualToString: @"["]) return NO;
  else if ([_delimiter isEqualToString: @"]"]) return YES;
  else if ([_delimiter isEqualToString: @"{"]) return NO;
  else if ([_delimiter isEqualToString: @"}"]) return YES;
  else if ([_delimiter isEqualToString: @"("]) return NO;
  else if ([_delimiter isEqualToString: @")"]) return YES;
  else return NO;
}

- (void) setDelimiter: (NSString *) de
{
  ASSIGN(_delimiter, de);
  if ([_delimiter isEqualToString: @"["]) _matcher = @"]";
  else if ([_delimiter isEqualToString: @"]"]) _matcher = @"[";
  else if ([_delimiter isEqualToString: @"{"]) _matcher = @"}";
  else if ([_delimiter isEqualToString: @"}"]) _matcher = @"{";
  else if ([_delimiter isEqualToString: @"("]) _matcher = @")";
  else if ([_delimiter isEqualToString: @")"]) _matcher = @"(";
}

- (void) setBackward: (BOOL) bool
{
  _backward = bool;
  if (_backward)
    _balance = -1;
  else
    _balance = +1;
}

- (void) string: (NSString *) element
{
  [super string: element];
  _position += [element length];
  _preChar = 0;
}

- (void) number: (NSString *) element 
{
  [super number: element];
  _position += [element length];
  _preChar = 0;
}

- (void) spaceAndNewLine: (unichar) element 
{
  [super spaceAndNewLine: element];
  _position++;
  _preChar = element;
}

- (void) symbol: (unichar) element 
{
  NSString *eStr;
  [super symbol: element];
  _position++;
  eStr = [NSString stringWithCharacters: &element length: 1];
  _preChar = element;

  if ( (_commentType == NoComment) &&
       (_stringBegin == NO)
      )
    {
      if (_backward)
        {
          /* backward search */
          if ([eStr isEqualToString: _delimiter])
            {
              _balance--;
              [_backwardArray addObject: _delimiter];
              [_positionArray addObject: [NSNumber numberWithUnsignedLongLong: _position]];
              if (_balance == -1)
                {
                  [_backwardArray removeAllObjects];
                  [_positionArray removeAllObjects];
                }
            }
          else if ([eStr isEqualToString: _matcher])
            {
              _balance++;
              [_backwardArray addObject: _matcher];
              [_positionArray addObject: [NSNumber numberWithUnsignedLongLong: _position]];
            }
          else 
            return;
        }
      else
        {
          if (_balance == 0)
            return; 

          /* forward search */
          if ([eStr isEqualToString: _delimiter])
            _balance++;
          else if ([eStr isEqualToString: _matcher])
            _balance--;
          else
            return;

          if (_balance == 0)
            {
              _result = NSMakeRange(_position, [_matcher length]);
            }
        }
    }
}

- (void) invisible: (unichar) element
{
  [super invisible: element];
  _position ++;
  _preChar = element;
}

- (NSRange) result
{
  unsigned long long position;
  int i;
  int len = [_delimiter length];

  if (_backward)
    {
      int count, balance = -1;
      count = [_backwardArray count];

      /* If the last glyph is in comment or string,
         it means the delimiter is in comment or string.
         Then it has no matched delimiter */

      if ( (_commentType == NoComment) &&
           (_stringBegin == NO) )
        {
          for (i = count-1; i > -1; i--)
            {
              if ([_delimiter isEqualToString: [_backwardArray objectAtIndex: i]])
                balance--;
              else
                {
                  balance++;
                  if (balance == 0)
                    {
                      position = [[_positionArray objectAtIndex: i] unsignedLongLongValue];
                      _result = NSMakeRange(position-len, len);
                      break;
                    }
                }
            }
        }
    }

  /* There is no way to tell whether the delimiter
     begins in comment or string because CodeHandler
     only receive string after the delimiter */

  return _result;
}

- (id) init
{
  self = [super init];
  [self setBackward: NO];
  _result = NSMakeRange(NSNotFound, 0);
  _backwardArray = [NSMutableArray new];
  _positionArray = [NSMutableArray new];
  return self;
}

- (void) dealloc
{
  RELEASE(_backwardArray);
  RELEASE(_delimiter);
  RELEASE(_positionArray);
  [super dealloc];
}

@end

