/*
**  ObjCMethodHandler.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 "ObjCMethodHandler.h"
#include <CodeEditorView/MethodNode.h>
#include <AppKit/AppKit.h>

@implementation ObjCMethodHandler

- (NSArray *) methods
{
  return methods;
}

- (MethodNode *) rootNode
{
  return rootNode;
}

#define NotMethod {step = MethodNone; [method setString: @""];}

- (void) string: (NSString *) element
{
  unsigned int len = [element length];

  [super string: element];

  /* Comments */
  if (_commentType != NoComment)
    {
    }
  else if (_stringBegin/* != NoString*/)
    {
    }
  else
    {
      if (step == MethodStart)
        {
          NotMethod;
        }
      else if (step == MethodSymbol)
        {
          if (_preSymbol == '(')
            {
              step = MethodReturnValue;
            }
          else if ((_preSymbol == '+') || (_preSymbol == '-'))
            {
              step = MethodName;
              
              /* Must be the first method name part */
              part = MethodNamePart;

              [method appendString: element];
            }
        }
      else if (step == MethodReturnValue)
        {
          if (_preSymbol == ')')
            {
              step = MethodName;
 
              /* Must be the first method name part */
              part = MethodNamePart;

              [method appendString: element];
            }
        }
      else if (step == MethodName)
        {
          if (part == MethodNamePart)
            {
              /* impossible */
            }
          else if (part == MethodSeparatePart)
            {
              if (_preSymbol == '(')
                {
                  part = MethodReturnValuePart;
                }
              else if (_preSymbol == ':')
                {
                  part = MethodMessagePart;
                }
            }
          else if (part == MethodReturnValuePart)
            {
              if (_preSymbol == ')')
                {
                  part = MethodMessagePart;
                }
            }
          else if (part == MethodMessagePart)
            {
              [method appendString: element];
            }
        }
      else if (_preChar == '@') 
        {
          if (([element isEqualToString: @"implementation"]) ||
              ([element isEqualToString: @"interface"]) ||
              ([element isEqualToString: @"protocol"]))
            {
              classDefined = YES;
              methodBeginPosition = position+len;
            }
        }
      else if (classDefined)
        {
          [classDefinition appendString: element];
        }
    }

  position += len;
  _preChar = 0;
}

- (void) number: (NSString *) element 
{
  [super number: element];

  /* Comments */
  if (_commentType != NoComment)
    {
    }
  else if (_stringBegin)
    {
    }
  else
    {
      if (step == MethodStart)
        {
          NotMethod;
        }
      else if (step == MethodSymbol)
        {
          NotMethod;
        }
      else if (step == MethodReturnValue)
        {
          NotMethod;
        }
      else if ((step == MethodName))
        {
          if (part == MethodNamePart)
            {
              [method appendString: element];
            }
        }
      else if (classDefined)
        {
          [classDefinition appendString: element];
        }
    }

  position += [element length];
  _preChar = 0;
}

- (void) spaceAndNewLine: (unichar) element 
{
  BOOL newline = NO;

  [super spaceAndNewLine: element];

  if ((element == 0x0A) || (element == 0x0D))
    {
      newline = YES;
    }

  /* Comments */
  if (_commentType != NoComment)
    {
    }
  else if (_stringBegin)
    {
    }
  else
    {
      if (classDefined)
        {
          if (newline)
            {
              MethodNode *node = [[MethodNode alloc] init];
              classDefined = NO;
              [node setName: AUTORELEASE([classDefinition copy])];
              [node setPosition: methodBeginPosition];
              [rootNode addChild: node];
              currentNode = node;
              RELEASE(node);
              [classDefinition setString: @""];
            }

          else
            {
              [classDefinition appendString: [NSString stringWithFormat: @"%c", element]];
            }
        }
        
      if ((newline) && (step == MethodNone))
        {
          step = MethodStart;
          methodBeginPosition = position;
        }
    }

  position++;
  _preChar = element;
}

- (void) symbol: (unichar) element 
{
  [super symbol: element];

  /* Comments */
  if (_commentType != NoComment)
    {
    }
  else if (_stringBegin)
    {
    }
  else
    {
      _preSymbol = element;

      if (step == MethodStart)
        {
          if ((element == '+') || (element == '-'))
            {
              step = MethodSymbol;
              methodBeginPosition = position;
              [method appendString: [NSString stringWithFormat: @"%c ", element]];
            }
          else
            {
              NotMethod;
            }
        }
      else if (step == MethodSymbol)
        {
        }
      else if (step == MethodReturnValue)
        {
        }
      else if (step == MethodName) 
        {
          if (element != '{') /* MethodName */
            {
              if (element == ':')
                {
                  part = MethodSeparatePart;
                  [method appendString: @": "];
                }
            }
        }
      else if (classDefined)
        {
          [classDefinition appendString: [NSString stringWithFormat: @"%c", element]];
        }

      if ((element == ';') || (element == '{') || 
          (element == '}') || (position == 0))
        {
          step = MethodStart;
          part = NotMethodPart;
          if ([method length])
            {
              NSDictionary *dict;

              dict = [NSDictionary dictionaryWithObjectsAndKeys:
                                              AUTORELEASE([method copy]), 
                                                               @"method",
                   [NSNumber numberWithUnsignedInt: methodBeginPosition], 
                                                             @"position",
                                              nil];
              [methods addObject: dict];
              if (currentNode)
                {
                  MethodNode *node = [[MethodNode alloc] init];
                  [node setName: AUTORELEASE([method copy])];
                  [node setPosition: methodBeginPosition];
                  [currentNode addChild: node];
                  RELEASE(node);
                }
            }
          //methodBeginPosition = position;
          [method setString: @""];
        }
    }

  position++;
  _preChar = element;
}

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

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

  method = [[NSMutableString alloc] init];
  classDefinition = [[NSMutableString alloc] init];
  methods = [[NSMutableArray alloc] init];
  rootNode = [[MethodNode alloc] init];
  currentNode = rootNode;

  classDefined = NO;
  step = MethodNone;
  part = NotMethodPart;
  _preSymbol = 0;

  return self;
}

- (void) dealloc
{
  RELEASE(method);
  RELEASE(classDefinition);
  RELEASE(methods);
  RELEASE(rootNode);
  [super dealloc];
}

@end

