/*
 Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )

 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
*/
 
#import <IO/Misc/PlayList.hpp>
#import <IO/Manager/IOManager.hpp>
#import <IO/Manager/IOLockGuard.hpp>
//#import <IO/Output/Video/GLWindow.h>
#import <skins/SkinBase.hpp>

#import <AppKit/AppKit.h>

#import <unistd.h>
#import <time.h>
#import <sys/time.h>

#import <lib/Preferences.h>
#import <util/Loader.h>

@class MyListView;

@interface MyScroller : NSView {

    float mProp, mValue;

    MyListView * mOwner;
}

- (void)drawRect:(NSRect)aRect;
- (BOOL) isFlipped;
- (void)drawThumb;
- (void) setFloatValue:(float) aFloat knobProportion:(float) knobProportion;
- (void) mouseDown:(NSEvent *) event;
- (void) mouseUp:(NSEvent *) event;
- (NSRect) thumbRect;
- (void) dragThumb;

@end // interface MyScroller

@implementation MyScroller

- (BOOL) inThumb:(NSPoint) pos
{
    NSPoint loc  = [ self convertPoint:pos fromView:nil ];
    NSRect  rect = [ self thumbRect ];
    
    //printf( "inThumb xy(%d,%d)\n", (int) loc.x, (int) loc.y );

    return ( loc.x >= rect.origin.x && loc.x < rect.origin.x + rect.size.width &&
             loc.y >= rect.origin.y && loc.y < rect.origin.y + rect.size.height );
}

- (BOOL) aboveThumb:(NSPoint) pos
{
    NSPoint loc  = [ self convertPoint:pos fromView:nil ];
    NSRect  rect = [ self thumbRect ];
    
    //printf( "aboveThumb xy(%d,%d)\n", (int) loc.x, (int) loc.y );

    return ( loc.y > rect.origin.y + rect.size.height && loc.y < [ self frame ].size.height );
}

- (BOOL) belowThumb:(NSPoint) pos
{
    NSPoint loc  = [ self convertPoint:pos fromView:nil ];
    NSRect  rect = [ self thumbRect ];
    
    //printf( "belowThumb xy(%d,%d)\n", (int) loc.x, (int) loc.y );

    return ( loc.y >= 0 && loc.y < rect.origin.y );
}

- (void) dragThumb
{
    int deltaY=0;
    
    int keepOn = YES;
    int lastY;
    
    NSPoint current = [ NSEvent mouseLocation];

    lastY = (int) current.y;

    do {

        NSEvent * theEvent = [ [ self window ] nextEventMatchingMask: NSAnyEventMask ];

        switch( [theEvent type] ) {

            case NSLeftMouseDragged:

                    current = [ NSEvent mouseLocation];

                    deltaY = lastY - (int) current.y;

                    if( deltaY < 0 ) {
                        [ mOwner lineUp ];
                    }
                    else {
                        [ mOwner lineDown ];
                    }
                        
                    lastY = (int) current.y;

                    break;

            case NSLeftMouseUp:
            
                    keepOn = NO;
                    break;
            default:
                    /* Ignore any other kind of event. */
                    break;
        }
    } while (keepOn);    
}

- (void) mouseDown:(NSEvent *) event
{
    if( [ self inThumb:[ event locationInWindow] ] ) {
        [ self dragThumb ];
    }
    else if(  [ self aboveThumb:[ event locationInWindow]  ]) {
        [ mOwner pageDown ];
    }
    else if(  [ self belowThumb:[ event locationInWindow]  ]) {
        [ mOwner pageUp ];
    }
}

- (void) mouseUp:(NSEvent *) event
{
}

- (void) setFloatValue:(float) aFloat knobProportion:(float) knobProportion
{
    mValue = aFloat;
    mProp  = knobProportion;
}

- (NSRect) thumbRect
{
    float x      = 2;
    float y      = [ self  frame ].size.height * mValue + 1;
    float width  = [ self  frame ].size.width - 4;
    float height = [ self  frame ].size.height * mProp - 2;

    if( x + height >= [ self  frame ].size.height ) {
        height = [ self  frame ].size.height - ( x + 2 );
    }
    
    return NSMakeRect( x, y, width, height );
}

- (void)drawThumb
{
    NSRect rect = [ self thumbRect ];

    [[NSColor blackColor] set];
    
    //NSRectFill( rect );

    //NSDrawButton( rect, rect );
    NSDrawGrayBezel( rect, rect );
}

- (void)drawRect:(NSRect)aRect
{
    NSRect rect = NSMakeRect( 0, 0, [ self  frame ].size.width, [ self  frame ].size.height );
    
    [[NSColor lightGrayColor ] set];
    
    //NSRectFill( b );
    NSDrawLightBezel( rect, rect );

    [ self drawThumb ];
}

- (BOOL) isFlipped
{
    return YES;
}


@end // implementation MyScroller

// --------------

@interface MyContentView : NSView {

    NSImage * image;
    
    float orgImageWidth;
    float orgImageHeight;

}

- (void)drawRect:(NSRect)aRect;

@end // interface MyContentView

@implementation MyContentView

- (void)drawRect:(NSRect)aRect
{
    //[ self  lockFocus ];
    
    //[[NSColor clearColor] set];
    
    //NSRectFill( [ self  frame ] );
    
    if( image != 0 ) {
    
        //puts("MyContentView.drawRect have image");

        float dstW = [[ self window ] frame ].size.width;
        float dstH = [[ self window ] frame ].size.height;

        //if( dstW > orgImageWidth || dstH > orgImageHeight ) {
            [ image setSize: NSMakeSize( dstW, dstH ) ];
        //}
        
        [ image drawAtPoint:NSZeroPoint fromRect:NSMakeRect( 0, 0, dstW,dstH ) operation:NSCompositeSourceOver fraction:1.0 ];
                
    }
    //[ self unlockFocus ];
}

@end // implementation MyContentView

// --------------

@interface MyListView : NSView {

    NSMutableArray * mList;

    int          mFirstVisible;
    unsigned     mSelected;
    MyScroller * mScroller;
}

- (void) pageUp;
- (void) pageDown;

- (void) lineUp;
- (void) lineDown;

- (void) updateScroller;

- (BOOL) isFlipped;

- (id)initWithFrame:(NSRect) frameRect;

- (void) addEntry:(NSString*) entry;

- (void)drawRect:(NSRect)aRect;

- (void)drawEntry:(NSString*) entry lineNo:(unsigned) lineNo selected:(BOOL) selected;

- (void)setFrame:(NSRect)frameRect;

- (void) mouseDown:(NSEvent *)theEvent;

- (int) lineHeight;

- (void) stopPlaying;

- (void) play:(NSString*) fileName;

- (unsigned) itemsPerPage;

@end // interface MyListView

@implementation MyListView

- (unsigned) itemsPerPage
{
    return (int) ([ self frame ].size.height / [ self lineHeight ] );
}

- (void) lineUp
{
    //puts( "lineUp" );

    if( mFirstVisible > 0 ) {
    
        mFirstVisible--;

        [ self updateScroller ];

        [ self display ];
    }
}

- (void) lineDown
{
    //puts( "lineDown" );

    if( mFirstVisible + 1 < (int) [ mList count ] ) {
    
        mFirstVisible++;

        [ self updateScroller ];

        [ self display ];
    }
}

- (void) pageUp
{
    //puts( "pageUp" );

    if( mFirstVisible - (int) [ self itemsPerPage ] >= 0 ) {

        mFirstVisible -= (int) [ self itemsPerPage ];

        [ self updateScroller ];

        [ self display ];
    }
    else {
    
        mFirstVisible = 0;
        
        [ self updateScroller ];
        
        [ self display ];
    }
}

- (void) pageDown
{
    //puts( "pageDown" );
    
    if( mFirstVisible + (int) [ self itemsPerPage ] < (int) [ mList count ] ) {

        mFirstVisible += (int) [ self itemsPerPage ];
        
        [ self updateScroller ];

        [ self display ];
    }
}

- (void) updateScroller
{
    //puts("updateScroller");

    float val, prop;

    float nItemsPerPage = (float) [ self frame ].size.height / (float) [ self lineHeight ];
    
    if( [ mList count ] >  nItemsPerPage ) {
        
        val  = (float) mFirstVisible / (float) [ mList count ];
        prop = nItemsPerPage / (float) [ mList count ]; 
         
    }
    else {
        val  = 0.0;
        prop = 1.0;
    }
    
    [ mScroller setFloatValue:val knobProportion:prop ];
    [ mScroller display ];
}

- (BOOL) isFlipped
{
    return YES;
}

- (void) stopPlaying
{
    IOManager::instance().sendCommand( "WindowController", "stopPlaying" );            
}

- (void) play:(NSString*) fileName
{
    IOManager::instance().sendCommand( "WindowController", "playMovie", [ fileName cString ] );            
}

- (int) lineAt:(NSPoint) pos
{
    NSPoint mouseLoc = [ self convertPoint:pos fromView:nil ];
    
    int ret = (int) (mouseLoc.y  / [ self lineHeight ]);

    //printf( "lineAt xy(%d,%d) = %d\n", (int) mouseLoc.x, (int) mouseLoc.y, ret );

    return ret;
}

- (void) mouseDown:(NSEvent *)theEvent
{    
    [ super mouseDown:theEvent ];

    int count = [ theEvent clickCount ];
    int line  = [ self lineAt:[theEvent locationInWindow] ];
    
    //printf("clickCount(%d) line(%d)\n", count, line );
    
    if( count > 0  && line + mFirstVisible < [ mList count ] ) {
        
        mSelected = mFirstVisible+line;
        
        [ self display ];
        
        if( count > 1 ) {
        
            NSString * fileName = [ mList objectAtIndex: mFirstVisible+line ];
        
            if( fileName ) {
                [ self stopPlaying ];
                [ self play:fileName ];
            }
        }
    }
}

- (void)setFrame:(NSRect)frameRect
{
    mSelected = 0;

    [ super setFrame:frameRect ];

    NSRect r = NSMakeRect( frameRect.size.width - 20, 0, 20, frameRect.size.height );
    //NSRect r = NSMakeRect( 0, 0, 20, frameRect.size.height );

    [ mScroller setFrame:r ];

    [ self updateScroller ];

}

- (id)initWithFrame:(NSRect) frameRect
{
     [ super initWithFrame:frameRect ];

    mList = [[ NSMutableArray arrayWithCapacity: 30 ] retain ];

    mFirstVisible = 0;
    mSelected     = 0;    

    mScroller = [ MyScroller alloc ];
    
    mScroller->mOwner = self;
    
    NSRect r = NSMakeRect( frameRect.size.width - 20, 0, 20, frameRect.size.height );
    //NSRect r = NSMakeRect( 0, 0, 20, frameRect.size.height );

    [ mScroller initWithFrame:r ];

    [ self addSubview: mScroller positioned:NSWindowAbove relativeTo:nil ];
    
    return self;
}

- (int) lineHeight
{
    NSFont * font = [NSFont menuFontOfSize:14 ];

    int ySpacing = 4;
      
    int fontHeight = (int) ([ font ascender ] + [ font descender ]);

    return fontHeight + ySpacing;
}

- (void)drawEntry:(NSString*) entry lineNo:(unsigned) lineNo selected:(BOOL) selected
{
    NSDictionary * d;
    
    if( ! selected ) {
        d = [NSDictionary dictionaryWithObject: [NSColor blueColor] forKey:NSForegroundColorAttributeName ];
    }
    else {
        d = [NSDictionary dictionaryWithObject: [NSColor cyanColor] forKey:NSForegroundColorAttributeName ];
    }
    
    NSRect  bounds = [self bounds];
    
    NSPoint textPos =  NSMakePoint( bounds.origin.x + 20, bounds.origin.y +  [ self lineHeight ]* lineNo );
    
    //printf("drawEntry xy(%d,%d) text(%s)\n", (int)textPos.x, (int)textPos.y, [ entry cString ] );
    [ entry drawAtPoint: textPos withAttributes: d ];
}

- (void)drawRect:(NSRect)aRect
{
    //puts("MyListView.drawRect");

    [[NSColor blackColor] set];
    
    NSRectFill( NSMakeRect( 0, 0, [self frame].size.width, [self frame].size.height ));

    unsigned lineNo = 0;
    
    unsigned max = mFirstVisible + [ self itemsPerPage ];
    
    if( max > [ mList count ] ) {
        max = [ mList count ];
    }
    
    for( unsigned i = mFirstVisible; i < max; i++ ) {
        
        NSString * str = (NSString*) [ mList objectAtIndex:i ];
        
        [ self drawEntry: str lineNo:lineNo selected:(mSelected == i )];
        
        lineNo++;
    }
}

- (void) addEntry:(NSString*) entry
{
    [ entry retain ];
    
    [ mList addObject: entry ];

    [ self updateScroller ];

    [ self display ];
    
}

@end // interface MyListView

// --------------

@interface MyWindow : NSWindow {

    PlayList       * mOwner;
    SkinBase       * mCurrentSkin;
    int             mTopBorder, mRightBorder, mLeftBorder, mBottomBorder;
    MyContentView * mainView;
    MyListView    * mListView;
}

- (void) initWith:(PlayList*) owner windowPos:(NSRect) windowPos;
- (void) setSkin:( const char *) skinName;
- (void) keyDown:(NSEvent *)theEvent;
- (void) windowDidResize:(NSNotification *) aNotification;
- (void) windowDidMove:(NSNotification*) aNotification;
- (void) moveWindow;
- (void) resizeWindow;
- (void) sizeChanged:(float) windowWidth height:(float) windowHeight;
- (void) posChanged:(float) x y:(float) y;
- (void) handleDrop:(NSString*) fileName;
- (void) updateContent;
-(int) getRightBorder;
-(int) getLeftBorder;

- (void) setRightBorder:( int ) val;
- (void) setLeftBorder:( int ) val;

-(int) getTopBorder;
-(int) getBottomBorder;

- (void) setTopBorder:( int ) val;
- (void) setBottomBorder:( int ) val;

- (void) move:(float) x y:(float) y;
- (void) resize:(float) w h:(float) h;
- (bool) create:(NSRect) windowPos;

- (void) playCurrentFile;
- (void) playFirstFile;
- (void) playLastFile;
- (void) playNextFile;
- (void) playPreviousFile;
- (void) addFile:(const char *) name;

- (void) toggleShow;

@end // interface MyGLWindow

@implementation MyWindow

- (void) toggleShow
{
    if( ! [ self isVisible ]) {

        bool isFullScreen = atoi( IOManager::instance().getValue( "GLWindow", "isFullScreen"  ).c_str() );

        printf("PlayList.toggleShow: isFullScreen(%d)\n", isFullScreen );
        
        if( isFullScreen ) {
        
            unsigned windowNumber = atoi( IOManager::instance().getValue( "GLWindow", "windowNumber"  ).c_str() );

            printf("PlayList.toggleShow: windowNumber(%d)\n", windowNumber );
            
            [ self setLevel: kCGOverlayWindowLevel ];
            
            [ self orderWindow:NSWindowAbove relativeTo:windowNumber ];
        }
        else {
            [ self setLevel: kCGNormalWindowLevelKey ];
            
            [ self makeKeyAndOrderFront:nil ];
        }
    }
    else {
        [ self orderOut:nil ];
    }
}

- (void) addFile:(const char *) name
{
    [ mListView addEntry: [NSString stringWithCString:name ]];
}

-(bool) create:(NSRect) windowPos
{
    int flags = NSBorderlessWindowMask;
    
    NSRect frame = [ NSWindow contentRectForFrameRect: windowPos styleMask: flags ];
    NSRect innerRect;
    
    [ self initWithContentRect: frame styleMask: flags backing: NSBackingStoreBuffered defer: NO ];

    [ self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]];

    mainView = [ MyContentView alloc ];
    
    mainView->image = nil;
    
    //[ mainView ) setOwner:self ];
    
    innerRect  = NSMakeRect( 0, 0, windowPos.size.width, windowPos.size.height );

    [ mainView initWithFrame: innerRect ];
        
    [ self setContentView: mainView ];
        
    //[ self setAcceptsMouseMovedEvents: true ];
                
    [ self setHasShadow:false ];
            
    mListView = [ MyListView alloc ];

    [ mListView initWithFrame: innerRect ];
    
    [ mainView addSubview: mListView ];
    
        
    [ self  setHasShadow:false ];

    [ mainView display ];
    
    return true;
}

- (void) move:(float) x y:(float) y
{
    NSRect r = [ self frame ];
    
    r.origin.x = x;
    r.origin.y = y;
    
    [ self setFrame:r display:true ];
    
    [ self posChanged: x y:y ];
}

- (void) resize:(float) w h:(float) h
{
    NSRect r = [ self frame ];
    
    r.size.width  = w;
    r.size.height = h;
    
    [ self setFrame:r display:true ];

    [ self sizeChanged: w height:h ];    
}

-(int) getRightBorder
{
    return mRightBorder;
}

-(int) getLeftBorder
{
    return mLeftBorder;
}

- (void) setRightBorder:( int ) pixels
{
    mRightBorder = pixels;
}

- (void) setLeftBorder:( int ) pixels
{
    mLeftBorder = pixels;
}

-(int) getTopBorder
{
    return mTopBorder;
}

-(int) getBottomBorder
{
    return mBottomBorder;
}

- (void) setTopBorder:( int ) pixels
{
    mTopBorder = pixels;
}

- (void) setBottomBorder:( int ) pixels
{
    mBottomBorder = pixels;
}

- (void) sizeChanged:(float) windowWidth height:(float) windowHeight
{

    float innerViewWidth  = windowWidth  - ( mLeftBorder + mRightBorder ) ;
    float innerViewHeight = windowHeight - ( mTopBorder + mBottomBorder );

    float x = mLeftBorder;
    float y = mBottomBorder;


    NSRect mainViewBounds   = NSMakeRect( 0, 0, windowWidth, windowHeight );
    NSRect listViewBounds   = NSMakeRect( x, y, innerViewWidth, innerViewHeight );

    //puts("MyWindow.sizeChanged");
    
    [ mainView    setFrame: mainViewBounds   ];
    [ mListView   setFrame: listViewBounds   ];
    
    [ super display ];

    [ self flushWindow ];    

    WritePrivateProfileInt( mOwner->getName().c_str(), "SizeX", (int) windowWidth  );
    WritePrivateProfileInt( mOwner->getName().c_str(), "SizeY", (int) windowHeight );
}

- (id)initWithContentRect:(NSRect)contentRect styleMask:(unsigned int)styleMask backing:(NSBackingStoreType)backingType defer:(BOOL)flag
{
    id _id = [ super initWithContentRect:contentRect styleMask:styleMask backing:backingType defer:flag ];

    //puts("initWithContentRect");

    [ self registerForDraggedTypes: [NSArray arrayWithObject: NSFilenamesPboardType]];

    return _id;
}

- (void) initWith:(PlayList*) owner windowPos:(NSRect) windowPos
{ 
    mCurrentSkin     =  0;        
    mOwner           = owner;
    mTopBorder = mLeftBorder = mRightBorder = mBottomBorder = 0;
}

- (void) setSkin:(const char *) skinName
{
    IOObject * obj = IOManager::instance().findObject( skinName );
        
    if( obj != 0 ) {
            
        mCurrentSkin = (SkinBase*) obj;
        
        //printf( "PlayListWindow found skin %s\n", skinName );
            
        if( mCurrentSkin != 0 ) {

            mainView->image = mCurrentSkin->getWindowBackgroundImage();
            mainView->orgImageWidth  = [ mainView->image size].width;
            mainView->orgImageHeight = [ mainView->image size].height;

            [ mainView->image setScalesWhenResized:YES ];

            [ self display ];
        }
    }
}

- (void) handleDrop:(NSString*) fileName
{
    //puts("MyWindow::handleDrop");
    
    [ mListView addEntry:fileName ];
    
    //IOManager::instance().sendCommand( "WindowController",  "handleDrop", mOwner->getName(), [ fileName cString ] );
                
}

static const char * getString( NSString * characters )
{
    NSAutoreleasePool * pool =[ [ NSAutoreleasePool alloc ] init ];

    const char * result = "";
    
    if( [ characters canBeConvertedToEncoding: [ NSString defaultCStringEncoding ]] ) {
        result = [ characters cString ];
    }
    else {
        result = [ characters lossyCString ];
    }

    [ pool release ];
    
    return result;
}

- (void) mouseDown:(NSEvent *)theEvent
{
    if( 1 ) {
    
        float width  = [ self frame ].size.width;
        //float height = [ self frame ].size.height;
        float x      = [ theEvent locationInWindow ].x;
        float y      = [ theEvent locationInWindow ].y;

        //printf("MyGLWindow::mouseDown xywh(%d,%d,%d,%d)\n", (int)x, (int) y, (int)width, (int)height );
    
        if( x >= ( width - 40 ) && x < width && y >= 0 && y < 40 ) {
            [ self resizeWindow ];
        }
            else {
            [ self moveWindow ];
        }
        [ super mouseDown:theEvent ];
    }
}

- (void) keyDown:(NSEvent *) event
{

    //printf("MyGLWindow::keyDown key(%s) code(%x) modifiers(%x)\n", key.c_str(), keyCode, modifiers );

    [ super keyDown:event ];

    string key = getString( [ event characters ]);
    char  keyCode  [12];
    char  modifiers[12];
    
    sprintf( keyCode,   "%d", [ event keyCode       ] );
    sprintf( modifiers, "%d", [ event modifierFlags ] );
    
    //IOManager::instance().sendCommand( "WindowController",  "keyDown", mOwner->getName(), key, keyCode, modifiers );
}
    
- (void) updateContent
{
    if( mCurrentSkin ) {
        mCurrentSkin->update();
    }
}

- (void) posChanged:(float) x y:(float) y
{
    WritePrivateProfileInt( mOwner->getName().c_str(), "OriginX", (int) x );
    WritePrivateProfileInt( mOwner->getName().c_str(), "OriginY", (int) y );
}

- (void)windowDidResize:(NSNotification*) aNotification
{
    [ super windowDidResize:aNotification ];
        
    NSRect bounds = [ self frame ];
        
    [ self sizeChanged:bounds.size.width height:bounds.size.height ];
        
}

- (void) windowDidMove:(NSNotification*) aNotification
{
    if( 1 ) {

        NSRect bounds = [ self frame ];

        WritePrivateProfileInt( mOwner->getName().c_str(), "OriginX", (int) bounds.origin.x );
        WritePrivateProfileInt( mOwner->getName().c_str(), "OriginY", (int) bounds.origin.y );
    }

}

- (void) moveWindow
{
    int deltaX=0, deltaY=0;
    
    int keepOn = YES;

    int lastX;
    int lastY;
    int rem;
    
    NSPoint current = [ NSEvent mouseLocation];

    lastX = (int) current.x;
    lastY = (int) current.y;

    //puts("moveWindow");

    do {

        NSEvent * theEvent = [ self nextEventMatchingMask: NSAnyEventMask ];

        switch( [theEvent type] ) {

            case NSLeftMouseDragged:

                    current = [ NSEvent mouseLocation];

                    deltaX = lastX - (int) current.x;
                    deltaY = lastY - (int) current.y;

                    { 
                        NSPoint point = NSMakePoint( [ self frame].origin.x, [ self frame].origin.y );
        
                        point.x -= deltaX;
                        point.y -= deltaY;
      
                        rem = (int)point.x % 4;
                    
                        switch( rem ) {
                        case 1:
                        case 2:
                            point.x -=  rem;
                            break;
                        case 3:
                            point.x += 1;
                            break;
                        }
                                        
                        [ [ self contentView ] lockFocus ];

                        [ self move:point.x  y:point.y ];
                    
                        [ [ self contentView ] unlockFocus ];

                        lastX = (int) current.x;
                        lastY = (int) current.y;

                    }
                    break;
            case NSLeftMouseUp:
            
                    current = [ NSEvent mouseLocation];

                    lastX = (int) current.x;
                    lastY = (int) current.y;

                    //if (isInside) [self doSomethingSignificant];
                    //[self highlight:NO];
                    keepOn = NO;
                    break;
            default:
                    /* Ignore any other kind of event. */
                    break;
        }
    } while (keepOn);    
}

static void nsRect2Carbon( NSRect rect, Rect & carbonRect )
{   
    NSSize screenSize = [[ NSScreen mainScreen ] frame ].size;
                     
    int l = int( rect.origin.x );
    int t = int( screenSize.height - ( rect.origin.y + rect.size.height ));
    int r = int( rect.origin.x+rect.size.width );
    int b = int(t + rect.size.height);
                        
    SetRect( &carbonRect, l, t, r, b );                                        
}

- (void) resizeWindow
{
    int deltaX=0, deltaY=0;
    
    int keepOn = YES;

    int lastX;
    int lastY;
    
    NSPoint current = [ NSEvent mouseLocation];

    lastX = (int) current.x;
    lastY = (int) current.y;

    NSRect rect = [ self frame];

    //puts("resizeWindow");
    
    CGrafPtr savedPort;
    
    GetPort( &savedPort );

    SetPort( 0 );
    
    PenState pnState;
    
    GetPenState(&pnState);
    
    ShowPen();
    
    PenSize( 2, 2 );
    PenMode( patXor );
    
    Pattern blackPat;

    GetQDGlobalsBlack( &blackPat );
    
    PenPat( &blackPat );

    Rect carbonRect;

    nsRect2Carbon( rect, carbonRect );

    MacFrameRect( &carbonRect );
    
    do { 

        NSEvent * theEvent = [ self nextEventMatchingMask: NSAnyEventMask ];
        
        switch( [theEvent type] ) {

            case NSLeftMouseDragged:

                    current = [ NSEvent mouseLocation];

                    deltaX = -( lastX - (int) current.x );
                    deltaY = lastY - (int) current.y;
                    
                    rect.size.width  += deltaX;
                    rect.size.height += deltaY;
                    rect.origin.y    -= deltaY;

                    MacFrameRect( &carbonRect );
                    
                    nsRect2Carbon( rect, carbonRect );

                    MacFrameRect( &carbonRect );
                    
                    lastX = (int) current.x;
                    lastY = (int) current.y;

                    break;
            case NSLeftMouseUp:
            
                    current = [ NSEvent mouseLocation];

                    lastX = (int) current.x;
                    lastY = (int) current.y;

                    keepOn = NO;
                    break;
            default:
                    /* Ignore any other kind of event. */
                    break;
        }

    } while( keepOn );

    nsRect2Carbon( rect, carbonRect );

    MacFrameRect( &carbonRect );

    ShowCursor();
    HidePen();
    SetPenState(&pnState);
    
    SetPort( savedPort );
    
    //[ self resize:rect.size.width h:rect.size.height ];

    [ self setFrame:rect display:true ];

    [ self sizeChanged:rect.size.width height:rect.size.height ];    
    
}

- ( void ) select:(unsigned) n
{
    if( n < [ mListView->mList count ] ) {
        
        mListView->mSelected = n;
        
        [ self display ];
    }
}

- (void) playSelected
{
    if( mListView->mSelected >= 0 && mListView->mSelected < [ mListView->mList count ] ) {

        NSString * fileName = [ mListView->mList objectAtIndex: mListView->mSelected ];
        
        if( fileName ) {
            [ mListView stopPlaying ];
            [ mListView play:fileName ];
        }
    }
}

- (void) playCurrentFile
{
    [ self playSelected ];     
}

- (void) playLastFile
{
    if( [ mListView->mList count ] > 0 ) {

        [ self select: [ mListView->mList count ] - 1  ];
    
        [ self playSelected ];     
    }
}

- (void) playFirstFile
{
    [ self select: 0 ];
    
    [ self playSelected ];     
}

- (void) playNextFile
{
    if( mListView->mSelected + 1 < [ mListView->mList count ] ) {

        [ self select: mListView->mSelected+1 ];

        [ self playSelected ];
    }
    else if( [ mListView->mList count ] > 0 ) {

        [ self select: 0 ];

        [ self playSelected ];
    }    
}

- (void) playPreviousFile
{
    [ self select: mListView->mSelected-1 ];

    [ self playSelected ];
}

- (unsigned int) draggingEntered:(id <NSDraggingInfo>)sender
{
    //puts("draggingEntered");
    return NSDragOperationCopy;
}

- (BOOL) prepareForDragOperation:(id <NSDraggingInfo>)sender
{
    //puts("prepareForDragOperation");
    return YES;
}


- (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
{
    //puts("performDragOperation");
    // Mike Ferris sez that you should do the drag operation in conclude!
    // That way you don't have to wait for time-outs when debugging the
    // drop code.
    return YES;
}

- (void) concludeDragOperation:(id <NSDraggingInfo>)sender
{
    unsigned i;
    NSPasteboard * pboard           = [ sender draggingPasteboard ];
    NSArray	 * draggedFileNames = [ pboard propertyListForType: NSFilenamesPboardType ];

    //puts("concludeDragOperation");
    
    for( i = 0; i < [ draggedFileNames count ]; i++ ) {
    
        NSString * s = [ draggedFileNames objectAtIndex:i ];
        
        //printf( "item(%d) is %s\n", i, [ s cString ] );
        
        //[ self handleDrop:s ];
        
        [ s retain ];
        
        [ mListView->mList addObject:s ];
    }
    
    [ mListView updateScroller ];

    [ mListView display ];
    
    //draggedFileNames = [ draggedFileNames fileNamesWithBasePath: @"" ];
    //draggedFileNames = [draggedFileNames arrayByRemovingObjectsInArray: files];
    //[ files addObjectsFromArray: draggedFileNames ];
    //[ self updateView: self ];
}

@end // implementationMyGLWindow

PlayList::PlayList( const string & aName )
 : IOObject( aName, "PlayList" )
 , mCurrentFile  ( "Player.CurrentFile"  )
{
    init();
}

PlayList::~PlayList()
{    
    finit();
}


void PlayList::createWindow()
{
    int wx = GetPrivateProfileInt( getName().c_str(), "OriginX", 50  );
    int wy = GetPrivateProfileInt( getName().c_str(), "OriginY", 500 );

    int ww = GetPrivateProfileInt( getName().c_str(), "SizeX", 300   );
    int wh = GetPrivateProfileInt( getName().c_str(), "SizeY", 400  );

    NSRect windowPos = NSMakeRect( wx, wy, ww, wh );

    MyWindow * window = mWindow;
    
    if( window == 0 ) {
    
        //IOLockGuard lockGuard( *this );
    
        window = [ MyWindow alloc ];
        
        [ window initWith:this windowPos:windowPos ];
        
        [ window create:windowPos ];

        [ window setTopBorder:     12 ];
        [ window setLeftBorder:    12 ];
        [ window setRightBorder:   12 ];
        [ window setBottomBorder:  12 ];
        
        [ window sizeChanged: [[ window contentView ] frame ].size.width height:[[ window contentView ] frame ].size.height ];
        
    }
    
    mWindow = window;
}

void PlayList::init()
{
    mWindow = 0;

    mCurrentFile.addView( this );                

}

void PlayList::finit()
{
    IOManager::instance().unregisterObject( this );
}

void PlayList::updateFrom( IOModel * aModel ) 
{

    //printf("%s.updateFrom: %s\n", getName().c_str(), aModel->getName().c_str() );
        
    if( aModel->getName() == "Player.CurrentFile" ) {
        
        ;//mFileInfo->setString( aModel->getString() );
    }
}

bool PlayList::command( const string & command, 
                        const string & param1,  const string & param2, const string & param3, const string & param4 )
{
    if( mWindow == 0 ) {
        createWindow();
    }

    printf("%s.command: %s %s %s\n", getName().c_str(), command.c_str(), param1.c_str(), param2.c_str() );

    if( command == "setSkin" ) {

       [ mWindow setSkin: param1.c_str() ];
    }
    else if( command == "lbdrag" ) {

        [ mWindow resizeWindow ];
    }
    else if( command == "toggleShow" ) {

        [ mWindow toggleShow ];
    }
    else if( command == "add" ) {
        [ mWindow addFile:param1.c_str() ];
    }
    else if( command == "playCurrentFile" ) {
        [ mWindow playCurrentFile ];
    }
    else if( command == "playFirstFile" ) {
        [ mWindow playFirstFile ];
    }
    else if( command == "playLastFile" ) {
        [ mWindow playLastFile ];
    }
    else if( command == "playNextFile" ) {
        [ mWindow playNextFile ];
    }
    else if( command == "playPreviousFile" ) {
        [ mWindow playPreviousFile ];
    }

    return true;
}

extern "C" int initPlayListPlugin( int argc, const char ** argv )
{
    PlayList * pl = new PlayList( "PlayListWindow" );
    
    IOManager::instance().registerObject( pl );
    
    pl->command("", "");
    
    return true;
}
    
