/*
 * Copyright (C) 2006-2007	Andre Beckedorf
 * 					 		<evilJazz _AT_ katastrophos _DOT_ net>
 * 
 * The few remaining parts in this almost completely rewritten file are
 * Copyright (C) 2005 Atmark <atmarkat _AT_ msn _DOT_ com>
 *                    AGAWA Koji <i _AT_ atty _DOT_ jp>
 *
 * 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.
 */

#ifndef PLAYLIST_H_INCLUDED
#define PLAYLIST_H_INCLUDED

#include <qvaluelist.h>
#include <qlist.h>
#include <qwidget.h>
#include <qpoint.h>

#ifdef QTOPIA
#include "qt/qlistview.h"
#else
#include <qlistview.h>
#endif

#include "sqlite_source/sqlite3.h"

class Media;
class MediaDatabase;
class SkinModeInformation;

class PlayListParams
{
public:
	PlayListParams();
	
	int sortedColumn;
	bool isSortAscending;
	bool isSorted;
	
	QString filterText;
	bool isFiltered;
	
	bool directMode;
};

class PlayListItem: public QListViewItem
{
public:
	PlayListItem(Media *media, unsigned long playlistID, QListView *parent);
	PlayListItem(Media *media, unsigned long playlistID, QListView *parent, QListViewItem *after);
	virtual ~PlayListItem() { }

	Media *media() const { return media_; }

	//QString text(int column) const;
	QString key(int column, bool ascending) const;
	void paintFocus(QPainter * p, const QColorGroup & cg, const QRect & r); 
	void paintCell(QPainter * p, const QColorGroup & cg, int column, int width, int align);
	int width( const QFontMetrics& fm, const QListView* lv, int c ) const;
	
	void setSelected(bool selected);

	inline unsigned long id() { return id_; }
	inline void setID(unsigned long newID) { id_ = newID; };
private:
	friend class PlayList;
	
	Media *media_;
	unsigned long id_;
};

class PlayList: public QListView
{
	Q_OBJECT
	
public:
	/*! 再生順序の種類
	    値に依存している部分があるので、値は変更しないでください。
	*/
	enum PlayOrder {
		ORDER_NORMAL = 0,		//!< 通常
		ORDER_REPEAT_ALL = 1,	//!< 全曲リピート
		ORDER_REPEAT_ONE = 2,	//!< 単曲リピート
		ORDER_RANDOM = 3,	//!< ランダム
		ORDER_REPEAT_RANDOM = 4,	//!< ランダムリピート
		ORDER_MAX = 5
	};

	enum Columns {
		COLUMN_NONE = 0,
		COLUMN_TRACKNO = 1,
		COLUMN_TITLE = 2,
		COLUMN_ARTIST = 3,
		COLUMN_ALBUM = 4,
		COLUMN_LENGTH = 5,
		COLUMN_MAX = 6	
	};
	
	enum InputMode {
		Select = 0,
		MultiSelect = 1,
		Move = 2
	};

	PlayList(const QString &mediaDBFilename, QWidget *parent = 0, const char *name = 0);
	virtual ~PlayList()	;
	
	void clear(bool clearDB = TRUE);
	void takeItem(QListViewItem *);
	
	void beginUpdate();
	void endUpdate();
	
	void beginChangingUpdate();
	void endChangingUpdate();
		
	void updateView(bool omitCacheCheck = false);
	void reloadView() { updateView(true); }
	MediaDatabase *mediaDatabase() { return mediaDatabase_; };	
	
	PlayListItem *lastItem();
	PlayListItem *firstItem();
	PlayListItem *previousItem();
	PlayListItem *nextItem();

	PlayListItem *nextPlayItem(bool modifyCurrentIndex = false);
	PlayListItem *previousPlayItem(bool modifyCurrentIndex = false);
	
	Media *currentMedia();
	Media *nextMedia();
	Media *previousMedia();
	
	void setFilter(const QString &filter);
	void resetFilter();
	void updateFilter();
	bool isFiltered() { return params.isFiltered; };
	
	PlayList::InputMode inputMode() { return inputMode_; }
	void setInputMode(PlayList::InputMode inputmode);
	
	QValueList<unsigned long> getSelectedMediaIDs();
	QList<Media> getSelectedMedia();
	QValueList<unsigned long> getSelectedItemIDs();
	QList<PlayListItem> &selectedItems();
	
	// Play Order
	void setPlayOrder(PlayOrder);
	void checkPlayOrderTable();
	void generatePlayOrderTable();
	
	int sortedColumn() { return params.sortedColumn; }
	bool isSortAscending() { return params.isSortAscending; }
	void setSortParams(int column, bool ascending = TRUE);
	void setSorting(int column, bool ascending = TRUE);	
	void resetSorting();
	bool isSorted() { return params.isSorted; };

	PlayListParams currentParams() { return params; };
	void setParams(PlayListParams params);	
	
	void setBackgroundColors(const QColor &evenColor, const QColor &oddColor);
	void setForegroundColor(const QColor &textColor);
	void setPlayIndicatorImage(const QPixmap &image);
	void setPauseIndicatorImage(const QPixmap &image);	
	
	PlayListItem *activeItem() { return activeItem_; }
	bool activeItemPaused() { return activeItemPaused_; }
	void setActiveItem(PlayListItem *item, bool ensureVisible = false, bool selectItem = false);
	void setActiveItemPaused(bool y);
	void setCurrentItemActive();
	
	int itemIndex(QListViewItem* item);
	int itemCount() { return itemCount_; }
	
	long long totalPlaytime() { return totalPlaytime_; };
	long long totalFileSize() { return totalFilesize_; };
	
	PlayListItem *insertItem(Media *media, PlayListItem *after = NULL);
	PlayListItem *insertItem(unsigned long mediaID, PlayListItem *after = NULL);
	PlayListItem *insertItem(const QString &mediaFilename, PlayListItem *after = NULL);

	void saveColumnOrder(const QCString &configName, const QCString &groupName);
	void saveColumnWidth(const QCString &configName, const QCString &groupName);
	void loadColumnOrder(const QCString &configName, const QCString &groupName);
	void loadColumnWidth(const QCString &configName, const QCString &groupName);	
		
	void setSkinMode(const SkinModeInformation &modeInfo);
	
	void setPlayListSource(const QString &name);
	const QString &playListSource() const { return playListSource_; }
	
	void setViewSource(const QString &name);
	void updateViewStatistics();
	
signals:
	void viewFiltered();
	void viewUpdated();
	void viewSorted();
	void playListSourceChanged();
	
public slots:
	// 前後のアイテムと入替
	void swapPreviousItem();
	void swapNextItem();
	
	void removeSelectedItems();
	
	void setSortedColumn(int column);

	// Look up items	
	PlayListItem *findItemByIndex(int index);
	PlayListItem *findItemByID(unsigned long playlistID);
	PlayListItem *findItemByMediaID(unsigned long mediaID);

	// Set item Active
	void setActiveItemByIndex(int index);
	bool setActiveItemByID(unsigned long playlistID);	
	bool setActiveItemByMediaID(unsigned long mediaID);
	
	void cleanUpMediaCache();
	void saveMediaCache();
	
protected:
	void keyPressEvent(QKeyEvent*);
	void contentsMousePressEvent(QMouseEvent *e); 
	void contentsMouseMoveEvent(QMouseEvent *e); 	
	void contentsMouseReleaseEvent(QMouseEvent *e);
	
private slots:
	void headerIndexChange(int section, int fromIndex, int toIndex);
	void headerClicked(int section);
	
	void mediaDatabaseCompacted();
	void mediaDatabasePreparingStatements(sqlite3 *db);
	void mediaDatabaseFinalizingStatements(sqlite3 *db);
		
private:
	// Media cache
	MediaDatabase *mediaDatabase_;

	int updateCount_;
	bool updatingView_;
	
	PlayOrder playOrder_;
	int *playOrderTable;
	
	int count_, currentIndex;
	
	friend class PlayListItem;
	QColorGroup evenRowColorGroup_;
	QColorGroup oddRowColorGroup_;
	const QPixmap *playIndicatorImage_;
	const QPixmap *pauseIndicatorImage_;	

	PlayListItem *activeItem_;
	unsigned long activeID_;
	unsigned long activeMediaID_;
	bool activeItemPaused_;

	InputMode inputMode_;
	PlayListParams params;
	PlayListParams savedParams;

	QString playListSource_;
	QString viewSource_;
	QString query_;
	
	QString dbFilterText_;
	bool dbFiltered_;
	
	bool dbPlaylistItemOrderDirty_;
	
	int itemCount_;
	long long totalPlaytime_;
	long long totalFilesize_;
	
	bool buttonDown_;
	QPoint buttonDownPos_;
	bool moveTriggered_;
	QList<PlayListItem> selectedItemsForMove_;	
	QList<PlayListItem> selectedItems_;
	bool selectedItemsDirty_;
	
	sqlite3_stmt *stmtInsertMediaIDIntoPlaylist;
	
	void swap(int &, int &);
	
	void ensurePlayListValidInDB();
	void transferPlayListToDB();
	void loadFromViewSource();
	
	void itemSelectedStateChanged(PlayListItem *item, bool selected);
};

#endif	// PLAYLIST_H_INCLUDED