/*******************************************************************************
*                         Goggles Music Manager                                *
********************************************************************************
*           Copyright (C) 2006-2010 by Sander Jansen. All Rights Reserved      *
*                               ---                                            *
* 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 3 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, see http://www.gnu.org/licenses.           *
********************************************************************************/
#ifndef GMTRACKDATABASE_H
#define GMTRACKDATABASE_H

#include "common.h"

class GMTrackList;


enum {
  PLAYLIST_M3U,
  PLAYLIST_M3U_EXTENDED,
  PLAYLIST_XSPF,
  PLAYLIST_PLS,
  PLAYLIST_CSV
  };

class GMTrackDatabase {
private:
  GMDatabase db;
public:

  /// Browse Queries
  /// ------------------------------------------------------------------------
  GMQuery list_genres;

  /// Insert Queries
  /// ------------------------------------------------------------------------
  GMQuery insert_root_component;
  GMQuery insert_path_component;
  GMQuery insert_track;           /// Insert Track
  GMQuery insert_genre;           /// Insert Genre
  GMQuery insert_artist;          /// Insert Artist;
  GMQuery insert_album;           /// Insert Album;
//  GMQuery insert_album_artist;    /// Insert Album-Artist Assoc;
  GMQuery insert_track_playlist;              /// Insert Track into Playlist
  GMQuery query_filename;         /// Query filename
  GMQuery query_root_component;
  GMQuery query_path_component;
  GMQuery query_path;
  GMQuery query_genre;            /// Query unique genre
  GMQuery query_album;            /// Query unique album from artist
  GMQuery query_album_name;       /// Query album name
  GMQuery query_artist;           /// Query unique artist
  GMQuery query_artist_with_album;/// Query artist by album
  GMQuery query_artist_name;      /// Query Artist Name for id
  GMQuery query_track;            /// Query track
  GMQuery query_track_genre;		  /// Query track genre
  GMQuery query_playlist_queue;               /// Get the max playlist queue
  GMQuery query_track_filename;   /// Query filename by track id
  GMQuery query_track_filename_by_album;
  GMQuery query_track_genre_id;		/// Query Track Genre ID
  GMQuery query_album_with_track; /// Query album by track
	GMQuery query_artist_name_album;/// Query artist by album
  GMQuery query_artist_year;      /// Query artist, year for track
  GMQuery query_album_artists;    /// Query artist and album for track


  GMQuery list_artists;
	GMQuery list_tracks_genre_only;	            /// List Tracks that have a certain genre
	GMQuery list_tracks_from_album;             /// List Tracks from Album
	GMQuery list_tracks_from_album_genre;       /// List Tracks from Album and Genre
  GMQuery list_albums_artist;


  /// Delete Queries
  /// ------------------------------------------------------------------------
  GMQuery delete_artist;                  /// Delete Artist
  GMQuery delete_genre;                   /// Delete Genre
  GMQuery delete_album;                   /// Delete Album
	GMQuery delete_track;						        /// Delete Track
  GMQuery delete_track_artist;            /// Delete Tracks from Artist
  GMQuery delete_track_album;             /// Delete Tracks from Album
  GMQuery delete_albums_artist;           /// Delete Album from Artist in Album List
  GMQuery delete_track_from_playlist;     /// Delete track from specific playlist
  GMQuery delete_track_from_playlists;    /// Delete track from all playlists
  GMQuery delete_album_from_playlists;    /// Delete tracks from album from all playlists
  GMQuery delete_artist_from_playlists;   /// Delete tracks from artist from all playlists


  GMQuery update_mrl;  		        /// Update Name of Artist
  GMQuery update_track;           /// Update track
  GMQuery update_album;           /// Update Album
  GMQuery update_track_title;     /// Update track title
  GMQuery update_track_year;      /// Update Track Year
  GMQuery update_played;          /// Update Track as played
  GMQuery update_track_genre;     /// Update track genre
	GMQuery update_track_genre_id;	/// Update track genre
	GMQuery update_track_no;				/// Update track & disc no
	GMQuery update_track_disc;			 // Update disc no
	GMQuery update_track_track;		  /// Update track no
  GMQuery update_track_artist;    /// Update track artist
  GMQuery update_track_importdate; /// Update track importdate;
	GMQuery query_track_no;				  /// Update track no
  GMQuery update_artist_album_id; /// Update artist in album_artist (with album id)
	GMQuery update_track_album_id;	/// Update track album
  GMQuery insert_album_existing;  /// Create new album entry based on existing
  GMQuery insert_album_existing_name;  /// Create new album entry based on existing
  GMQuery query_album_existing;  /// Create new album entry based on existing
  GMQuery query_artist_album;      /// Query Artist Name for id



protected:
  void setup_insert_queries();
  void clear_insert_queries();

  FXbool upgrade_to_2009();

  FXbool reorderPlaylists();

protected:
  FXbool queryGenre(FXint & result,const FXString & name,FXbool insert);
//  FXbool queryGenre(FXString & result,FXint trackid);
  FXbool queryArtist(FXint & result,const FXString & name,FXbool insert);
  FXbool queryArtist(FXint & result,FXint album);
  FXbool queryArtist(FXString & result,FXint album);
  FXbool queryAlbum(FXint & result,const FXString & name,FXint artist,FXint year,FXdouble gain,FXdouble peak,FXbool insert);
  FXbool queryAlbum(FXString & name,FXint album);
	FXbool queryAlbum(FXint & album,FXint & year, FXint track);
  FXbool updateAlbum(FXint &album,const GMTrack&,FXint artist);
	FXbool getTrackGenre(FXint & genre,FXint trackid);

  void addPath(const FXString & path,FXint & id);
  FXbool findPath(const FXString & path,FXint & id);

  FXbool setup_tables();
  FXbool setup_queries();
  void fix_genres();
public:
  /// Constructor
  GMTrackDatabase();

  GMDatabase * database() { return &db; }

  FXbool clearTracks(FXbool removeplaylists);

  /// Clear Database
	void clear();

  /// Initialize the database. Return FALSE if failed else TRUE
  FXbool init(const FXString & filename,FXbool checkversion=false);


  ///=======================================================================================
  ///   QUERY ITEMS
  ///=======================================================================================

  FXbool getStream(FXint id,GMStream & info);

	/// Return Track Info
	FXbool getTrack(FXint id,GMTrack & info);



	/// Return artist, album id
	FXbool getTrackAssociation(FXint id,FXint & artist,FXint & album);

  /// Return filename for track
  FXString getTrackFilename(FXint id);

  /// Return a list of filenames
  FXbool getTrackFilenames(FXIntList & ids,FXStringList & filenames,FXLongList & importdates ,const FXString & root=FXString::null);

  /// Return list of filenames
  void getTrackFilenames(const FXIntList & tracks,FXStringList & filenames);

  FXString getPathName(FXint id);

  FXbool getAlbumTrack(FXint id,FXString & path);

  /// Return the album path
  FXint getAlbumPath(FXint id);

	/// Return album id for track
	FXint getTrackAlbum(FXint id);

	/// Return Name for given album
	FXString getAlbumName(FXint id);

	/// Return Artist for given album
	FXString getAlbumArtist(FXint id);

	/// Return Artist Name for given id
	FXString getArtistName(FXint id);

	/// Return Genre Name for give id
	FXString getGenreName(FXint id);

  /// Return Play list name for given id
  FXString getPlaylistName(FXint id);

  /// Return number of tracks in database
  FXint getNumTracks();

  /// Return number of tracks in database
  FXint getNumStreams();

  /// Return number of albums in database
  FXint getNumAlbums();

  /// Return number of artists in database
  FXint getNumArtists();

  /// Return total time of all tracks
	FXint getTotalTime();

  /// Mark track as played
  FXbool playedTrack(FXint id,FXlong t);

  /// Update Playlist Queue
  FXbool updateTrackPlaylists(FXint playlist,FXIntList & tracks);

  FXbool trackInPlaylist(FXint track,FXint playlist);

  ///=======================================================================================
  ///   INSERTING ITEMS
  ///=======================================================================================

	/// Check if we have a track
	FXbool hasTrack(const FXString &,FXint & id);

  /// Check if we have file in directory
	FXbool hasTrack(const FXString & directory,const FXString & filename,FXint & id);

  /// Insert Track into database
  FXbool insertTrack(const GMTrack & info,FXint & id);

  /// Uodate Track in database
  FXbool updateTrack(FXint id,const GMTrack & info);

  /// Insert Playlist into database
  FXbool insertPlaylist(const FXString & name,FXint & id);

  /// Insert Track in Playlist
  FXbool insertTrackInPlaylist(FXint playlist,FXint & track);

  /// Insert Track in Playlist
  FXbool insertTrackInPlaylist(FXint playlist,FXIntList & tracks);

  /// Remove Queue numbers from Playlist
  FXbool removeTracksFromPlaylist(const FXIntList & queue,FXint playlist);

  FXbool insertStream(const FXString & url,const FXString & description,const FXString & genre);

  ///=======================================================================================
  ///   DELETING ITEMS
  ///=======================================================================================

  void beginDelete();

  /// Remove Track from database
  FXbool removeTrack(FXint id);

  /// Remove Track from database
  FXbool removeTracks(const FXIntList &ids);

  /// Remove Album from database
  FXbool removeAlbum(FXint id);

  /// Remove Artist from database
  FXbool removeArtist(FXint id);

  /// Remove Genre from database
  FXbool removeGenre(FXint id,FXbool update_tracks=true);

  /// Remove Playlist from database
  FXbool removePlaylist(FXint id);

  /// Remove Stream
  FXbool removeStream(FXint id);

  void endDelete(FXbool vacuum=true);

  /// Synchronize all tables and makes sure no empty entries are left behind.
  FXbool vacuum();

  ///=======================================================================================
  ///   EDITING ITEMS
  ///=======================================================================================

  void beginEdit();

  /// Set Track No
  FXbool setTrackDiscNumber(FXint id,FXuint no);

  /// Set Track Disc
  FXbool setTrackDisc(FXint id,FXushort disc);
  FXbool setTrackDisc(const FXIntList & ids,FXushort disc);

  /// Set Track Number
  FXbool setTrackNumber(FXint id,FXushort no);

  /// Set Track Title
  FXbool setTrackTitle(FXint id,const FXString & name);

  /// Set Track Genre
  FXbool setTrackGenre(FXint id,const FXString & name);
  FXbool setTrackGenre(const FXIntList & ids,const FXString & name);

  /// Set Track Album
  FXbool setTrackAlbum(FXint id,const FXString & name);
  FXbool setTrackAlbum(const FXIntList & ids,const FXString & name,FXbool sameartist);

	/// Set Track Artist
  FXbool setTrackAlbumArtist(FXint id,const FXString & name,const FXString & album_title);
  FXbool setTrackAlbumArtist(const FXIntList & ids,const FXString & name,const FXString & album_title);

	/// Set Track Artist
  FXbool setTrackAlbumArtist(FXint id,const FXString & name);

	/// Set Track Artist
  FXbool setTrackArtist(FXint id,const FXString & name);
  FXbool setTrackArtist(const FXIntList & ids,const FXString & name);

	/// Set Track Year
  FXbool setTrackYear(FXint id,FXuint year);
  FXbool setTrackYear(const FXIntList & ids,FXuint year);

	/// Change the filename of id
	void setTrackFilename(FXint id,const FXString & filename);

  /// Set Playlist Name
  FXbool setPlaylistName(FXint id,const FXString & name);

  /// Move oldq to newq
  FXbool moveTrack(FXint playlist,FXint oldq,FXint newq);

  /// Mark track as imported
  FXbool setTrackImported(FXint id,FXlong tm);

  void endEdit(FXbool vacuum=true);

  FXbool setStreamFilename(FXint id,const FXString & filename);

  FXbool setStreamDescription(FXint id,const FXString & description);

  FXbool setStreamGenre(FXint id,const FXString & genre);

  FXbool setStreamBitrate(FXint id,FXint rate);

  ///=======================================================================================
  ///   LISTING ITEMS
  ///=======================================================================================


  /// List Genres
  FXbool listGenres(FXComboBox * list,FXbool insert_default=TRUE);

  /// List Artists with optional genre
  FXbool listArtists(FXList * list,FXIcon * icon,FXint genre=-1,FXint playlist=-1);

  /// List Artists
  FXbool listArtists(FXComboBox * list);

  /// List Albums from Artist
  FXbool listAlbums(FXComboBox * list,FXint album);

	/// List Tracks from Album
	FXbool listTracks(FXIntList & list,FXint album,FXint genre,FXint playlist=-1);

	/// List Tracks with genre
	FXbool listTracks(FXIntList & list,FXint genre);

	FXbool listTracksArtists(FXIntList & list,FXint artist,FXint genre,FXint playlist=-1);

  /// List Playlists
  FXbool listPlaylists(FXIntList & ids);

  ///=======================================================================================
  ///  EXPORT
  ///=======================================================================================
  FXbool exportList(const FXString & filename,FXint playlist,FXuint format);

  /// Destructor
  ~GMTrackDatabase();
  };
#endif
