/****************************************************************************
 *   Copyright (C) 2004 by Arboretum Systems, Inc.                          *
 *   Technical administrator: Alain Mazy, hav@mazy.be                       *
 *   Lead program designer: Georges Jaroslaw, gjaro@arboretum.com           *
 *                                                                          *
 *   HyperEngine-AV is a video, audio and text editor that can be used to   *
 *   record, import, edit, process and arrange together video, sound and    *
 *   text. These are all achieved in the program's free-form document       *
 *   window, with no limitations to the number of tracks.                   *
 *   The purpose of this program is to provide to users at all levels of    *
 *   expertise a readily accessible tool enabling them to create movies,    *
 *   slide shows or presentations.                                          *
 *                                                                          *
 *   HyperEngine-AV itself is free software. However, plug-ins that can be  *
 *   used as add-ons to HyperEngine-AV may or may not be free software, at  *
 *   the discretion of each plug-in developer and as specified by these     *
 *   plug-ins' respective licenses.                                         *
 *   You can redistribute HyperEngine-AV itself 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.                                             *
 *                                                                          *
 *   HyperEngine-AV 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 all applicable details.                 *
 *                                                                          *
 *   You should have received a copy of the GNU General Public License      *
 *   along with this program; if not, write to:                             *
 *   Free Software Foundation, Inc.,                                        *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.              *
 ****************************************************************************/

#ifndef TArmeWSObj_h
#include "TArmeWSObj.h"
#endif //TArmeWSObj_h

#ifndef LibraryToggle_h
#include "LibraryToggle.h"
#endif //LibraryToggle_h

#define USE_NEW_DRAW_GRID

//#ifndef BOPTask_h
//#include "BOPTask.h"
//#endif //BOPTask_h

#import "MITopLevelContainerRep.h"
#import "MIObjectRep.h"
#import "MIMainViewTrackers.h"
#import "MIObject.h"
#import "MIMainViewController.h"
#import "MIMontageDocument.h"
#import "MIApplicationController.h"
#import "MIRuler.h"
#import "MITimePaletteController.h"
#import "MICreateWSObjsFromFilesCommand.h"
#import "MIPreferences.h"
#import "MISnapperDB.h"
#import "MITime.h"
#import "MIApplication.h"
#import "MIApplicationController.h"

#import "MILibraryElement.h"
#import "MISliceSelectionTracker.h"

#if USE_LIBRARY
#import "MICreateClipsFromLibraryElementsCommand.h"
#endif //USE_LIBRARY

#ifndef ZzTimer_h
#include "ZzTimer.h"
#endif ZzTimer_h

const float			kRightMarginToMoveVisibleRect = 0.99;
const float			kLeftMarginToMoveVisibleRectTo = 0.01;
const int			kSnappingThreshold = 15;

bool				gDeferRedrawsUntilCommandEnd = NO;
NSRect				gDeferedRedrawRect = NSZeroRect;

#undef VER_DEF_TOPIC
#define VER_DEF_TOPIC MITopLevelContainerRep

@implementation MITopLevelContainerRep

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
	{
		fMouseTracker = nil;
		fDrawRedrawRects = NO;
        fBackgroundColor = [[NSColor grayColor] retain];
        fMainViewController = nil;
        [self registerForDraggedTypes:[[MIApplicationController sharedApplicationController] pasteboardTypes]];
		fShouldDrawPlaybar = YES;
		fDropEnabled = YES;
    }
    return self;
}

- (void)dealloc
{
    [fBackgroundColor release];
    [self unregisterDraggedTypes];
    [fPlaybarCacheImageRep release];
    [super dealloc];
}

- (void)awakeFromNib
{
    fMainViewController = [[self window] windowController];
	fDropEnabled = YES;
}

- (void)setMainViewController:(MIMainViewController*)theMainViewController
{
    fMainViewController = theMainViewController;
}

- (MIMainViewController*)mainViewController
{
    if ( !fMainViewController )
    {
        verntl(interfaceStephan,0,"main view controller not set for this top level container");
    }
    
    return fMainViewController;
}

- (MITopLevelContainerRep*)getTopLevelContainerRep
{
	return self;
}

- (NSRect)minimalRectToFitContent
{
	return [self MIRectToNSRect:[fRepresentedObject minimalRectToFitContent]];
}

- (ArmeTime)pixelToArmeTime:(float)pixels
{
    return [fMainViewController pixelToArmeTime:pixels];
}

- (float)armeTimeToPixel:(ArmeTime)time
{
    return [fMainViewController armeTimeToPixel:time];
}

- (double)doubleTimeToPixel:(double)time
{
	return [fMainViewController doubleTimeToPixel:time];
}

- (double)pixelToDoubleTime:(float)pixels
{
	return [fMainViewController pixelToDoubleTime:pixels];
}

- (MIVPos)pixelToMIVPos:(float)pixels
{
	return [fMainViewController pixelToMIVPos:pixels];
}

- (float)MIVPosToPixel:(MIVPos)vpos
{
	return [fMainViewController MIVPosToPixel:vpos];
}

- (NSRect)MIRectToNSRect:(MIRect)rect
{
	return [fMainViewController MIRectToNSRect:rect];
}

- (MIPoint)NSPointToMIPoint:(NSPoint)point
{
	return [fMainViewController NSPointToMIPoint:point];
}

- (MIRect)NSRectToMIRect:(NSRect)rect
{
	return [fMainViewController NSRectToMIRect:rect];
}

- (void)setBackgroundColor:(NSColor*)color
{
    [color retain];
    [fBackgroundColor release];
    fBackgroundColor = color;
}

- (NSColor*)getBackgroundColor
{
	return fBackgroundColor;
}

extern bool gEnableCursorRectsUpdate;

- (void)resetCursorRects
{
	// used to recreate the cursor rectangles, called each time the view scrolls or the focus has changed and comes back here.
	if ( !gEnableCursorRectsUpdate )
		return;

	// $$$TODO: restrict this only to visible object reps
	MIObject		*aChild;
//	NSEnumerator	*childEnum;

//	childEnum = [[fRepresentedObject getChildren] objectEnumerator];
	for(UInt32 childEnumIndex = 0; childEnumIndex < [[fRepresentedObject getChildren] count]; childEnumIndex++)
	//while ( aChild = [childEnum nextObject] )
	{
		aChild = [[fRepresentedObject getChildren] objectAtIndex:childEnumIndex];
		[aChild addCursorRectsInTLC:self];
	}

//	[fRepresentedObject addCursorRectsInTLC:self];
}

- (NSRect)getTLCFrame
{
    return [self frame];
}

- (void)setRepresentedObject:(MIObject*)object
{
	fRepresentedObject = object ; // NO REF COUNT HERE. JUST LIKE MIOBJECTREP
}

- (MIObject*)representedObject
{
	return fRepresentedObject;
}

-(BOOL)isOpaque
{
	// this function is used to tell the window manager that there's no need to draw anything behind.
	return YES;
}


//#define TIME_MITopLevelContainerRep_drawRect
- (void)drawSelection:(NSRect)clippingRect
{
	//MTGStartTimeLog
	// now let's draw the selection if there is any for this clip
	MIWSSelection* sel = [[[self getTopLevelContainerRep] mainViewController] selection];
	if(([sel type] == kMIWSSelectionTypeTimeSlice) && [sel containsObject:self])
	{
		// 	kMIWSSelectionTypeTimeSlice,
		// kMIWSSelectionTypeObjects
		float start, endx;
		
		// if it's a slice selection, only draw a slice
		start = [[self mainViewController] armeTimeToPixel:[sel startTime]];
		endx = [[self mainViewController] armeTimeToPixel:[sel endxTime]];
		// maybe it's a zero length selection, which is still a selection
		if(start==endx)
			endx = start+1;
		if(start > endx)
		{
			float tmp = start;
			start = endx;
			endx = tmp;
		}
		NSRect tlcFrame = [self frame];
		if ( start < NSMinX(tlcFrame) )
			start = NSMinX(tlcFrame);
		if ( endx > NSMaxX(tlcFrame) )
			endx = NSMaxX(tlcFrame);
			
		[[NSColor colorWithCalibratedRed:0.0 green:0.0 blue:1.0 alpha:0.5] set];
		[NSBezierPath fillRect:NSMakeRect(start, clippingRect.origin.y, endx-start, clippingRect.size.height)];
	}
	//MTGEndTimeLog(@"MIObjectRep",@"drawSelection:drawNow:")
}


- (void)drawRect:(NSRect)aRect
{
//	vernl(4,"drawRect called with " << aRect);
//	vernl(0,"************** MITopLevelContainerRep drawRect ************");
	
#ifdef TIME_MITopLevelContainerRep_drawRect
	ZZTIMERS_USED_HERE;
	ZZSTART_TIMER("drawRect");
#endif //TIME_MITopLevelContainerRep_drawRect

//	MTGStartTimeLog
//	NSEnumerator		*childrenEnum;
	MIObject			*aChild;
	NSRect				childrenFrame;
	if([[MIApplicationController sharedApplicationController] mainViewRedrawDisabled])
		return;
		     
	if ( [MIPreferences uniformBackground] )
	{
//		[[NSColor colorWithCalibratedRed:0.686 green:0.737 blue:0.808 alpha:1.0] set];
//		[[NSColor whiteColor] set];
		[[[MIPreferences sharedPrefs] workspaceBGColor] set];
		[NSBezierPath fillRect:aRect];
	}
	else
	{
		// draw the standard window background
		NSDrawWindowBackground(aRect);
		
		// draw the HyperEngine-AV color alpha layer
		[[NSColor colorWithCalibratedRed:0.686 green:0.737 blue:0.808 alpha:0.5] set];
		[NSBezierPath fillRect:aRect];
	}


#ifdef USE_NEW_DRAW_GRID
	[self drawGrid:aRect];
#else //#ifdef USE_NEW_DRAW_GRID
	$$$
	// draw the grid if need be
	if ( [fMainViewController gridFlags] & MIShowGrid )
	{
		[self drawGuides:aRect];
	}
#endif //#ifndef USE_NEW_DRAW_GRID
	
	
	// Draw all the children from here
	
//    childrenEnum = [[fRepresentedObject getChildren] objectEnumerator];	
	SInt32 startTime;
	for(UInt32 childrenEnumIndex = 0; childrenEnumIndex < [[fRepresentedObject getChildren] count]; childrenEnumIndex++)
//    while ( aChild = [childrenEnum nextObject] )
    {
		aChild = [[fRepresentedObject getChildren] objectAtIndex:childrenEnumIndex];
		TArmeWSObj* wsChild = [aChild WSObject];
//		vernl(0,"MITopLevelContainerRep drawRect wsChild->GetName() = " << wsChild->GetName());
		startTime = (SInt32)(GET_VAL(wsChild->GetStartTime()));
//		vernl(0,"MITopLevelContainerRep drawRect startTime = " << startTime << " wsChild->GetStartTime() = " << wsChild->GetStartTime());
		if ([aChild WSObject]->GetType() == TArmeWSObj::kVideoXFadeEffect)
		{
			childrenFrame = [[aChild findRepresentationInTLC:self] frame];
			if ( NSContainsRect(aRect, childrenFrame) ||
				NSIntersectsRect(aRect, childrenFrame ) )
			{
				[aChild drawRect:aRect inTLC:self withOffset:[self bounds].origin];
			}
        }
    }

	//childrenEnum = [[fRepresentedObject getChildren] objectEnumerator];
	
	for(UInt32 childrenEnumIndex = 0; childrenEnumIndex < [[fRepresentedObject getChildren] count]; childrenEnumIndex++)
	//while ( aChild = [childrenEnum nextObject] )
	{
		aChild = [[fRepresentedObject getChildren] objectAtIndex:childrenEnumIndex];
		if ([aChild WSObject]->GetType() != TArmeWSObj::kVideoXFadeEffect)
		{
			childrenFrame = [[aChild findRepresentationInTLC:self] frameIncludingShadow];
			if ( NSContainsRect(aRect, childrenFrame) ||
				NSIntersectsRect(aRect, childrenFrame ) )
			{
				[aChild drawRect:aRect inTLC:self withOffset:[self bounds].origin];
			}
		}
	}

	if ( fMouseTracker )
	{
		[fMouseTracker draw:aRect];
	}
	
	[self drawMarkers];
	[self drawLocators];
	[self cacheAndDrawPlaybar:aRect];
	[self drawSelection:aRect];


// uncomment the following to check what is being displayed   
	if ( fDrawRedrawRects )
	{
		[[NSColor magentaColor] set];
		[[NSBezierPath bezierPathWithRect:aRect] stroke];
	}


/*
	!!!!! EXPERIMENTAL: rect queues !!!!!
	see comment at the end of this file
*/
//  [self debugDrawSnapperDBLines:aRect];
	////MTGEndTimeLog(@"MITopLevelContainerRep",@"drawRect:")
#ifdef AUTOMATION_DATA
	NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithObject:[NSFont fontWithName:@"Lucida Grande" size:36] forKey:NSFontAttributeName];
	[dic setObject:[NSColor redColor] forKey:NSForegroundColorAttributeName];
	[@"A ENABLED!!" drawAtPoint:NSZeroPoint withAttributes:dic];
#endif
#ifdef TIME_MITopLevelContainerRep_drawRect
	ZZEND_TIMER();
#endif //TIME_MITopLevelContainerRep_drawRect
}

-(void)debugDrawSnapperDBLines:(NSRect)aRect;
{
	NSEnumerator* snapObjEnum = [[[fRepresentedObject montageDoc] snapperDB] objectEnumerator];
	MIObjectBoundsInfo* snapInfo;
	while(snapInfo = [snapObjEnum nextObject])
	{
		float startVLine = [fMainViewController armeTimeToPixel:snapInfo->fStart];
		[[NSColor greenColor] set];
		[NSBezierPath strokeLineFromPoint: NSMakePoint(startVLine,NSMinY(aRect)) toPoint:NSMakePoint(startVLine,NSMaxY(aRect))];
		
		float endxVLine = [fMainViewController armeTimeToPixel:snapInfo->fEndx];
		[[NSColor redColor] set];
		[NSBezierPath strokeLineFromPoint: NSMakePoint(endxVLine,NSMinY(aRect)) toPoint:NSMakePoint(endxVLine,NSMaxY(aRect))];

		float bottomHLine = [fMainViewController MIVPosToPixel:snapInfo->fBottom];
		[[NSColor greenColor] set];
		[NSBezierPath strokeLineFromPoint: NSMakePoint(NSMinX(aRect),bottomHLine) toPoint:NSMakePoint(NSMaxX(aRect),bottomHLine)];
		
		float bodyTopxHLine = [fMainViewController MIVPosToPixel:snapInfo->fBodyTopx];
		[[NSColor blueColor] set];
		[NSBezierPath strokeLineFromPoint: NSMakePoint(NSMinX(aRect),bodyTopxHLine) toPoint:NSMakePoint(NSMaxX(aRect),bodyTopxHLine)];
		
		float topxHLine = [fMainViewController MIVPosToPixel:snapInfo->fTopx];
		[[NSColor redColor] set];
		[NSBezierPath strokeLineFromPoint: NSMakePoint(NSMinX(aRect),topxHLine) toPoint:NSMakePoint(NSMaxX(aRect),topxHLine)];
	}
}

#ifndef USE_NEW_DRAW_GRID
$$$$$$$$$
- (void)drawGuides:(NSRect)aRect
{
	NSEnumerator		*guideEnum;
	MIGuide				*aGuide;
	float				tmpVal;
	float				minX, maxX, minY, maxY;
	
	minX = NSMinX(aRect);
	maxX = NSMaxX(aRect);
	minY = NSMinY(aRect);
	maxY = NSMaxY(aRect);
	
	guideEnum = [fGuides objectEnumerator];
	
	[[NSColor blackColor] set];
	
	while ( aGuide = [guideEnum nextObject] )
	{
		if ( [aGuide object] )
			[[NSColor grayColor] set];
		else
			[[NSColor blackColor] set];
		
		if ( [aGuide type] == MIHorizontalGuide )
		{
			tmpVal = [self MIVPosToPixel:[aGuide VPos]];
			if ( tmpVal >= minY && tmpVal <= maxY )
			{
// Rounding test
//				[NSBezierPath strokeLineFromPoint:	NSMakePoint(minX, tmpVal-0.5) toPoint:	NSMakePoint(maxX, tmpVal-0.5)];
				[NSBezierPath strokeLineFromPoint:	NSMakePoint(minX, tmpVal) toPoint:	NSMakePoint(maxX, tmpVal)];
			}
		}
		else if ( [aGuide type] == MIVerticalGuide )
		{
			tmpVal = [self armeTimeToPixel:[aGuide time]];
			if ( tmpVal >= minX && tmpVal <= maxX )
			{
// Rounding test
//				[NSBezierPath strokeLineFromPoint:	NSMakePoint(tmpVal-0.5, minY) toPoint:	NSMakePoint(tmpVal-0.5,maxY)];
				[NSBezierPath strokeLineFromPoint:	NSMakePoint(tmpVal, minY) toPoint:	NSMakePoint(tmpVal,maxY)];
			}
		}
	}
}
#endif //#ifndef USE_NEW_DRAW_GRID

/*- (void)setNeedsDisplayInRect:(NSRect)rect {
    if ( [self lockFocusIfCanDraw] ) {
        [[NSColor yellowColor] set];
        [[NSBezierPath bezierPathWithRect:rect] fill];
        [[NSColor magentaColor] set];
        [[NSBezierPath bezierPathWithRect:rect] stroke];
        [[NSGraphicsContext currentContext] flushGraphics];
        [self unlockFocus];
        usleep( 100000 );
    }
    [super setNeedsDisplayInRect:rect];
	//[self displayIfNeeded];
}*/


- (void)redrawBehindPlaybar {
    NSRect visibleRect = [self visibleRect];

	if ( fPlaybarCacheImageRep ) {
		NSPoint pt = NSMakePoint(fPlaybarCachePosition - 1, NSMinY(visibleRect));
		[self lockFocus];
		[fPlaybarCacheImageRep drawAtPoint:pt];
		[self unlockFocus];
		[fPlaybarCacheImageRep release];
		fPlaybarCacheImageRep = nil;
	} else {
		[self setNeedsDisplayInRect:NSMakeRect(fPlaybarCachePosition - 1, NSMinY(visibleRect), 2, NSHeight(visibleRect))];
		[fPlaybarCacheImageRep release];
		fPlaybarCacheImageRep = nil;
		fShouldDrawPlaybar = NO;
		[self displayIfNeeded];
		fShouldDrawPlaybar = YES;
	}
}

- (void)focusCacheAndDrawPlaybar:(NSRect)rect {

	if ( fPlaybarCacheImageRep ) {
		[fPlaybarCacheImageRep release];
		fPlaybarCacheImageRep = nil;
	}

	fPlaybarCachePosition = (int)[self getCurrentPlayBarPosition];
	fCachedVisibleRect = rect;
	if ( [self lockFocusIfCanDraw] ) {
		fPlaybarCacheImageRep  = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(fPlaybarCachePosition - 1, NSMinY(fCachedVisibleRect), 2, NSHeight(fCachedVisibleRect))];

		[self drawPlaybar:rect];
		[[NSGraphicsContext currentContext] flushGraphics];
		[self unlockFocus];
	}
}

- (void)cacheAndDrawPlaybar:(NSRect)rect {

	BOOL useCache = YES;
	

	if ( fPlaybarCachePosition == (int)[self getCurrentPlayBarPosition] ) {
		useCache = NO;
	}

	if ( fPlaybarCacheImageRep ) {
        [fPlaybarCacheImageRep release];
        fPlaybarCacheImageRep = nil;
	}
	

	fPlaybarCachePosition = (int)[self getCurrentPlayBarPosition];
	fCachedVisibleRect = rect;

	if ( useCache ) {
		fPlaybarCacheImageRep  = [[NSBitmapImageRep alloc] initWithFocusedViewRect:NSMakeRect(fPlaybarCachePosition - 1, NSMinY(fCachedVisibleRect), 2, NSHeight(fCachedVisibleRect))];
	}
	[self drawPlaybar:rect];

}

- (void)drawPlaybar:(NSRect)rect {
	if ( fShouldDrawPlaybar ) {
		fPlaybarCachePosition = (int)[self getCurrentPlayBarPosition];
		fCachedVisibleRect = rect;

		[[NSColor blueColor] set];
		/*NSBezierPath *path = [NSBezierPath bezierPath];
		[path moveToPoint:NSMakePoint(fPlaybarCachePosition, NSMinY(rect))];
		[path lineToPoint:NSMakePoint(fPlaybarCachePosition, NSMaxY(rect))];
		[path setLineWidth:2];
		[path stroke];*/
		[NSBezierPath strokeLineFromPoint:NSMakePoint(fPlaybarCachePosition, NSMinY(rect)) toPoint:NSMakePoint(fPlaybarCachePosition, NSMaxY(rect))];
	}
}

- (void)drawLocators
{
    [[NSColor greenColor] set];
    [NSBezierPath strokeLineFromPoint:	NSMakePoint([self getLeftLocatorPosition], NSMinY([self frame]))
                              toPoint:	NSMakePoint([self getLeftLocatorPosition], NSMaxY([self frame]))];

    [[NSColor redColor] set];
    [NSBezierPath strokeLineFromPoint:	NSMakePoint([self getRightLocatorPosition], NSMinY([self frame]))
                              toPoint:	NSMakePoint([self getRightLocatorPosition], NSMaxY([self frame]))];
							  
}

- (void)drawMarkers
{
    MIMontageDocument *document = [fMainViewController document];
    unsigned i;
    float position;
    NSRect visibleRect = [self visibleRect];

    [[NSColor colorWithCalibratedRed:0.5 green:0.5 blue:0.5 alpha:1.0] set];

    for ( i = 0 ; i < [document getMarkerCount] ; i++ )
	{
        position = [self armeTimeToPixel:[document getMarker:i]];

        [NSBezierPath strokeLineFromPoint:NSMakePoint(position, NSMinY(visibleRect))
                                  toPoint:NSMakePoint(position, NSMaxY(visibleRect))];
	}
}

- (void)moveVisibleRectToPlayBar
{
    NSRect	currentVisibleRect = [self visibleRect];
    NSRect	newVisibleRect;

    if ( [self getCurrentPlayBarPosition] < NSMinX(currentVisibleRect)  ||
         ( [self getCurrentPlayBarPosition] - NSMinX(currentVisibleRect) ) >= 
         ( kRightMarginToMoveVisibleRect * NSWidth(currentVisibleRect) )
        )
    {
        newVisibleRect = currentVisibleRect;
        newVisibleRect.origin.x = [self getCurrentPlayBarPosition] - (kLeftMarginToMoveVisibleRectTo * NSWidth(currentVisibleRect));
        [self scrollRectToVisible:newVisibleRect];
    }
}

- (void)CenterOnPoint:(MIPoint)center
{
	NSRect vRect = [self visibleRect];
	
	NSPoint	c;// = [self MIPointToNSPoint:center];
	
	c.x -= NSWidth(vRect)/2;
	c.y -= NSHeight(vRect)/2;
	
	if ( c.x < 0 )
		c.x = 0;
	if ( c.y < 0 )
		c.y = 0;
		
	[self scrollPoint:c];
	
/*
- (void)scrollPoint:(NSPoint)aPoint
Scrolls the receiver's closest ancestor NSClipView so aPoint in the receiver lies at the origin of the NSClipView's bounds rectangle.
*/
}

- (MIPoint)currentCenter
{
	MIPoint p = MIZeroPoint;
	NSRect vRect = [self visibleRect];
	
	p.time = [self pixelToArmeTime:NSMidX(vRect)];
	p.vpos = [self pixelToMIVPos:NSMidY(vRect)];
	
	return p;
}

-(BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
	// this function is used to tell that the view receives the first 'mousedown' event
	return YES;
}

- (void)rightMouseDown:(NSEvent*)theEvent
{
	[self mouseDown:theEvent];
}

- (void)rightMouseDragged:(NSEvent*)theEvent
{
	[self mouseDragged:theEvent];
}

- (void)rightMouseUp:(NSEvent*)theEvent
{
	[self mouseUp:theEvent];
}

- (void)mouseDown:(NSEvent*)theEvent
{
	NSPoint 		mouseLoc;
	unsigned int 	theModifier;
	unsigned int	mask;
	MIObjectRep		*targetObjRep = nil;
	NSRect			targetFrame;

	if ( fMouseTracker )
	{
		verntl(interfaceStephan,0,"Receiving mouseDown even while a mouseTracker already exists in TLC");
		[fMouseTracker release];
                fMouseTracker = nil;
	}

	// modify the modifiers to get rid of the CAPS LOCK, FUNCTION and NUM LOCK keys
	// remaining flags are:
	// NSHelpKeyMask, NSControlKeyMask, NSShiftKeyMask, NSCommandKeyMask, NSAlternateKeyMask

	theModifier = [theEvent modifierFlags];
//	theModifier &= ~(NSAlphaShiftKeyMask|NSNumericPadKeyMask|NSFunctionKeyMask);
	//since I don't know when (10.3 ?), theModifier is almost always 256 and this is not handled correctly afterwards
	mask = (NSHelpKeyMask| NSControlKeyMask| NSShiftKeyMask| NSCommandKeyMask| NSAlternateKeyMask);
	theModifier &= mask;


	// modify the mouse location to get the position in the view coord system.
	mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];

	// find the deepest obj rep hit by the mouse
	targetObjRep = [self hitTestForMIObject:mouseLoc];

	// send a double click event to the view if clickcount equals 2
	if ( targetObjRep && [theEvent clickCount] == 2 )
	{
		if ( [targetObjRep doubleClick:[targetObjRep convertPointFromTLCCoords:mouseLoc] modifier:theModifier] )
			return;
	}

	// check if a one click action has been done in the object itself and if more mousetracking is needed
	if ( targetObjRep )
    {
        NSPoint					mouseLocInView;
        MIObjectMouseHandling	result;
        
		// verify a second time that the mouse location is within the object
        targetFrame = [targetObjRep getTLCFrame];
        
		// convert the mouse location to the object's coordinate system 
        mouseLocInView = [targetObjRep convertPointFromTLCCoords:mouseLoc];
        if ( NSPointInRect(mouseLoc, targetFrame) )
        {
			// check if the object did something with the mouse event
            result = [targetObjRep handleMoreMouseTracking:mouseLocInView modifier:theModifier type:[theEvent type]];

			if ( result == MIStopMouseHandling  )
				return;

			if ( result == MIAskMeATracker &&
				(fMouseTracker = [targetObjRep getTheMouseTracker:mouseLocInView]) )
            {
				[fMouseTracker retain];
				[targetObjRep invalidateTheMouseTracker];
//				[fMouseTracker start:mouseLoc withModifiers:theModifier];
//				return;
            }
        }
    }
    
	// if no mouse tracker exist, create a selection tracker
    if ( !fMouseTracker )
	{
/*
		// if alternate is pressed, created a slice selection tracker
		if( theModifier & NSAlternateKeyMask )
		{
			fMouseTracker = [[MISliceSelectionTracker alloc] initWithObjectRep:self inView:self 
								atPos:mouseLoc withModifiers:nil];
		}
		else
*/
			fMouseTracker = [[MISelectionTracker alloc] initWithView:self atPos:mouseLoc withModifiers:theModifier];

	}
	
	// start the mouse tracker
	[fMouseTracker start:mouseLoc withModifiers:theModifier];

}

- (void)mouseDragged:(NSEvent *)theEvent
{
	NSPoint			mouseLoc;
	unsigned int	theModifier;
	unsigned int	mask;

	mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];

	theModifier = [theEvent modifierFlags];

//	theModifier &= ~(NSAlphaShiftKeyMask|NSNumericPadKeyMask|NSFunctionKeyMask);
	//since I don't know when (10.3 ?), theModifier is almost always 256 and this is not handled correctly afterwards
	mask = (NSHelpKeyMask| NSControlKeyMask| NSShiftKeyMask| NSCommandKeyMask| NSAlternateKeyMask);
	theModifier &= mask;
	// remaining flags are:
	// NSHelpKeyMask, NSControlKeyMask, NSShiftKeyMask, NSCommandKeyMask, NSAlternateKeyMask

	[self autoscroll:theEvent];
	[fMouseTracker mouseMoved:mouseLoc withModifiers:theModifier];
}

- (void)mouseUp:(NSEvent *)theEvent
{
	NSPoint			mouseLoc;
	unsigned int	theModifier;
	unsigned int	mask;
	
	mouseLoc = [self convertPoint:[theEvent locationInWindow] fromView:nil];
	theModifier = [theEvent modifierFlags];

//	theModifier &= ~(NSAlphaShiftKeyMask|NSNumericPadKeyMask|NSFunctionKeyMask);
	//since I don't know when (10.3 ?), theModifier is almost always 256 and this is not handled correctly afterwards
	mask = (NSHelpKeyMask| NSControlKeyMask| NSShiftKeyMask| NSCommandKeyMask| NSAlternateKeyMask);
	theModifier &= mask;
	// remaining flags are:
	// NSHelpKeyMask, NSControlKeyMask, NSShiftKeyMask, NSCommandKeyMask, NSAlternateKeyMask

	[fMouseTracker mouseMoved:mouseLoc withModifiers:theModifier];
	[fMouseTracker stop:mouseLoc withModifiers:theModifier];
	[fMouseTracker release];
	fMouseTracker = nil;

	if ( [[fMainViewController selection] count] )
	{
		[[MITimePaletteController sharedTimePaletteController] setFeedbackType:MITimePaletteSelectionFeedback];
		[[MITimePaletteController sharedTimePaletteController] setFeedbackObject:[fMainViewController selection]];
	}
	else
		[[MITimePaletteController sharedTimePaletteController] setFeedbackType:MITimePaletteLocatorsFeedback];

	[[[MIApplicationController sharedApplicationController] timePaletteController] getValuesFromMainView];
}

- (ArmeTime)getCurrentPlayBarTime
{
	return fCurrentPlayBarPosition;
}

- (ArmeTime)getLeftLocatorTime
{
	return fLeftLocatorPosition;
}

- (ArmeTime)getRightLocatorTime
{
	return fRightLocatorPosition;
}


- (float)getCurrentPlayBarPosition
{
    return [self armeTimeToPixel:fCurrentPlayBarPosition];
}

- (float)getLeftLocatorPosition
{
	return [self armeTimeToPixel:fLeftLocatorPosition];
}

- (float)getRightLocatorPosition
{
	return [self armeTimeToPixel:fRightLocatorPosition];
}

- (MIPoint)newObjectLocation
{
	return [self NSPointToMIPoint:NSMakePoint( [self armeTimeToPixel:fCurrentPlayBarPosition], NSMidY( [self visibleRect] ) )];
}

- (void)scrollToNewObject
{
	NSRect visibleRect = [self visibleRect];
	[self scrollRectToVisible:NSMakeRect( [self armeTimeToPixel:fCurrentPlayBarPosition], NSMidY( visibleRect ), NSWidth(visibleRect) - 10, NSHeight(visibleRect) / 2)];
}

- (void)setCurrentPlayBarPosition:(ArmeTime)position
{
	NSRect 		tlcFrame = [self frame];
	int		oldPos = (int)[self getCurrentPlayBarPosition];
	int		newPos = (int)[self armeTimeToPixel:position];
	MIRuler *ruler = [fMainViewController ruler];
	
	if ( ( oldPos == newPos ) || ( fCurrentPlayBarPosition == position ) )
		return;

        [ruler playbarNeedsDisplay];
        [self redrawBehindPlaybar];
        fCurrentPlayBarPosition = position;
        [ruler playbarNeedsDisplay];
		
        [self focusCacheAndDrawPlaybar:[self visibleRect]];
		[ruler displayIfNeeded];
		[[self window] flushWindowIfNeeded];
		[[MITimePaletteController sharedTimePaletteController] getValuesFromMainView];
}


- (MIObjectRep*)hitTestForMIObject:(NSPoint)aPoint
{
	// recursively check for object's children until the farthest decendant is found.
	//NSEnumerator		*objEnum = nil;
	MIObject			*anObject = nil;
	MIObjectRep			*theObjectRep = nil;
	MIObjectRep			*transition = nil;
	
	//objEnum = [[fRepresentedObject getChildren] reverseObjectEnumerator];
	SInt32 objEnumIndex = [[fRepresentedObject getChildren] count]-1;
	while ( (objEnumIndex >= 0) && !theObjectRep )
	{
		anObject = [[fRepresentedObject getChildren] objectAtIndex:objEnumIndex];
		objEnumIndex--;
		if ( [anObject getType] == TArmeWSObj::kVideoXFadeEffect )
		{
			if ( !transition )
				transition = [anObject hitTest:aPoint inTLC:self];; // transitions are second class citizens, they get selected only if no other thing can be selected.
			continue;
		}
			
		// let each object determine whether it occured if it's them or one of their children
		theObjectRep = [anObject hitTest:aPoint inTLC:self];
	}
	
	if ( !theObjectRep && transition )
		theObjectRep = transition;

	return theObjectRep;
}


////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////  Dragging
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

/*
As the image is dragged into the destination's boundaries, the destination is sent a draggingEntered: message.
¥  While the image remains within the destination, a series of draggingUpdated: messages are sent.
¥  If the image is dragged out of the destination, draggingExited: is sent and the sequence of NSDraggingDestination messages stops. If it re-enters, the sequence begins again (with a new draggingEntered: message).
¥  When the image is released, it either slides back to its source (and breaks the sequence) or a prepareForDragOperation: message is sent to the destination, depending on the value returned by the most recent invocation of draggingEntered: or draggingUpdated:.
¥  If the prepareForDragOperation: message returned YES, a performDragOperation: message is sent.
¥  Finally, if performDragOperation: returned YES, concludeDragOperation: is sent.
*/

// The clipsheetwindowView is already registered as a dragging recipient on initialization of the clipSheetController

- (BOOL)canFileBeImported:(NSString*)name
{
	BOOL isDirectory;
	NSFileManager *fileManager = [NSFileManager defaultManager];
	
	if ( ![fileManager fileExistsAtPath:name isDirectory:&isDirectory] ) return NO;

	if ( isDirectory ) {
		// is it a montage document ?
		if ( [[[name pathExtension] lowercaseString] isEqualToString:@"montage"] ) return YES;
		if ( [[[name pathExtension] lowercaseString] isEqualToString:@"HAV"] ) return YES;
		
		// check directory to find out if at least one file can be imported
		NSString *file;
		NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:name];
		while (file = [enumerator nextObject]) {
			if ( [self canFileBeImported:[name stringByAppendingFormat:@"/%@", file]] ) return YES;
		}
		return NO;
	}

	// is file's extension supported ?
	if ( [[[MIApplicationController sharedApplicationController] fileExtensions] containsObject:[[name pathExtension] lowercaseString]] ) return YES;

	// is file's type supported ?
	OSType hfsType = [[fileManager fileAttributesAtPath:name traverseLink:NO] fileHFSTypeCode];
	if ( [[[MIApplicationController sharedApplicationController] fileTypes] containsObject:[NSString stringWithFormat:@"'%@'",[NSString stringWithCString:(char*)&hfsType length:4]]] ) return YES;

	return NO;
}

- (NSArray*)discardUnsupportedFiles:(NSArray*)files {
	BOOL isDirectory;
	NSFileManager *fileManager = [NSFileManager defaultManager];
	NSMutableArray *array = [NSMutableArray array];
	NSEnumerator *enumerator = [files objectEnumerator];
	NSString *path;

	while (( path = [enumerator nextObject] )) {
		if ( [fileManager fileExistsAtPath:path isDirectory:&isDirectory] ) {

			if ( isDirectory ) {
				// is it a montage document ?
				if (( [[[path pathExtension] lowercaseString] isEqualToString:@"montage"] ) || ( [[[path pathExtension] lowercaseString] isEqualToString:@"HAV"] )) {
					[array addObject:path];
				} else {
					// recurcively check directory
					NSArray *dirContent = [fileManager directoryContentsAtPath:path];
					NSMutableArray* content = [NSMutableArray arrayWithCapacity:[dirContent count]];
					NSEnumerator *contentEnumerator = [dirContent objectEnumerator];
					NSString *name;

					while (( name = [contentEnumerator nextObject] )) {
						[content addObject:[path stringByAppendingFormat:@"/%@", name]];
					}
					
					[array addObjectsFromArray:[self discardUnsupportedFiles:content]];
				}
			}

			// is file's extension supported ?
			else if ( [[[MIApplicationController sharedApplicationController] fileExtensions] containsObject:[[path pathExtension] lowercaseString]] ) {
				[array addObject:path];
			} else {
				// is file's type supported ?
				OSType hfsType = [[fileManager fileAttributesAtPath:path traverseLink:NO] fileHFSTypeCode];
				if ( [[[MIApplicationController sharedApplicationController] fileTypes] containsObject:[NSString stringWithFormat:@"'%@'",[NSString stringWithCString:(char*)&hfsType length:4]]] ) {
					[array addObject:path];
				}
			}
		}
	}
	return array;
}

- (void)importSelectedFiles:(NSArray*)files contextDictionary:(NSMutableDictionary*)dict
{
	MICreateWSObjsFromFilesCommand	*createClipsCommand = [[[MICreateWSObjsFromFilesCommand alloc] initWithFiles:files controller:fMainViewController] autorelease];
	MIPoint position;

	[[dict objectForKey:@"position"] getValue:&position];
	[createClipsCommand setFirstPosition:position];
	[createClipsCommand setParent:[dict objectForKey:@"parent"]];

	[[fMainViewController document] doCmd:createClipsCommand];

	if ( [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowVObjLines ||
		 [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowHObjLines )
		[[MIApplicationController sharedApplicationController] redrawAllMainWindows];

	[[MIApplicationController sharedApplicationController] modelChangedForDocument:[[self mainViewController] document]];
	fDropEnabled = YES;
}


- (void)importWithObjectsFromDictionary:(NSMutableDictionary*)dict
{
	id files = [[dict objectForKey:@"files"] retain];
	[dict removeObjectForKey:@"files"];
	[fMainViewController importFilesUsingImportPanelIfNeeded:[files autorelease] importSelector:@selector(importSelectedFiles:contextDictionary:) importTarget:self contextDictionary:dict];
}

- (unsigned int)draggingEntered:(id <NSDraggingInfo>)sender
{
    NSPasteboard	*pboard;
    NSArray			*fileNames;
    NSString		*name;
    unsigned int	returnVal;
    unsigned int	i, n;
	NSPoint			mouseLoc;
	unsigned int	modifiers;	
    
    returnVal = NSDragOperationNone;

	if ( fDropEnabled == NO ) return returnVal;
	
    pboard = [sender draggingPasteboard];
    
    if ([[pboard types] containsObject:NSFilenamesPboardType])
    {
        fileNames = [pboard propertyListForType:NSFilenamesPboardType];
        n = [fileNames count];
        for ( i = 0; i < n && returnVal == NSDragOperationNone; i++ )
        {
            name = [fileNames objectAtIndex:i];
            if ([self canFileBeImported:name])
                returnVal = NSDragOperationCopy;
        }
    }
	else if ( [[pboard types] containsObject:MILibraryElementsPboardType])
	{
		returnVal = NSDragOperationCopy;
	}
	
    fLastDraggingAnswer = returnVal;
	
	mouseLoc = [self convertPoint:[sender draggingLocation] fromView:nil];
	modifiers = 0;
    
	fMouseTracker = [[MIDragThingsFromOutsideTracker alloc] initWithView:self atPos:mouseLoc withModifiers:modifiers];
	[fMouseTracker start:mouseLoc withModifiers:modifiers];
    return returnVal;
}

- (unsigned int)draggingUpdated:(id <NSDraggingInfo>)sender
{
	NSPoint			mouseLoc;
	unsigned int	modifiers;	

	mouseLoc = [self convertPoint:[sender draggingLocation] fromView:nil];
	modifiers = 0;

	[fMouseTracker mouseMoved:mouseLoc withModifiers:modifiers];

	return fLastDraggingAnswer;
}

- (void)draggingExited:(id <NSDraggingInfo>)sender
{
	NSPoint			mouseLoc;
	unsigned int	modifiers;	

	mouseLoc = [self convertPoint:[sender draggingLocation] fromView:nil];
	modifiers = 0;

	[fMouseTracker stop:mouseLoc withModifiers:modifiers];
	[fMouseTracker release];
	fMouseTracker = nil;
    fLastDraggingAnswer = NSDragOperationNone;
}

- (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender
{
	return fDropEnabled;
}

- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
	return fDropEnabled;
}


- (void)concludeDragOperation:(id <NSDraggingInfo>)sender
{
	NSPasteboard					*pboard;
    NSArray							*fileNames;
	MIObject						*parent;
	NSPoint							mouseLoc;
	unsigned int					modifiers = 0;	
	
	// get new parent from the mouseTracker and release it.
	parent = [[fMouseTracker destination] representedObject];
	mouseLoc = [self convertPoint:[sender draggingLocation] fromView:nil];

    pboard = [sender draggingPasteboard];
    
//    NSMutableArray* bopTaskArray = nil;
	
	// check if the information contains filenames
	if ([[pboard types] containsObject:NSFilenamesPboardType])
    {
        fileNames = [pboard propertyListForType:NSFilenamesPboardType];

		// calculate new position
		NSPoint pixelPosition = [self convertPoint:[sender draggingLocation] fromView:nil];
		pixelPosition.y -=
#ifdef SMALL_TITLEBAR
			GET_VALUE(kDefaultClipRepresentationHeight);
#else
		    kDefaultClipRepresentationHeight;
#endif
			//+ GET_VALUE(kRepTitleHeight) ) ;

		MIPoint position = [fMainViewController NSPointToMIPoint:pixelPosition];

		if ( [fMouseTracker destination] )
			position = [[[fMouseTracker destination] representedObject] convertPointFromTLCCoords:position];

		NSArray *files = [self discardUnsupportedFiles:fileNames];

		if ( ![fMainViewController unwantedFiles:files] ) {
			// This will allow the Finder to stop waiting
			NSMutableDictionary *dict = [NSMutableDictionary dictionary];
			if ( parent ) [dict setObject:parent forKey:@"parent"];
			else [dict setObject:[self representedObject] forKey:@"parent"];
			[dict setObject:[NSValue valueWithBytes:&position objCType:@encode(MIPoint)] forKey:@"position"];
			[dict setObject:files forKey:@"files"];

			fDropEnabled = NO;
			
			// call importWithObjectsFromDictionary: in .2 secs to do the real work
			[self performSelector:@selector(importWithObjectsFromDictionary:) withObject:dict afterDelay:.2 inModes:[NSArray arrayWithObject:NSDefaultRunLoopMode]];
		}
    }
	else if ( [[pboard types] containsObject:MILibraryElementsPboardType])
	{
#if USE_LIBRARY
		NSData	*d;
		MICreateClipsFromLibraryElementsCommand *cmd;
		MIObjectRep	*rep;
		
		d = [pboard dataForType:MILibraryElementsPboardType];
		libElems = [NSUnarchiver unarchiveObjectWithData:d];

		// calculate new position
		NSPoint pixelPosition = [self convertPoint:[sender draggingLocation] fromView:nil];
		MIPoint position = [fMainViewController NSPointToMIPoint:pixelPosition];

		cmd = [[[MICreateClipsFromLibraryElementsCommand alloc] initWithElements:libElems] autorelease];
		[cmd setMainViewController:fMainViewController];
		[cmd setGlobalFirstPosition:position];
		if ( (rep = [fMouseTracker destination]) )
			[cmd setParent:[rep representedObject]];
		else
			[cmd setParent:fRepresentedObject];
			
		[[fMainViewController document] doCmd:cmd];

		if ( [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowVObjLines ||
			[[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowHObjLines )
			[[MIApplicationController sharedApplicationController] redrawAllMainWindows];
	
#else
		ZzAssert(0);
#endif //USE_LIBRARY
	}
	[fMouseTracker stop:mouseLoc withModifiers:modifiers];
	[fMouseTracker release];
	fMouseTracker = nil;
}


- (void)createChildrenRepresentationsRecursivelyInSelf
{
	MIObject* tlc = [self representedObject];
	MIObject* aChild;
	NSEnumerator* childEnum = [[tlc getChildren] objectEnumerator];
	while ( aChild = [childEnum nextObject] )
	{
		[aChild createRepresentationsRecursively:self];
	}
}

#ifdef USE_NEW_DRAW_GRID
- (void)drawGrid:(NSRect)aRect
{
	aRect = NSInsetRect(aRect,-1,-1);

	[NSBezierPath setDefaultLineWidth:0.0];
	//[[NSColor colorWithCalibratedRed:0.686 green:0.737 blue:0.808 alpha:1.0] set];
//	[[NSColor colorWithCalibratedRed:0.626 green:0.657 blue:0.708 alpha:1.0] set];
	[[NSColor colorWithCalibratedRed:0.424 green:.424 blue:.424 alpha:1.0] set];

	if([[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowVLines)
	{
		MITime		*bigGridDelta = [[fMainViewController ruler] minTimeUnit];
		MITime		*littleGridDelta = [[fMainViewController ruler] minSubTimeUnit];
		ZzAssert([bigGridDelta getDoubleTime] != 0);
		if ( [[MIPreferences sharedPrefs] getHorizontalGridSpacing] != 0 )
		{
			// if it's not 0 (automatic), it's a fraction of a bar
			MITime *t;
			t = [MITime timeWithDocument:[fRepresentedObject montageDoc]];
/*
			[t setBars:2 beats:1 nb16ths:1 ppq:0];
			t->fTheTime /= [[MIPreferences sharedPrefs] getHorizontalGridSpacing];
*/
			[t setDoubleTime:0];
			switch ( [[MIPreferences sharedPrefs] getHorizontalGridSpacing] )
			{
				case 1:
					[t setSeconds:1];
					break;
				case 2:
					[t setSeconds:10];
					break;
				case 3:
					[t setSeconds:30];
					break;
				case 4:
					[t setMinutes:1];
					break;
				case 5:
					[t setMinutes:2];
					break;
				default:
					[t setSeconds:1];
					break;
			}
			
			// check that the time is large enough to display
			float p = [fMainViewController doubleTimeToPixel:[t getDoubleTime]];
			while ( p < 10 )
			{
				p *= 2;
				t->fTheTime *= 2;
			}
			bigGridDelta = t;
			littleGridDelta = nil;
		}
	
		
		ArmeTime	firstTime = [fMainViewController pixelToArmeTime:NSMinX(aRect)];
		ArmeTime	lastTime = [fMainViewController pixelToArmeTime:NSMaxX(aRect)];
		MITime		*time = [MITime timeWithDocument:[fRepresentedObject montageDoc]];
		
		// draw thick grid first
		// 1. round to next division
		
		// first next division (tick mark)
		// is located at (((int)(currentPosition/minUnit length))+1)* minUnitLength

		[time setDoubleTime:( (((int)((double)GET_VALUE(firstTime)/[bigGridDelta getDoubleTime]))+1)*[bigGridDelta getDoubleTime])];
	
		while( [time getDoubleTime] < GET_VALUE(lastTime))
		{
			float pixelPos = [fMainViewController doubleTimeToPixel:[time getDoubleTime]];
/* Rounding test
			[NSBezierPath strokeLineFromPoint:NSMakePoint(pixelPos-0.5, NSMinY(aRect)) toPoint:NSMakePoint(pixelPos-0.5, NSMaxY(aRect))];
*/
			[NSBezierPath strokeLineFromPoint:NSMakePoint(pixelPos, NSMinY(aRect)) toPoint:NSMakePoint(pixelPos, NSMaxY(aRect))];
			[time addTime:bigGridDelta];
		}
		
		if( littleGridDelta )
		{
			// draw thin grid first
			[time setDoubleTime:( ((GET_VALUE(firstTime)/[littleGridDelta getDoubleTime])+1)*[littleGridDelta getDoubleTime])];
		
			while( [time getDoubleTime] < GET_VALUE(lastTime))
			{
				float pixelPos = [fMainViewController doubleTimeToPixel:[time getDoubleTime]];
/* Rounding test
				[NSBezierPath strokeLineFromPoint:NSMakePoint(pixelPos-0.5, NSMinY(aRect)) toPoint:NSMakePoint(pixelPos-0.5, NSMinY(aRect))];
*/
				[NSBezierPath strokeLineFromPoint:NSMakePoint(pixelPos, NSMinY(aRect)) toPoint:NSMakePoint(pixelPos, NSMinY(aRect))];
				[time addTime:littleGridDelta];
			}
		}
	}
	
	if([[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowHLines)
	{
		MIVPos vPosSpacing = [[MIPreferences sharedPrefs] gridVSpacing];
		
		MIVPos firstVPos = [fMainViewController pixelToMIVPos:NSMinY(aRect)];
		MIVPos lastVPos = [fMainViewController pixelToMIVPos:NSMaxY(aRect)];
		MIVPos vpos;
		
		// 1. round to next division

		GET_VALUE(vpos) = ((GET_VALUE(firstVPos)/GET_VALUE(vPosSpacing)) + 1)*GET_VALUE(vPosSpacing);
	
		while(GET_VALUE(vpos) < GET_VALUE(lastVPos))
		{
			float pixelPos = [fMainViewController MIVPosToPixel:vpos];
			[NSBezierPath strokeLineFromPoint:NSMakePoint(NSMinX(aRect),pixelPos) toPoint:NSMakePoint(NSMaxX(aRect),pixelPos)];
			GET_VALUE(vpos) += GET_VALUE(vPosSpacing);
		}
	}
	
	// draw object lines...

	if ( [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowHObjLines ||
		 [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowVObjLines )
	{
		NSEnumerator* snapObjEnum = [[[fRepresentedObject montageDoc] snapperDB] objectEnumerator];
		MIObjectBoundsInfo* snapInfo;
		BOOL showV = [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowVObjLines;
		BOOL showH = [[MIPreferences sharedPrefs] gridShowMask] & kPrefsGridShowHObjLines;
		[[NSColor colorWithCalibratedRed:0.627 green:0.627 blue:0.627 alpha:1.0] set];
		ArmeTime	minTime = [self pixelToArmeTime:NSMinX(aRect)];
		ArmeTime	maxTime = [self pixelToArmeTime:NSMaxX(aRect)];
		MIVPos		minVPos = [self pixelToMIVPos:NSMinY(aRect)];
		MIVPos		maxVPos = [self pixelToMIVPos:NSMaxY(aRect)];
		
		while ( snapInfo = [snapObjEnum nextObject] )
		{
			if ( showV )
			{
				if ( GET_VALUE(snapInfo->fStart) >= GET_VALUE(minTime) &&
					 GET_VALUE(snapInfo->fStart) <= GET_VALUE(maxTime) )
				{
					float pixelPos = [fMainViewController armeTimeToPixel:snapInfo->fStart];
					[NSBezierPath strokeLineFromPoint:NSMakePoint(pixelPos, NSMinY(aRect)) toPoint:NSMakePoint(pixelPos, NSMaxY(aRect))];
				}
				if ( GET_VALUE(snapInfo->fEndx) >= GET_VALUE(minTime) &&
					 GET_VALUE(snapInfo->fEndx) <= GET_VALUE(maxTime) )
				{
					float pixelPos = [fMainViewController armeTimeToPixel:snapInfo->fEndx];
					[NSBezierPath strokeLineFromPoint:NSMakePoint(pixelPos, NSMinY(aRect)) toPoint:NSMakePoint(pixelPos, NSMaxY(aRect))];
				}				
			}
		
			if ( showH )
			{
				if ( GET_VALUE(snapInfo->fBottom) >= GET_VALUE(minVPos) &&
					 GET_VALUE(snapInfo->fBottom) <= GET_VALUE(maxVPos) )
				{
					float pixelPos = [fMainViewController MIVPosToPixel:snapInfo->fBottom];
					[NSBezierPath strokeLineFromPoint:NSMakePoint(NSMinX(aRect),pixelPos) toPoint:NSMakePoint(NSMaxX(aRect),pixelPos)];
				}
				if ( GET_VALUE(snapInfo->fTopx) >= GET_VALUE(minVPos) &&
					 GET_VALUE(snapInfo->fTopx) <= GET_VALUE(maxVPos) )
				{
					float pixelPos = [fMainViewController MIVPosToPixel:snapInfo->fTopx];
					[NSBezierPath strokeLineFromPoint:NSMakePoint(NSMinX(aRect),pixelPos) toPoint:NSMakePoint(NSMaxX(aRect),pixelPos)];
				}
			}
		}
	}
	
}
#endif //#ifdef USE_NEW_DRAW_GRID

- (MIMouseTracker*)mouseTracker
{
	return fMouseTracker;
}

- (void)recreateFrame
{
    NSRect 	newFrame;
    NSRect	visibleRect;
    BOOL	bNeedsRecreating = NO;
    newFrame = [self MIRectToNSRect:[fRepresentedObject modelFrame]];
    visibleRect = [[[self enclosingScrollView] contentView] frame];
    // make sure that the frame is at least as large as the visible rectangle...
    newFrame.size.width = max(NSWidth(visibleRect), NSWidth(newFrame));
    newFrame.size.height = max(NSHeight(visibleRect), NSHeight(newFrame));

    [self setFrame:newFrame];

    if ( bNeedsRecreating )
		[self recreateFrame];
}

- (void)setLeftLocatorPosition:(ArmeTime)position
{
	NSRect		updateRect;
	NSRect 		tlcFrame = [self frame];
	float		oldPos = [self getLeftLocatorPosition];
	float		newPos = [self armeTimeToPixel:position];

	if ( oldPos == newPos )
		return;
		
	updateRect.origin.y = NSMinY(tlcFrame);
	updateRect.size.height = NSHeight(tlcFrame);

	updateRect.origin.x = min(oldPos, newPos) - 1;
	updateRect.size.width = fabs(oldPos - newPos) + 2;

	[self setNeedsDisplayInRect:updateRect];
	
	[[fMainViewController ruler] setNeedsDisplay:YES];

	fLeftLocatorPosition = position;
	
	[[[MIApplicationController sharedApplicationController] timePaletteController] getValuesFromMainView];
}

- (void)setRightLocatorPosition:(ArmeTime)position
{
	NSRect		updateRect;
	NSRect 		tlcFrame = [self frame];
	float		oldPos = [self getRightLocatorPosition];
	float		newPos = [self armeTimeToPixel:position];

	if ( oldPos == newPos )
		return;
		
	updateRect.origin.y = NSMinY(tlcFrame);
	updateRect.size.height = NSHeight(tlcFrame);

	updateRect.origin.x = min(oldPos, newPos) - 1;
	updateRect.size.width = fabs(oldPos - newPos) + 2;

	[self setNeedsDisplayInRect:updateRect];
	
	[[fMainViewController ruler] setNeedsDisplay:YES];

	fRightLocatorPosition = position;
	[[[MIApplicationController sharedApplicationController] timePaletteController] getValuesFromMainView];
}

- (void)refreshTrackingRect
{

}

- (void)setImagesAndColor
{
	// this is needed for setMuted is sometimes called on TLC (during render for example)
}

- (void)refreshCachedTitleImage:(BOOL)createIfAbsent
{
	// this is needed for setMuted is sometimes called on TLC (during render for example)
}

- (void)refreshCachedBodyImage:(BOOL)createIfAbsent
{
	// this is needed for setMuted is sometimes called on TLC (during render for example)
}

- (void)refreshCachedAutomationImage:(BOOL)createIfAbsent
{
	// this is needed for setMuted is sometimes called on TLC (during render for example)
}

- (void)refreshCachedTitleStringImage
{
	// this is needed for setMuted is sometimes called on TLC (during render for example)
}

- (NSPoint)convertPointFromTLCCoords:(NSPoint)p
{
	return p;
}

- (NSPoint)convertPointToTLCCoords:(NSPoint)p
{
	return p;
}

- (void)setNeedsDisplay
{
	[self setNeedsDisplay:YES];
}

- (void)setNeedsDisplayInRect:(NSRect)rect
{
	if ( gDeferRedrawsUntilCommandEnd )
	{
		if ( !NSEqualRects(gDeferedRedrawRect, NSZeroRect) )
		{
			gDeferedRedrawRect = NSUnionRect(gDeferedRedrawRect, rect);
		}
		else
			gDeferedRedrawRect = rect;
	}
	else
		[super setNeedsDisplayInRect:rect];
}

- (void)flushDeferedRedraws
{
	if ( !NSEqualRects(gDeferedRedrawRect, NSZeroRect) )
	{
		[self setNeedsDisplayInRect:gDeferedRedrawRect];
		gDeferedRedrawRect = NSZeroRect;
	}
}

- (TArmeDoc*)getDoc
{
	return [[self representedObject] WSObject]->GetDoc();
}

- (void)setSelected:(BOOL)flag
{
	return;
}


/*
- (void)setNeedsDisplay:(BOOL)flag
{
	[super setNeedsDisplay:flag];
}

- (void)setNeedsDisplayInRect:(NSRect)rect
{
	NSLog([NSString stringWithFormat:@"Rect: {%5.5f, %5.5f} {%5.5f, %5.5f}", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height]);
//	if ( NSEqualPoints( rect.origin, NSZeroPoint) )
//		NSLog(@"origin is 0");
		
	[super setNeedsDisplayInRect:rect];
}
*/

/*
	Problem:
	rendering is slow...
	On several occasions, the TLC must draw 2 small parts of itself separated by a long distance.
	Instead of doing 2 rendering passes, it does 1 with the union of the 2 rectangles, thus causing a big potential decrease of performance.
	
	optimisation attempt:
	when setNeedsDisplayInRect is called, instead of forwarding all the messages to the view,
	keep a list of the rectangles in a queue.
	forward the messages to the view one at a time.
	
	warning: this will work only as long as the UI is not multi-threaded.
*/


// Actions handled by the document
- (IBAction)saveDocument:(id)sender {
	[[[self mainViewController] document] saveDocument:sender];
}
- (IBAction)saveDocumentTo:(id)sender {
	[[[self mainViewController] document] saveDocumentTo:sender];
}
- (IBAction)revertDocumentToSaved:(id)sender {
	[[[self mainViewController] document] revertDocumentToSaved:sender];
}

- (BOOL)validateMenuItem:(NSMenuItem *)anItem {
	return [[[self mainViewController] document] validateMenuItem:anItem];
}

@end