/*
 * kxinewidget.h - a kde / qt api for xine-lib
 *
 * Copyright (C) 2003-2005 Jürgen Kofler <kaffeine@gmx.net>
 * Copyright (C) 2005-2006 Christophe Thommeret <hftom@free.fr>
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
 */

#ifndef KXINEWIDGET_H
#define KXINEWIDGET_H

/* define this if you want to use QT only - disables post plugin support (except visualization)! */
//#define USE_TQT_ONLY 1

/* Usage:
 *
 * KXineWidget m_xine = new KXineWidget(parent);
 * m_xine->appendToQueue("the_best_song_of_the_world.mp3");
 *
 * You should at least connect to signalXineFatal(const TQString&)!
 *
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* forward declaration */
class TQWidget;
class TQString;
class TQStringList;
class TQMouseEvent;
class TQTimerEvent;
class TQTime;

#include <tqtimer.h>
#include <tqptrlist.h>
#include <tqthread.h>
#include <X11/Xlib.h>
#include <xine.h>


#ifndef USE_TQT_ONLY
#include "postfilter.h"
#else
typedef int PostFilter; /* dummy type */
#endif

#ifdef HAVE_XCB
#include <xcb/xcb.h>
#endif

#define SUPPORTED_PROTOCOLS "file,http,mms,mmst,rtsp,rtp,tcp,pnm,cdda,vcd,vcdo,dvd,dvb,pvr,v4l,net,vdr,smb"

#define DEFAULT_TVTIME_CONFIG "tvtime:method=LinearBlend,enabled=1,pulldown=none,framerate_mode=half_top,judder_correction=0,use_progressive_frame_flag=1,chroma_filter=0,cheap_mode=1"

#define DEFAULT_OSD_FONT_SIZE 18
#define DEFAULT_OSD_DURATION  5000
#define OSD_MESSAGE_LOW_PRIORITY    1
#define OSD_MESSAGE_NORMAL_PRIORITY 2

class KXineWidget : public TQWidget, public TQThread
{

	TQ_OBJECT
  

public:
	KXineWidget(TQWidget *parent=0, const char *name=0,
	            const TQString& pathToConfigFile = TQString(), const TQString& pathToLogoFile = TQString(),
	            const TQString& audioDriver = TQString(), const TQString& videoDriver = TQString(),
	            bool startManual = false, bool verbose = false);
	~KXineWidget();

	enum Speed { Normal = 0, Pause, Fast1, Fast2, Slow1, Slow2, Undefined };

	bool initXine(); /* call this only if you set startManual = true in the constructor */
	bool isXineReady() const { return m_xineReady; }
	bool isPlaying() const;
	Speed getSpeed() const { return m_currentSpeed; }
	TQString getXineLog() const;

	void setQueue(const TQStringList& urls) { m_queue = urls; }
	void appendToQueue(const TQString& url) { m_queue.append(url); } /* file to play; call slotPlay() to play queue... */
	void clearQueue() { m_queue.clear(); }
	bool isQueueEmpty() const { return m_queue.empty(); }

	void showOSDMessage(const TQString& message, uint duration = DEFAULT_OSD_DURATION /* ms */, int priority = OSD_MESSAGE_NORMAL_PRIORITY);

	/* stream info */
	const TQString& getURL() const { return m_trackURL; }
	const TQString& getTitle() const { return m_trackTitle; }
	const TQString& getArtist() const { return m_trackArtist; }
	const TQString& getAlbum() const { return m_trackAlbum; }
	const TQString& getTrackNumber() const { return m_trackNumber; } //may return an empty string with xine-lib 1.0
	const TQString& getGenre() const { return m_trackGenre; }
	const TQString& getYear() const { return m_trackYear; }
	const TQString& getComment() const { return m_trackComment; }
	const TQTime& getLength() const { return m_trackLength; }
	const TQString& getVideoCodec() const { return m_trackVideoCodec; }
	TQSize getVideoSize() const { return TQSize(m_videoFrameWidth, m_videoFrameHeight); }
	int getVideoWidth();
	int getVideoHeight();
	uint getVideoBitrate() const { return m_trackVideoBitrate; }
	const TQString& getAudioCodec() const { return m_trackAudioCodec; }
	uint getAudioBitrate() const { return m_trackAudioBitrate; }
	const TQString& getSubtitleURL() const { return m_trackSubtitleURL; }
	const TQString& getSaveURL() const { return m_trackSaveURL; }
	bool hasVideo() const { return m_trackHasVideo; }
	bool hasAudio() const { return m_trackHasAudio; }
	bool hasChapters() const { return m_trackHasChapters; }
	bool hasSubtitleURL() const { return !m_trackSubtitleURL.isNull(); }
	bool hasSaveURL() const { return !m_trackSaveURL.isNull(); }
	bool isSeekable() const { return m_trackIsSeekable; }

	uint getVolume() const; /* percent */
	bool SoftwareMixing() const;
	TQTime getPlaytime() const;
	uint getPosition() const; /* 0..65535 */

	void savePosition(const int pos) { (pos > 0) ? m_savedPos = pos : m_savedPos = 0; }

	/* plugin handling */
	TQStringList getAudioDrivers() const { return m_audioDriverList; }
	TQStringList getVideoDrivers() const { return m_videoDriverList; }
	void getAutoplayPlugins(TQStringList& pluginNames) const;
	bool getAutoplayPluginURLS(const TQString& name, TQStringList& urls);
	TQStringList getVisualPlugins() const;

#ifndef USE_TQT_ONLY
	void createDeinterlacePlugin(const TQString& configString, TQWidget* parent);
	const TQString getDeinterlaceConfig() const;
	TQStringList getVideoFilterNames() const;
	TQStringList getAudioFilterNames() const;
	TQStringList getAudioFilterConfig();
	TQStringList getVideoFilterConfig();
#endif

	TQString getSupportedExtensions() const;  /* get mime types xine can play */

	void playNextChapter() const;
	void playPreviousChapter() const;

	/* config stuff */
	void setStreamSaveDir(const TQString& dir);
	const TQString getStreamSaveDir();
	void setBroadcasterPort(const uint port);
	void getVideoSettings(int& hue, int& sat, int& contrast, int& bright,
	                      int& avOffset, int& spuOffset) const;
	void getspuOffset(int& spuOffset) const;
	/* disc drives devices*/
	TQString audiocdDevice() const;
	TQString vcdDevice() const;
	TQString dvdDevice() const;

	/* dvd stuff */
	uint currentDVDTitleNumber() const;
	uint getDVDTitleCount() const;
	uint currentDVDChapterNumber() const;
	uint getDVDChapterCount() const;
	uint currentDVDAngleNumber() const;
	uint getDVDAngleCount() const;

	/* take a screenshot */
	TQImage getScreenshot() const;
	void getScreenshot(uchar*& rgb32BitData, int& videoWidth, int& videoHeight, double& scaleFactor) const;

	/* get the xine engine, needed by the xine configuration dialog */
	const xine_t* const getXineEngine() const;
	void saveXineConfig();

	/* for fullscreen */
	void startMouseHideTimer();
	void stopMouseHideTimer();

	void globalPosChanged();  /* call this if global pos of parent was changed */

signals:
	void signalXineFatal(const TQString& message);   /** initXine() not successfull! **/
	void signalXineError(const TQString& message);
	void signalXineMessage(const TQString& message);
	void signalXineStatus(const TQString& status);
	void signalXineReady();
	void signalXinePlaying();

	void signalHasChapters(bool);
	void signalPlaybackFinished();
	void signalNewChannels(const TQStringList& audio, const TQStringList& sub, int currentAudio, int currentSub);
	void signalNewPosition(int, const TQTime&);

	void signalTitleChanged();
	void signalVideoSizeChanged();
	void signalLengthChanged();

	void signalRightClick(const TQPoint&);  /* right-click on video window */
	void signalLeftClick(const TQPoint&);
	void signalMiddleClick();
	void signalDoubleClick();
	void signalSyncVolume();

	void signalDvbOSDHidden();

public slots:
	virtual void polish();

	void slotPlay();
	void slotStop();

	void slotSetVolume(int);
	void slotToggleMute();
	void slotSpeedPause();
	void slotSpeedNormal();
	void slotSpeedFaster();
	void slotSpeedSlower();
	void slotSetVisualPlugin(const TQString& name);
	void slotSetAudioChannel(int);
	void slotSetSubtitleChannel(int);
	void slotSetFileSubtitles(TQString);
	void slotStartSeeking();
	void slotSeekToPosition(int pos);
	void slotSeekToPositionBlocking(int pos);
	void slotSeekToTime(const TQTime&);
	void slotStopSeeking();
	void slotEnableVideoFilters(bool enable);
	void slotEnableAudioFilters(bool enable);
	void slotEject();
	void slotEnableAutoresize(bool enable);
	void slotAspectRatioAuto();
	void slotAspectRatio4_3();
	void slotAspectRatioAnamorphic(); /* 16:9 */
	void slotAspectRatioSquare(); /* 1:1 */
	void slotAspectRatioDVB(); /* 2.11:1 */
	void slotZoomIn();
	void slotZoomOut();
	void slotZoomOff();
	void slotZoomOutX();
	void slotZoomInX();
	void slotZoomOutY();
	void slotZoomInY();
	void slotToggleDeinterlace();
	void slotSetDeinterlaceConfig(const TQString&);
	void slotGetInfoDelayed();

	/* disc drive devices */
	void slotSetAudiocdDevice(const TQString&);
	void slotSetVcdDevice(const TQString&);
	void slotSetDvdDevice(const TQString&);

	void slotSetHue(int hue);
	void slotSetSaturation(int sat);
	void slotSetContrast(int contrast);
	void slotSetBrightness(int bright);
	void slotSetAVOffset(int av);
	void slotSetSpuOffset(int spu);

	void slotSetEq30(int val);
	void slotSetEq60(int val);
	void slotSetEq125(int val);
	void slotSetEq250(int val);
	void slotSetEq500(int val);
	void slotSetEq1k(int val);
	void slotSetEq2k(int val);
	void slotSetEq4k(int val);
	void slotSetEq8k(int val);
	void slotSetEq16k(int val);
	void slotSetVolumeGain(bool gain);

	/* DVD Menus */
	void slotMenuToggle();
	void slotMenuTitle();
	void slotMenuRoot();
	void slotMenuSubpicture();
	void slotMenuAudio();
	void slotMenuAngle();
	void slotMenuPart();
	void slotDVDMenuLeft();
	void slotDVDMenuRight();
	void slotDVDMenuUp();
	void slotDVDMenuDown();
	void slotDVDMenuSelect();

	/***** postprocess filters ****/
	void slotCreateVideoFilter(const TQString& name, TQWidget* parent);
	void slotCreateAudioFilter(const TQString& name, TQWidget* parent);
	void slotDeleteVideoFilter(PostFilter* filter);
	void slotDeleteAudioFilter(PostFilter* filter);
	void slotRemoveAllVideoFilters();
	void slotRemoveAllAudioFilters();

protected slots:
	void slotSendPosition();
	void slotEmitLengthInfo();
	void slotHideMouse();
	void slotOSDHide();
	void slotNoRecentMessage();

protected:
	void mouseMoveEvent(TQMouseEvent*);
	void mousePressEvent(TQMouseEvent*);
	void timerEvent(TQTimerEvent*);
	void mouseDoubleClickEvent(TQMouseEvent*);
	void wheelEvent(TQWheelEvent*);
	void initOSD();
	virtual void run();

  static int makeVolumeLogarithmic(int volume);

  static bool s_logarithmicVolume;

private:
#ifndef HAVE_XCB
	bool x11Event(XEvent *);
#else
	void paintEvent(TQPaintEvent *);
#endif

	/********* callbacks and threads ************/
	static void destSizeCallback(void* p, int video_width, int video_height, double video_aspect,
	                             int* dest_width, int* dest_height, double* dest_aspect);

	static void frameOutputCallback(void* p, int video_width, int video_height, double video_aspect,
	                                int* dest_x, int* dest_y, int* dest_width, int* dest_height,
	                                double* dest_aspect, int* win_x, int* win_y);

	static void videoDriverChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void audioDriverChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void audioMixerMethodChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void showOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void sizeForOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void fontForOSDMessagesChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void monitorXResChangedCallback(void* p, xine_cfg_entry_t* entry);
	static void monitorYResChangedCallback(void* p, xine_cfg_entry_t* entry);

	static void xineEventListener(void* p, const xine_event_t*);

protected:
	void sendXineError();
	TQTime getLengthInfo();
#ifndef USE_TQT_ONLY
	void wireVideoFilters();
	void unwireVideoFilters();
	void wireAudioFilters();
	void unwireAudioFilters();
#endif

	/* HELPER FUNCTIONS */
public:
#ifdef USE_TQT_ONLY
	static TQString i18n(const char *text);
#endif
	static void debugOut(TQString);
	static void errorOut(TQString);
	static void warningOut(TQString);
	static TQTime msToTime(int msec);
	static void   yuy2Toyv12(uint8_t *y, uint8_t *u, uint8_t *v, uint8_t *input, int width, int height);
	static uchar *yv12ToRgb(uint8_t *src_y, uint8_t *src_u, uint8_t *src_v, int width, int height);

protected:
	TQStringList m_queue;

	int seekThreadPos;
	int seekThreadTime;
	bool seekThreadPause;
	bool m_startXineManual;
	bool m_xineReady;
	TQString m_logoFile;
	TQString m_preferedAudio;
	TQString m_preferedVideo;
	bool m_xineVerbose;
	TQString m_configFilePath;
	TQStringList m_audioDriverList;
	TQStringList m_videoDriverList;

	/*x11*/
#ifndef HAVE_XCB
	Display *connection;
#else
	xcb_connection_t *connection;
#endif

	/*xine*/
#ifndef HAVE_XCB
	x11_visual_t m_x11Visual;
#else
	xcb_visual_t m_x11Visual;
#endif
	xine_t* m_xineEngine;
	xine_audio_port_t* m_audioDriver;
	xine_video_port_t* m_videoDriver;
	xine_stream_t* m_xineStream;
	xine_event_queue_t* m_eventQueue;
	xine_osd_t* m_osd;
	bool m_osdUnscaled;
	bool m_osdShow;
	int m_osdSize;
	char* m_osdFont;
	char** m_audioChoices;
	char* m_audioInfo;
	char** m_videoChoices;
	char* m_videoInfo;
	char* m_mixerInfo;
	char* m_osdShowInfo;
	char** m_osdSizeOptions;
	char* m_osdSizeInfo;
	char* m_osdFontInfo;
	double monitorXRes, monitorYRes;
	char *xResInfo;
	char *yResInfo;

#ifndef USE_TQT_ONLY
	/*postfilter*/
	TQPtrList<PostFilter> m_videoFilterList;
	bool m_videoFiltersEnabled;
	TQPtrList<PostFilter> m_audioFilterList;
	bool m_audioFiltersEnabled;
	PostFilter* m_deinterlaceFilter;
	bool m_deinterlaceEnabled;
	PostFilter* m_visualPlugin;
#else
	xine_post_t* m_xinePost;
	xine_post_out_t* m_postAudioSource;
	xine_post_in_t* m_postInput;
#endif

	TQString m_audioDriverName;
	TQString m_videoDriverName;
	TQString m_visualPluginName;

	int m_videoFrameWidth;
	int m_videoFrameHeight;
	double m_videoAspect;
	int m_globalX;
	int m_globalY;

	Speed m_currentSpeed;
	TQString m_xineMessage;
	TQString m_xineError;
	TQString m_statusString;
	bool m_softwareMixer;
	bool m_volumeGain;
	double m_displayRatio;
	TQString m_cachedCDPath, m_cachedVCDPath, m_cachedDVDPath;
	TQSize m_newParentSize;
	int m_currentZoom;
	int m_currentZoomX, m_currentZoomY;
	TQStringList m_audioCh;
	TQStringList m_subCh;
	int m_currentAudio, m_currentSub;
	int m_savedPos;
	bool m_autoresizeEnabled;
	bool m_DVDButtonEntered;
	TQString m_newMRLReference;

	TQTimer m_posTimer;
	TQTimer m_lengthInfoTimer;
	uint m_lengthInfoTries;
	TQTimer m_mouseHideTimer;
	TQTimer m_osdTimer;
	TQTimer m_recentMessagesTimer;

	TQString m_trackURL;
	TQString m_trackTitle;
	TQString m_trackArtist;
	TQString m_trackAlbum;
	TQString m_trackNumber;
	TQString m_trackGenre;
	TQString m_trackYear;
	TQString m_trackComment;
	TQTime m_trackLength;
	TQString m_trackVideoCodec;
	uint m_trackVideoBitrate;
	TQString m_trackAudioCodec;
	uint m_trackAudioBitrate;
	TQString m_trackSubtitleURL;
	TQString m_trackSaveURL;
	bool m_trackHasVideo;
	bool m_trackHasAudio;
	bool m_trackHasChapters;
	bool m_trackIsSeekable;

	/*  dvb  */
signals:
	void stopDvb();

public:
	TQString TimeShiftFilename;

public slots:
	void setDvb( const TQString &pipeName, const TQString &chanName, int haveVideo );
	void setDvbCurrentNext( const TQString &channelName, const TQStringList &list );
	bool openDvb();
	bool playDvb();
	void slotPlayTimeShift();
	void dvbShowOSD();
	void dvbHideOSD();

private:
	TQString m_dvbChannelName;
	bool m_dvbSaveTitle;
	int dvbHaveVideo;
	TQTimer dvbOSDHideTimer;
	xine_osd_t *dvbOSD;
	TQStringList dvbCurrentNext;
	unsigned int dvbColor[256];
	unsigned char dvbTrans[256];
	void initDvbPalette();
};

#endif /* KXINEWIDGET_H */
