/* 
   Project: MPDCon

   Copyright (C) 2004

   Author: Daniel Luederwald

   Created: 2004-05-12 17:59:14 +0200 by flip
   
   Playlist Controller

   This application 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 application 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
   Library General Public License for more details.
 
   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include <AppKit/AppKit.h>
#include "PlaylistController.h"

/* ---------------------
   - Private Interface -
   ---------------------*/
@interface PlaylistController(Private)
- (void) _doRemove;
- (void) _moveRows: (NSArray *)rows atRow: (int)row;
@end

@implementation PlaylistController

/* --------------------------
   - Initialization Methods -
   --------------------------*/

+ (id) sharedPlaylistController
{
  static PlaylistController *_sharedPlaylistController = nil;

  if (! _sharedPlaylistController) 
    {
    _sharedPlaylistController = [[PlaylistController allocWithZone: 
						       [self zone]] init];
    }
  
  return _sharedPlaylistController;
}

- (id) init
{
  self = [self initWithWindowNibName: @"PlaylistViewer"];
  
  if (self) 
    {
      [self setWindowFrameAutosaveName: @"PlaylistViewer"];
    }

  mpdController = [MPDController sharedMPDController];
  
  return self;
}

- (void) dealloc
{
  RELEASE(playlist);
  RELEASE(playlistTimes);

  [super dealloc];
}

/* ---------------
   - Gui Methods -
   ---------------*/

- (void) awakeFromNib
{
  NSNotificationCenter *defCenter;

  [playlistTable setAutosaveName: @"PlaylistTable"];
  [playlistTable setAutosaveTableColumns: YES];
  [playlistTable setTarget: self];
  [playlistTable setDoubleAction: @selector(doubleClicked:)];

  [playlistTable registerForDraggedTypes: 
		   [NSArray arrayWithObjects: PlaylistDragType, nil]];

  [lengthView setFont: [NSFont systemFontOfSize: 12]];

  defCenter = [NSNotificationCenter defaultCenter];

  [defCenter addObserver: self
		selector: @selector(songChanged:)
	            name: SongChangedNotification
	          object: nil];

  [defCenter addObserver: self
	        selector: @selector(playlistChanged:)
	            name: PlaylistChangedNotification
	          object: nil];

  [defCenter addObserver: self
	        selector: @selector(didNotConnect:)
	            name: DidNotConnectNotification
	          object: nil];

  [defCenter addObserver: self
	        selector: @selector(selectTrack:)
	            name: FindPlaylistNotification
	          object: nil];

  [defCenter addObserver: self
	        selector: @selector(getAllTracks:)
	            name: GetTracksNotification
	          object: nil];

  currentSong = [mpdController getCurrentSongNr];

  [self playlistChanged: nil];  
}

- (void) removeSongs: (id)sender
{
  switch ([removeSelector indexOfSelectedItem]) 
    {
    case 0:
      [self _doRemove];
      break;
    case 1:
      [mpdController clearPlaylist];
      break;
    }
}

- (void) managePlaylists: (id)sender
{
  [[PlaylistsManagerController sharedPLManagerController] showWindow: self];
}

- (void) doubleClicked: (id)sender
{
  int row;

  if ([playlistTable clickedRow] == -1)
    {
      return;
    }

  row = [playlistTable selectedRow];
  [mpdController playSong: row];
}

- (void) showCurrentSong: (id)sender
{
  int state;

  state = [mpdController getState];
  if ((state == state_PAUSE) || (state == state_PLAY)) 
    {
      [playlistTable scrollRowToVisible: currentSong-1];
      [playlistTable selectRow: currentSong-1 byExtendingSelection: NO];
    }
}

- (void) shuffleList: (id)sender
{
  [mpdController shuffleList];
}

- (void) browseCollection: (id)sender
{
  [[CollectionController sharedCollectionController] showWindow: self];
}



/* --------------------------------
   - TableView dataSource Methods -
   --------------------------------*/

- (int) numberOfRowsInTableView: (NSTableView *)tableView
{
    return [playlist count];
}

-          (id) tableView: (NSTableView *)tableView 
objectValueForTableColumn: (NSTableColumn *)tableColumn row:(int)row
{
  NSString *identifier;

  identifier = [tableColumn identifier];

   if ([identifier isEqual: @"track"])
     {
       return [NSString stringWithFormat: @"%d", row+1];
     }
   else if ([identifier isEqual: @"time"]) 
     {
       return [playlistTimes objectAtIndex: row];
     } 
   else if ([identifier isEqual: @"play"]) 
     {
       if ((row == currentSong-1))
	 {
	   return @">";
	 }
       else
	 {
       return @"";
	 }
     } 
   else 
     {
       return [[playlist objectAtIndex: row] valueForKey: identifier];
     }
}


/* ------------------------------
   - TableView dragging Methods -
   ------------------------------*/

- (NSDragOperation) tableView: (NSTableView *)tv
		 validateDrop: (id <NSDraggingInfo>)info
		  proposedRow: (int)row
	proposedDropOperation: (NSTableViewDropOperation)dropOperation
{
  NSArray *typeArray;
  NSString *availableType;
  NSPasteboard *pboard;
  NSDragOperation dragOperation;
  
  pboard = [info draggingPasteboard];
  typeArray = [NSArray arrayWithObjects: PlaylistDragType, nil];
  availableType = [pboard availableTypeFromArray: typeArray];
  dragOperation = NSDragOperationNone;
  
  if (availableType)
    {
      [tv setDropRow: row dropOperation: NSTableViewDropAbove];
      if ([availableType isEqualToString: PlaylistDragType])
        dragOperation = NSDragOperationMove;
    }

  return dragOperation;
}

- (BOOL) tableView: (NSTableView *)tv
	acceptDrop: (id <NSDraggingInfo>)info
	       row: (int)row
     dropOperation: (NSTableViewDropOperation)dropOperation
{
  NSPasteboard *pboard;
  NSArray *objectsList, *typeArray;
  NSString *availableType;
  BOOL accept;
  
  if ([info draggingSource] != playlistTable)
    {
      return NO;
    }

  pboard = [info draggingPasteboard];
  typeArray = [NSArray arrayWithObjects: PlaylistDragType, nil];
  
  availableType = [pboard availableTypeFromArray: typeArray];
  objectsList = [pboard propertyListForType: availableType];

  if ([objectsList count])
    {
      if ([availableType isEqualToString: PlaylistDragType]) 
	{
	  [self _moveRows: objectsList atRow: row];
	  [tv selectRow: row byExtendingSelection: NO];
	}
      accept = YES;
    }
  else
    {
      accept = NO;
    }

  return accept;
}


- (BOOL) tableView: (NSTableView *)tv
	 writeRows: (NSArray *)rows
      toPasteboard: (NSPasteboard*)pboard
{
  NSArray *typeArray, *filesList;
  BOOL accept;
  unsigned int count;
  
  count = [rows count];
  
  if (count > 0)
    {
      accept = YES;
      typeArray = [NSArray arrayWithObjects: PlaylistDragType, nil];
      [pboard declareTypes: typeArray owner: self];
      [pboard setPropertyList: rows forType: PlaylistDragType];
    }
  else
    {
      accept = NO;
    }
  
  return accept;
}

/* ------------------------
   - Notification Methods -
   ------------------------*/

- (void) songChanged: (NSNotification *)aNotif
{
  currentSong = [mpdController getCurrentSongNr];
  [playlistTable reloadData];
}

- (void) playlistChanged: (NSNotification *)aNotif
{
  int length;
  int j;

  AUTORELEASE(playlist);

  playlist = RETAIN([mpdController getPlaylist]);

  length=0;

  if ([playlist count] != 0) 
    {
      int i;
      int tSecs, tMins, tHours;
      
      for (i = 0; i < [playlist count]; i++) 
	{
	  length += [[playlist objectAtIndex: i] getTotalTime];
	}
    
    tSecs = (length % 60);
    tMins = (int) (length/60) % 60;
    tHours = (int) length/3600;
    
    [lengthView setStringValue: [NSString stringWithFormat: 
				 _(@"Playlist Length: %d:%02d:%02d"), 
				 tHours, tMins, tSecs]];
    } 
  else 
    {
      [lengthView setStringValue: _(@"Playlist Length: 0:00:00")];
    }

  AUTORELEASE(playlistTimes);

  playlistTimes = [[NSMutableArray alloc] init];

  for (j = 0; j < [playlist count]; j++) 
    {
      int time;
      int tSecs, tMins;
      
      time = [[playlist objectAtIndex: j] getTotalTime];
      
      tSecs = (time % 60);
      tMins = (int) time/60;
      
    [playlistTimes addObject: [NSString stringWithFormat: @"%d:%02d", 
					tMins, tSecs]];
    }
  
  [playlistTable reloadData];
}


- (void) didNotConnect: (NSNotification *)aNotif
{
  [[self window] performClose: self];
}

- (void) getAllTracks: (NSNotification *)aNotif
{
  if(![[aNotif object] isEqual: GetTracksFromPlaylist])
    {
      return;
    }

  [[NSNotificationCenter defaultCenter] postNotification: 
		 [NSNotification notificationWithName: TracksSendNotification 
				               object: playlist]];
}

- (void) selectTrack: (NSNotification *)aNotif
{
  int trackNr;

  trackNr = [[aNotif object] intValue];
  [playlistTable scrollRowToVisible: trackNr];
  [playlistTable selectRow: trackNr byExtendingSelection: NO];
}
@end

/* -------------------
   - Private Methods -
   -------------------*/

@implementation PlaylistController(Private)
- (void) _doRemove
{
  NSEnumerator *songEnum;
  NSNumber *songNumber;
  int i;

  songEnum = [playlistTable selectedRowEnumerator];

  i = 0;
  songNumber;

  while (songNumber = [songEnum nextObject]) 
    {
      [mpdController removeSong: [songNumber intValue]-i];
      i++;
    }
  
  [playlistTable deselectAll: self];
}


- (void) _moveRows: (NSArray *)rows atRow: (int)row
{
  int i;

  for (i = 0; i < [rows count]; i++) 
    {
      int oldRow;
      
      oldRow = [[rows objectAtIndex: i] intValue];

      if (oldRow != row+1)
	{
	  [mpdController moveSongNr: oldRow to: row+i];
	}
    }

  [playlistTable reloadData];
}

@end
