/*
   NSTextContainerAndStorage.m

   Author:	H. N. Schaller <hns@computer.org>
   Date:	Jun 2006

   This file is part of the mySTEP Library and is provided
   under the terms of the GNU Library General Public License.
*/

#import <AppKit/NSTextContainer.h>
#import <AppKit/NSTextStorage.h>
#import <AppKit/NSLayoutManager.h>
#import <AppKit/NSTextView.h>

@implementation NSTextContainer

- (NSSize) containerSize; { return size; }
- (BOOL) containsPoint:(NSPoint) point; { NIMP; return NO; }
- (BOOL) heightTracksTextView; { return heightTracksTextView; }

- (id) initWithContainerSize:(NSSize) sz;
{
	if((self=[super init]))
		{
		size=sz;
		}
	return self;
}

- (void) dealloc;
{
	[self setTextView:nil];
	[super dealloc];
}

- (BOOL) isSimpleRectangularTextContainer; { return YES; }
- (NSLayoutManager *) layoutManager; { return layoutManager; }
- (float) lineFragmentPadding; { return lineFragmentPadding; }
- (NSRect) lineFragmentRectForProposedRect:(NSRect) proposedRect
			 sweepDirection:(NSLineSweepDirection) sweepDirection
			 movementDirection:(NSLineMovementDirection) movementDirection
			 remainingRect:(NSRect *) remainingRect;
{
	NIMP;
	return NSZeroRect;
}

- (void) replaceLayoutManager:(NSLayoutManager *) newLayoutManager;
{
	int idx;
	[self retain];	// just be sure
	idx=[[layoutManager textContainers] indexOfObject:self];	// find current text container
	if(idx != NSNotFound)
		[layoutManager removeTextContainerAtIndex:idx];			// remove us from our old layout manager
	[self setLayoutManager:newLayoutManager];
	[layoutManager insertTextContainer:self atIndex:idx];	// connect to the new layout manager
	[self release];
}

- (void) setContainerSize:(NSSize) sz; { size=sz; }
- (void) setHeightTracksTextView:(BOOL) flag; { heightTracksTextView=flag; }
- (void) setLayoutManager:(NSLayoutManager *) lm; { layoutManager=lm; }
- (void) setLineFragmentPadding:(float) pad; { lineFragmentPadding=pad; }
- (void) setTextView:(NSTextView *) tv; { [textView setTextContainer:nil]; ASSIGN(textView, tv); [textView setTextContainer:self]; }
- (void) setWidthTracksTextView:(BOOL) flag; { widthTracksTextView=flag; }
- (NSTextView *) textView; { return textView; }
- (BOOL) widthTracksTextView; { return widthTracksTextView; }

- (void) encodeWithCoder:(NSCoder *) coder;
{
	NIMP;
}

- (id) initWithCoder:(NSCoder *) coder;
{
	int tcFlags=[coder decodeInt32ForKey:@"NSTCFlags"];
#if 0
	NSLog(@"%@ initWithCoder: %@", self, coder);
#endif
#define HEIGHTTRACKS ((tcFlags&0x01)!=0)
	heightTracksTextView=HEIGHTTRACKS;
#define WIDTHTRACKS ((tcFlags&0x02)!=0)
	widthTracksTextView=WIDTHTRACKS;
	layoutManager=[coder decodeObjectForKey:@"NSLayoutManager"];
	textView=[[coder decodeObjectForKey:@"NSTextView"] retain];
	size.height=[coder decodeFloatForKey:@"NSHeight"];
	size.width=[coder decodeFloatForKey:@"NSWidth"];
#if 0
	NSLog(@"%@ done", self);
#endif
	return self;
}

@end

@implementation NSTextStorage

- (id) init;
{
	if((self=[super init]))
		{
#if __APPLE__
		concreteString=[NSMutableAttributedString new];
#endif
		layoutManagers=[NSMutableArray new];
		}
	return self;
}

- (void) dealloc;
{
#if __APPLE__
	[concreteString release];
#endif
	[layoutManagers release];
	[self setDelegate:nil];
	[super dealloc];
}

- (void) addLayoutManager:(NSLayoutManager *)lm; { [layoutManagers addObject:lm]; }
- (int) changeInLength; { NIMP; return 0; }
- (id) delegate; { return delegate; }

- (void) edited:(unsigned)editedMask 
		  range:(NSRange)range 
 changeInLength:(int)delta;
{
	NIMP;
}

- (void) beginEditing;
{
}

- (void) endEditing;
{
//	[self fixAttributesInRange:editedRange];
// inform NSLayoutManager(s)
}

- (unsigned int) editedMask; { NIMP; return 0; }
- (NSRange) editedRange; { return editedRange; }
- (void) ensureAttributesAreFixedInRange:(NSRange)range;
{
	NIMP;
}

- (BOOL) fixesAttributesLazily; { return fixesAttributesLazily; }

- (void) invalidateAttributesInRange:(NSRange)range;
{
	NIMP;
}

- (NSArray *) layoutManagers; { return layoutManagers; }
- (void) processEditing;
{
	NIMP;
	return;
}

- (void) removeLayoutManager:(NSLayoutManager *)obj; { [layoutManagers removeObject:obj]; }

- (void) setDelegate:(id)obj;
{
	if(delegate)
		; // disconnect notifications
	delegate=obj;
	if(delegate)
		; // connect notifications
}

- (NSArray *) attributeRuns; { return NIMP; }
- (NSArray *) characters; { return NIMP; }
- (NSFont *) font; { return NIMP; }
- (NSColor *) foregroundColor; { return NIMP; }
- (NSArray *) paragraphs; { return NIMP; }
- (void) setAttributeRuns:(NSArray *)attributeRuns; { NIMP; return; }
- (void) setCharacters:(NSArray *)characters; { NIMP; return; }
- (void) setFont:(NSFont *)font; { NIMP; return; }
- (void) setForegroundColor:(NSColor *)color; { NIMP; return; }
- (void) setParagraphs:(NSArray *)paragraphs; { NIMP; return; }
- (void) setWords:(NSArray *)words; { NIMP; return; }
- (NSArray *) words; { return NIMP; }

- (void) encodeWithCoder:(NSCoder *) coder;
{
	[super encodeWithCoder:coder];
}

- (id) initWithCoder:(NSCoder *) coder;
{
#if 0
	NSLog(@"%@ initWithCoder: %@", self, coder);
	NSLog(@"NSAttributes=%@", [coder decodeObjectForKey:@"NSAttributes"]);
	NSLog(@"NSString=%@", [coder decodeObjectForKey:@"NSString"]);
	NSLog(@"NSAttributeInfo=%@", [coder decodeObjectForKey:@"NSAttributeInfo"]);	// NSData(!)
	NSLog(@"NSDelegate=%@", [coder decodeObjectForKey:@"NSDelegate"]);
#endif
#if __APPLE__
	concreteString=[[NSMutableAttributedString alloc] initWithCoder:coder];
#else
	self=[super initWithCoder:coder];	// we are a real subclass of NSMutableAttributedString
	NSLog(@"FIXME: doesn't unarchive textStorage's attributes properly");
	// FIXME: these should be decoded in NSAttributedString!
	[coder decodeObjectForKey:@"NSAttributes"];	// this is an array of attribute runs
	[coder decodeObjectForKey:@"NSAttributeInfo"];	// NSAttributeInfo is most probably a list of ranges where the attributes apply (unless it is for the full range)
#endif
	[self setDelegate:[coder decodeObjectForKey:@"NSDelegate"]];
#if 0
	NSLog(@"%@ done", self);
#endif
	return self;
}

#if __APPLE__

// reimplement NSMutableAttributedString methods as wrappers for concreteString since we are a semiconcrete subclass of Apple's foundation

- (NSString *) string;
{
	// we might cache since this is called pretty often
	return [concreteString string];
}

- (NSMutableString *) mutableString;
{
	// we might cache since this is called pretty often
	return [concreteString mutableString];
}

- (void) replaceCharactersInRange:(NSRange) rng withAttributedString:(NSAttributedString *) str
{
	return [concreteString replaceCharactersInRange:rng withAttributedString:str];
}

- (void) replaceCharactersInRange:(NSRange) rng withString:(NSString *) str
{
	return [concreteString replaceCharactersInRange:rng withString:str];
}

- (NSDictionary *) attributesAtIndex:(unsigned) index effectiveRange:(NSRangePointer) range
{
	return [concreteString attributesAtIndex:index effectiveRange:range];
}

- (void) setAttributes:(NSDictionary *)attributes range:(NSRange)aRange
{
	[concreteString setAttributes:attributes range:aRange];
}

#endif

@end

NSString *NSTextStorageDidProcessEditingNotification=@"NSTextStorageDidProcessEditingNotification";
NSString *NSTextStorageWillProcessEditingNotification=@"NSTextStorageWillProcessEditingNotification";

