/* 
   Project: MPDCon

   Copyright (C) 2004

   Author: Daniel Luederwald

   Created: 2004-05-12 17:59:14 +0200 by flip
   
   Collection 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 "CollectionController.h"

/* ---------------------
   - Private Interface -
   ---------------------*/
@interface CollectionController(Private)
- (void) _getAllAlbumsForArtistAt: (int)row;
- (void) _getAllTracksForArtistAt: (int)artistRow albumAt: (int)albumRow;


int _artistSort(id artist1, id artist2, void *context);
int _albumSort(id album1, id album2, void *context);
int _trackSort(id track1, id track2, void *context);
int _titleSort(id title1, id title2, void *context);
@end

@implementation CollectionController

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

+ (id) sharedCollectionController
{
  static CollectionController *_sharedCollectionController = nil;

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

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

  allArtists = RETAIN([[MPDController sharedMPDController] getAllArtists]);

  return self;
}

- (void) dealloc
{
  RELEASE(allSongs);
  RELEASE(allArtists);
  RELEASE(allAlbums);

  [super dealloc];
}

/* --------------------
   - Playlist Methods -
   --------------------*/

- (void) addSelected: (id)sender
{
  NSEnumerator *songEnum = [trackView selectedRowEnumerator];
  NSNumber *songNumber;
  
  int i = 0;
  
  while (songNumber = [songEnum nextObject]) 
    {
      [[MPDController sharedMPDController] 
	addTrack: [[allSongs objectAtIndex: [songNumber intValue]] getPath]];
      i++;
    }
  
  if (i == 0) 
    {
      int j;
      
      for (j = 0; j < [allSongs count]; j++)
	[[MPDController sharedMPDController] 
	  addTrack: [[allSongs objectAtIndex: j] getPath]];
    }
}

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

- (void) awakeFromNib
{
  [trackView setAutosaveName: @"CollectionTrackTable"];
  [trackView setAutosaveTableColumns: YES];
  [trackView setTarget: self];
  [trackView setDoubleAction: @selector(doubleClicked:)];

  [artistView setTarget: self];
  [artistView setDoubleAction: @selector(doubleClicked:)];

  [albumView setTarget: self];
  [albumView setDoubleAction: @selector(doubleClicked:)];

  [artistView selectRow: 0 byExtendingSelection: NO];

  [[NSNotificationCenter defaultCenter] addObserver: self
					selector: @selector(didNotConnect:)
					name: DidNotConnectNotification
					object: nil];
 [[NSNotificationCenter defaultCenter] addObserver: self
					selector: @selector(selectTrack:)
					name: FindCollectionNotification
					object: nil];
 [[NSNotificationCenter defaultCenter] addObserver: self
				       selector: @selector(getAllTracks:)
				       name: GetTracksNotification
				       object: nil];
}

- (void) updateCollection: (id)sender
{
  [[MPDController sharedMPDController] updateCollection];

  RELEASE(allArtists);

  allArtists = RETAIN([[MPDController sharedMPDController] getAllArtists]);

  [artistView reloadData];
  [artistView scrollRowToVisible: 0];

  [self tableViewSelectionDidChange: [NSNotification 
				       notificationWithName: @"Blubb" 
				       object: artistView]];
}

- (void) doubleClicked: (id)sender
{
  if (sender == trackView) 
    {
      if ([trackView clickedRow] >= 0) 
	{
	  [self addSelected: self];
	}
      else 
	{
	  NSString *identifier;
	  
	  identifier = [(NSTableColumn *)[[trackView tableColumns] 
			  objectAtIndex: [trackView clickedColumn]] 
			 identifier];
	  
	  if ([identifier isEqual: @"artist"]) 
	    {
	      NSArray *tmpArray = RETAIN([AUTORELEASE(allSongs) 
				     sortedArrayUsingFunction: _artistSort 
				     context: NULL]);
	      allSongs = tmpArray;
	    } 
	  else if ([identifier isEqual: @"album"]) 
	    {
	      NSArray *tmpArray = RETAIN([AUTORELEASE(allSongs) 
				     sortedArrayUsingFunction: _albumSort 
				     context: NULL]);
	      allSongs = tmpArray;
	    } 
	  else if ([identifier isEqual: @"title"]) 
	    {
	      NSArray *tmpArray = RETAIN([AUTORELEASE(allSongs)
				     sortedArrayUsingFunction: _titleSort 
				     context: NULL]);
	      allSongs = tmpArray;
	    } 
	  else if ([identifier isEqual: @"trackNr"]) 
	    {
	      NSArray *tmpArray = RETAIN([AUTORELEASE(allSongs) 
				     sortedArrayUsingFunction: _trackSort 
				     context: NULL]);
	      allSongs = tmpArray;
	    } 
	  
	  [trackView reloadData];
	}
    } 
  else if ((sender == artistView) || (sender == albumView)) 
    {
      [self addSelected: self];
    }
}

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

- (int) numberOfRowsInTableView: (NSTableView *)tableView
{
  if (tableView == trackView)
    {
      return [allSongs count];
    }
  else if (tableView == artistView) {
    return [allArtists count]+1;
  }
  else 
    {
      return [allAlbums count]+1;
    }
}

- (id) tableView: (NSTableView *)tableView 
objectValueForTableColumn: (NSTableColumn *)tableColumn 
	     row:(int) row
{
  NSString *identifier = [tableColumn identifier];
  
  if (tableView == trackView) 
    {
      return [[allSongs objectAtIndex: row] valueForKey: identifier];
    }
  else if (tableView == artistView) 
    {
      if (row == 0) 
	{
	  return @"All";
	}
      else
	{
	  return [allArtists objectAtIndex: row-1];
	}
    } 
  else 
    {
      if (row == 0) 
	{
	  return @"All";
	}
      else
	{
	  return [allAlbums objectAtIndex: row-1];
	}
    }
}

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

- (void) tableViewSelectionDidChange: (NSNotification *)aNotif
{
  if ([aNotif object] == trackView) 
    {
      return;
    }
  
  if ([aNotif object] == artistView) 
    {
      [self _getAllAlbumsForArtistAt: [artistView selectedRow]];

      [albumView reloadData];
      [albumView selectRow: 0 byExtendingSelection: NO];
      [albumView scrollRowToVisible: 0];
      
      [self tableViewSelectionDidChange: [NSNotification 
					   notificationWithName: @"Blubb" 
					   object: albumView]];
    }
  else if ([aNotif object] == albumView) 
    {
      [self _getAllTracksForArtistAt: [artistView selectedRow] 
	    albumAt: [albumView selectedRow]];

      [trackView reloadData];
      [trackView deselectAll: self];
      [trackView scrollRowToVisible: 0];
      
      [[NSNotificationCenter defaultCenter] 
	postNotification: [NSNotification notificationWithName: 
					    ShownCollectionChangedNotification 
					  object: nil]];
    }
}

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


- (void) getAllTracks: (NSNotification *)aNotif
{
  if (! [[aNotif object] isEqual: GetTracksFromCollection])
    {
      return;
    }
  
    [[NSNotificationCenter defaultCenter]
      postNotification: [NSNotification notificationWithName: 
					  TracksSendNotification 
					object: allSongs]];
}

- (void) selectTrack: (NSNotification *)aNotif
{
  int trackNr = [[aNotif object] intValue];

  [trackView selectRow: trackNr byExtendingSelection: NO];
  [trackView scrollRowToVisible: trackNr];
}
@end

/* -------------------
   - Private Methods -
   -------------------*/
@implementation CollectionController(Private)

- (void) _getAllAlbumsForArtistAt: (int)row
{
  RELEASE(allAlbums);
  
  if (row == 0) 
    {
      allAlbums = RETAIN([[MPDController sharedMPDController] getAllAlbums]);
    } 
  else 
    {
      allAlbums = RETAIN([[MPDController sharedMPDController] 
		     getAlbumsForArtist: [allArtists 
					   objectAtIndex: (row - 1)]]);
    }
}

- (void) _getAllTracksForArtistAt: (int)artistRow albumAt: (int)albumRow
{
  RELEASE(allSongs);

  if (artistRow == 0) 
    {
      if (albumRow == 0)
	{
	  allSongs = RETAIN([[MPDController sharedMPDController] 
			getAllTracks]);
	}
      else
	{
	  allSongs = RETAIN([[MPDController sharedMPDController] 
			getAllTracksForAlbum: 
			  [allAlbums objectAtIndex: (albumRow -1)]]);
	}
  } 
  else 
    {
      if (albumRow == 0) 
	{
	  allSongs = RETAIN([[MPDController sharedMPDController] 
			getAllTracksForArtist: 
			  [allArtists objectAtIndex: (artistRow - 1)]]);
	} 
      else 
	{
	  allSongs = RETAIN([[MPDController sharedMPDController] 
			getAllTracksForArtist: [allArtists objectAtIndex: 
							     (artistRow - 1)] 
			album: [allAlbums objectAtIndex: 
					    (albumRow -1)]]);
	}
    }
}


int _artistSort(id artist1, id artist2, void *context)
{
  PlaylistItem *pl1, *pl2;

  pl1 = (PlaylistItem *)artist1;
  pl2 = (PlaylistItem *)artist2;

  return [[pl1 getArtist] caseInsensitiveCompare: [pl2 getArtist]];
}

int _albumSort(id album1, id album2, void *context)
{
  PlaylistItem *pl1, *pl2;

  pl1 = (PlaylistItem *)album1;
  pl2 = (PlaylistItem *)album2;

  return [[pl1 getAlbum] caseInsensitiveCompare: [pl2 getAlbum]];
}

int _titleSort(id track1, id track2, void *context)
{
  PlaylistItem *pl1, *pl2;

  pl1 = (PlaylistItem *)track1;
  pl2 = (PlaylistItem *)track2;

  return [[pl1 getTitle] caseInsensitiveCompare: [pl2 getTitle]];
}

int _trackSort(id track1, id track2, void *context)
{
  PlaylistItem *pl1, *pl2;

  pl1 = (PlaylistItem *)track1;
  pl2 = (PlaylistItem *)track2;

  return [[pl1 getTrackNr] caseInsensitiveCompare: [pl2 getTrackNr]];
}

@end

