/* Variable.m created by ovidiu on Sun 30-Mar-1997 */

#include <stdio.h>

#import <Foundation/NSString.h>
#import <Foundation/NSArray.h>
#import <Foundation/NSValue.h>
#import "GdbDisplayController.h"
#import "Frame.h"
#import "Variable.h"

#define ASSIGN(variable, value) \
  [value retain]; \
  [variable release]; \
  variable = value;


@implementation Variable
- (void)setName:(NSString*)aString		{ ASSIGN(name, aString); }
- (NSString*)name				{ return name; }
- copyWithZone:(NSZone*)zone			{ return self; }

- (void)setValue:(Value*)aValue
{
  ASSIGN(value, aValue);
  [value setGdbDisplayController:gdbController];
}

- (void)setGdbDisplayController:(GdbDisplayController*)anObject
{
  gdbController = anObject;
  [value setGdbDisplayController:gdbController];
}

- (void)dealloc
{
  [name release];
  [value release];
  [super dealloc];
}

- (NSString*)description
{
  return [NSString stringWithFormat:@"%@ = %@", name, value];
}

/* GdbDisplayValue protocol's methods */

- (NSString*)title				{ return name; }
- (NSString*)stringValue       			{ return [value stringValue]; }
- (NSString*)additionalDescription		{ return nil; }
- (Value*)value					{ return value; }

- (NSArray*)indirectedComponents
{
  return [value indirectedComponents];
}

- (BOOL)indirectedComponentsAreKnown
{
  return [value indirectedComponentsAreKnown];
}

- (void)getIndirectedComponentsFromGDB
{
  [value getIndirectedComponentsFromGDB];
}

@end /* Variable */


@implementation Type
- (void)setTypeName:(NSMutableString*)typeName	{ ASSIGN(name, typeName); }
- (void)setScalarTypeKind:(tScalarTypeKind)type	{ scalarKind = type; }
- (NSMutableString*)typeName			{ return name; }
- (tTypeKind)typeKind				{ return kind; }
- (tScalarTypeKind)scalarTypeKind		{ return scalarKind; }
- (NSString*)description			{ return name; }

- (void)setTypeKind:(tTypeKind)type
{
  if (kind == kScalar && scalarKind == kChar && type == kPointer)
    kind = kCString;
  else if (kind == kVoid && type == kPointer)
    kind = kVoidPointer;
  else
    kind = type;
}

- (Class)valueClass
{
  switch (kind) {
    case kVoid:		return [VoidValue class];
    case kScalar:	return [SimpleValue class];
    case kEnum:		return [EnumerationValue class];
    case kStructure:	return [StructureValue class];
    case kClass:	return [ClassValue class];
    case kUnion:	return [UnionValue class];
    case kArray:	return [ArrayValue class];
    case kCString:
    case kVoidPointer:
    case kPointer:	return [PointerValue class];
    default:		return nil;
  }
}

- (void)dealloc
{
  [name release];
  [super dealloc];
}
@end /* Type */


@implementation Value
- (void)setType:(Type*)aType			{ ASSIGN(type, aType); }
- (Type*)type					{ return type; }
- (void)setStringValue:(NSString*)value	       	{}

- (void)setGdbDisplayController:(GdbDisplayController*)anObject
{
  gdbController = anObject;
}

- (void)dealloc
{
  [type release];
  [super dealloc];
}

- copyWithZone:(NSZone*)zone
{
  return [self retain];
}

/* GdbDisplayValue protocol's methods */
- (NSString*)title				{ return @""; }
- (NSString*)stringValue			{ return @""; }
- (NSString*)additionalDescription		{ return nil; }
- (Value*)value					{ return self; }
- (NSArray*)indirectedComponents		{ return nil; }
- (BOOL)indirectedComponentsAreKnown		{ return YES; }
- (void)getIndirectedComponentsFromGDB		{}
@end /* Value */


@implementation VoidValue
- (NSString*)description			{ return @"void "; }
@end


@implementation SimpleValue
+ (SimpleValue*)numberWithString:(NSString*)string
{
  SimpleValue* value = [[[self alloc] init] autorelease];
  value->stringNumber = [string copy];
  return value;
}

- (void)dealloc
{
  [stringNumber release];
  [description release];
  [super dealloc];
}

- (void)setStringValue:(NSString*)value		{ ASSIGN(stringNumber, value); }
- (void)setDescription:(NSString*)str		{ ASSIGN(description, str); }
- (NSString*)additionalDescription		{ return description; }
- (NSString*)stringValue			{ return stringNumber; }

- (NSString*)description
{
  if (description)
    return [NSString stringWithFormat:@"(%@) %@ %@",
                type, stringNumber, description];
  else
    return [NSString stringWithFormat:@"(%@) %@", type, stringNumber];
}
@end /* SimpleValue */


@implementation EnumerationValue
- (void)setStringValue:(NSString*)val		{ ASSIGN(value, val); }
- (NSString*)stringValue			{ return value; }

- (void)dealloc
{
  [value release];
  [super dealloc];
}

- (NSString*)description
{
  return [NSString stringWithFormat:@"(%@) %@", type, value];
}
@end


@implementation AggregateValue
- (BOOL)isStructure				{ return NO; }
- (BOOL)isClass					{ return NO; }
- (BOOL)isUnion					{ return NO; }
- (BOOL)isArray					{ return NO; }
- (NSArray*)indirectedComponents		{ return componentValues; }

- (void)setArrayValue:(NSMutableArray*)value
{
  int i, count = [value count];

  ASSIGN(componentValues, value);
  for (i = 0; i < count; i++)
    [[componentValues objectAtIndex:i] setGdbDisplayController:gdbController];
}

- (void)dealloc
{
  [componentValues release];
  [super dealloc];
}

- (NSString*)description
{
  NSMutableString* description = [NSMutableString string];
  int i, count = [componentValues count];
  BOOL firstSeen = NO;

  [description appendFormat:@"(%@) {\n", type];
  for (i = 0; i < count; i++) {
    if (firstSeen)
      [description appendString:@",\n"];
    else
      firstSeen = YES;
    [description appendString:[[componentValues objectAtIndex:i] description]];
  }
  [description appendString:@"}\n"];

  return description;
}

@end /* AggregateValue */

@implementation StructureValue
- (BOOL)isStructure		{ return YES; }
@end

@implementation ClassValue
- (BOOL)isClass			{ return YES; }
@end

@implementation UnionValue
- (BOOL)isUnion			{ return YES; }
@end

@implementation ArrayValue
- (BOOL)isArray			{ return YES; }
@end


@implementation PointerValue
+ (PointerValue*)pointerWithAddress:(NSString*)address
{
  PointerValue* value = [[[self alloc] init] autorelease];
  value->addressString = [address copy];
  return value;
}

- (void)setStringValue:(NSString*)val  		{ ASSIGN(addressString, val); }
- (void)setDescription:(NSString*)str		{ ASSIGN(description, str); }

/* GdbDisplayValue protocol's methods */
- (id)stringValue      				{ return addressString; }
- (NSString*)additionalDescription		{ return description; }

- (NSArray*)indirectedComponents
{
  if (indirectedValue) {
    if ([indirectedValue isKindOfClass:[NSArray class]])
      return indirectedValue;
    else
      return [NSArray arrayWithObject:indirectedValue];
  }
  else
    return nil;
}

- (BOOL)indirectedComponentsAreKnown
{
  return indirectedValue != nil;
}

- (void)getIndirectedComponentsFromGDB
{
  NSString* command;

  /* Avoid recursivity in the case of a parse error in the GDB output */
  if (printCommandExecuted)
    return;

  command = [NSString stringWithFormat:@"print-typed *(%@)%@",
                                        [self type], [self stringValue]];
//  NSLog (@"execute '%@'", command);
  [gdbController executeGDBCommand:command
                          annotate:NO
                      notifyObject:self
                          selector:@selector(indirectedValue:type:)];
}

- (void)indirectedValue:(NSString*)gdbOutput type:(GdbOutputType)gdbOutputType
{
  NSArray* array;

  if (gdbOutputType != GDB_OUTPUT_ANNOTATION)
    return;

//  NSLog (@"received '%@'", gdbOutput);
  printCommandExecuted = YES;
  [indirectedValue release];
  array = [Variable variablesFromDescription:gdbOutput];
  indirectedValue = [[array objectAtIndex:0] value];

  /* If the value is a structure then indirect it */
  if ((array = [indirectedValue indirectedComponents]))
    indirectedValue = array;
  [indirectedValue retain];

  [indirectedValue setGdbDisplayController:gdbController];

  [gdbController updateCurrentFrame];
}

@end /* PointerValue */
