//**************************************************************************
//*                     This file is part of the                           *
//*                MMC - Mpxplay Multimedia Commander                      *
//*                   The source code of MMC is                            *
//*        (C) copyright 1998-2016 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.net                          *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  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.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
//function: video playing surface event handlers

//#define MPXPLAY_USE_DEBUGF 1
#define DISPQT_DEBUG_OUTPUT NULL //stdout
#define DISPQT_DEBUGOUT_EVENT stdout
#define DISPQT_DEBUGOUT_CURSOR NULL //stdout

#include <QtGui>
#include <QtWidgets>
#include "moc_video_qt.h"
#include "moc_mainwindow.h"

extern "C" {
 extern keyconfig kb[];
 extern unsigned long mpxplay_config_videoplayer_type;
}

DispQtVideoEventFilter::DispQtVideoEventFilter(MainWindow *main_window, QWidget *parent, QWidget *filtered) : QObject(parent)
{
	this->main_window = main_window;
	this->parent_widget = parent;
	this->filtered_widget = filtered;
	this->video_surface_contextmenu = NULL;
	this->mouse_pressed_buttons = Qt::NoButton;
	this->mouse_last_globalpos_x = this->mouse_last_globalpos_y = 0; // not needed

	timer_singleclick = new QTimer(this);
	timer_singleclick->setInterval(DISPQT_VIDEOWIDGET_SINGLECLICK_TIMEOUTMS);
	timer_singleclick->setSingleShot(true);
	connect(timer_singleclick, SIGNAL(timeout()), this, SLOT(mouse_singleclick_timeouthandler()));
	this->timer_doubleclick.setSingleShot(true);
	this->singleclick_event = this->mouse_cursor_forbidden_hide = this->singleclick_fullsrc_start = this->fullsrc_curr = this->is_cursor_overrided = false;

	this->timer_mouse_hide = new QTimer;
	this->timer_mouse_hide->setSingleShot(true);
	connect(this->timer_mouse_hide, SIGNAL(timeout()), this, SLOT(mouse_cursor_hide()));

	this->timer_cmenu_hide.setSingleShot(true);
}

bool DispQtVideoEventFilter::is_video_fullscreen(void)
{
	DispQtVideoPlayer *player = (DispQtVideoPlayer *)this->parent_widget;
	return player->video_get_value(DispQtVideoPlayer::VideoCtrlValue_FullScreen);
}

void DispQtVideoEventFilter::mouse_cursor_forbid_hide(bool forbid)
{
	this->mouse_cursor_forbidden_hide = forbid;
	this->mouse_cursor_show_timed(false);
}

void DispQtVideoEventFilter::mouse_cursor_show_timed(bool timed)
{
	mutex_video.tryLock(DISPQT_VIDEO_MUTEX_TIMEOUT);
	mpxplay_debugf(DISPQT_DEBUGOUT_CURSOR, "mouse_cursor_show_timed b:%d t:%d", this->is_cursor_blank, timed);
	if(this->is_cursor_overrided){
		QApplication::restoreOverrideCursor();
		QCursor *cursor = QApplication::overrideCursor();
		if(cursor){
			Qt::CursorShape curshape = QApplication::overrideCursor()->shape();
			if((curshape == Qt::BlankCursor) || (curshape == Qt::OpenHandCursor)) // list all modified cursor shape here
				QApplication::setOverrideCursor(Qt::ArrowCursor);
		}
		this->is_cursor_overrided = false;
	}
	if(timed && !this->mouse_cursor_forbidden_hide && this->is_video_fullscreen()){
		this->timer_mouse_hide->setInterval(DISPQT_VIDEO_CURSORHIDE_TIMEOUT);
		this->timer_mouse_hide->start();
	}else
		this->timer_mouse_hide->stop();
	mutex_video.unlock();
}

void DispQtVideoEventFilter::mouse_cursor_hide(void)
{
	mutex_video.tryLock(DISPQT_VIDEO_MUTEX_TIMEOUT);
	mpxplay_debugf(DISPQT_DEBUGOUT_CURSOR, "mouse_cursor_hide b:%d", this->is_cursor_blank);
	if(!this->is_cursor_overrided){
		QApplication::setOverrideCursor(Qt::BlankCursor);
		this->is_cursor_overrided = true;
	}
	mutex_video.unlock();
}

void DispQtVideoEventFilter::cmenu_about_hide(void)
{
	this->timer_cmenu_hide.start(DISPQT_VIDEOWIDGET_CMENUHIDE_TIMEOUTMS);
	this->mouse_pressed_buttons = Qt::NoButton;
	this->mouse_cursor_show_timed(true);
}

void DispQtVideoEventFilter::mouse_singleclick_timeouthandler(void)
{
	mutex_video.tryLock(DISPQT_VIDEO_MUTEX_TIMEOUT);
	mpxplay_debugf(DISPQT_DEBUGOUT_EVENT, "STO: b:%d", this->mouse_pressed_buttons);
	if((this->singleclick_fullsrc_start == this->fullsrc_curr) && !this->timer_doubleclick.isActive())
	{
		if(this->mouse_pressed_buttons == Qt::LeftButton)
		{
			QApplication::setOverrideCursor(Qt::OpenHandCursor);
			this->is_cursor_overrided = true;
		}
		else if(this->mouse_pressed_buttons == Qt::NoButton)
		{
			this->timer_doubleclick.start(DISPQT_VIDEOWIDGET_DOUBLECLICK_TIMEOUTMS);
			this->main_window->mainwin_handle_keypresscode(kb[51].c);
			this->singleclick_event = true;
		}
	}
	mutex_video.unlock();
}

void DispQtVideoEventFilter::video_surface_move(int move_x, int move_y)
{
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	if(mpxplay_config_videoplayer_type == MPXPLAY_VIDEOPLAYERTYPE_FFMPEG)
		emit ((FFMpegVideoWidget *)this->filtered_widget)->signal_ffmpeg_swctx_move(move_x, move_y); // FIXME: hack
#endif
}

void DispQtVideoEventFilter::video_zoom_step(int globalpos_x, int globalpos_y, int direction)
{
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	if(mpxplay_config_videoplayer_type == MPXPLAY_VIDEOPLAYERTYPE_FFMPEG)
		emit ((FFMpegVideoWidget *)this->filtered_widget)->signal_ffmpeg_swctx_zoom(globalpos_x, globalpos_y, direction); // FIXME: hack
#endif
}

void DispQtVideoEventFilter::video_callback_call(int globalpos_x, int globalpos_y, unsigned long command, void *arg1, int *arg2)
{
#ifdef MPXPLAY_LINK_ORIGINAL_FFMPEG
	if(mpxplay_config_videoplayer_type == MPXPLAY_VIDEOPLAYERTYPE_FFMPEG)
		emit ((FFMpegVideoWidget *)this->filtered_widget)->videowidget_ffmpeg_callback_call(globalpos_x, globalpos_y, command, arg1, arg2); // FIXME: hack
#endif
}

bool DispQtVideoEventFilter::eventFilter(QObject *watched, QEvent *event)
{
	bool accepted = false;
	if(watched != (QObject *)this->filtered_widget)
		return accepted;
	//mpxplay_debugf(DISPQT_DEBUGOUT_EVENT, "video event: %d", event->type());
	accepted = true;
	QMouseEvent *me = static_cast<QMouseEvent*>(event);
	switch(event->type()){
		case QEvent::Close:
			if(this->main_window->gui_config->video_control & DISPQT_CONFIG_VIDEOCTRL_ENABLE_VIDEO)
				this->main_window->CloseWindowTriggeredfromExternal();
			accepted = false;
			break;
		case QEvent::KeyPress:
			{
				QKeyEvent *ke = static_cast<QKeyEvent*>(event);
				mpxplay_debugf(stdout, "KEY event DispQtVideoEventFilter");
				this->main_window->handle_keypressevent(ke);
			}
			break;
		case QEvent::MouseButtonPress:
			this->mouse_cursor_show_timed(false);
			this->mouse_pressed_buttons = me->button();
			this->mouse_last_globalpos_x = me->globalX();
			this->mouse_last_globalpos_y = me->globalY();
			if(me->button() & Qt::LeftButton){  // start or stop playing with single click, fullscreen switch with double click
				if(!this->timer_doubleclick.isActive() && !this->timer_singleclick->isActive() && !this->timer_cmenu_hide.isActive()) {
					this->timer_singleclick->start(DISPQT_VIDEOWIDGET_SINGLECLICK_TIMEOUTMS);
					this->singleclick_fullsrc_start = this->fullsrc_curr = is_video_fullscreen();
					this->singleclick_event = false;
					//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "MPE");
				}
			} else if(me->button() & Qt::RightButton){  // context menu open
				//this->menuaction_filename->setText(((DispQtVideoPlayer *)this->parent_widget)->video_media_name());
				this->timer_singleclick->stop();
				if(this->video_surface_contextmenu){
					disconnect(this->video_surface_contextmenu, SIGNAL(aboutToHide()), this, SLOT(cmenu_about_hide()));
					delete this->video_surface_contextmenu;
				}
				this->video_surface_contextmenu = new DispQtVideoSurfaceContextMenu(this->main_window, this, this->filtered_widget);
				connect(this->video_surface_contextmenu, SIGNAL(aboutToHide()), this, SLOT(cmenu_about_hide()));
				this->video_surface_contextmenu->popup(me->globalPos());
			}
			break;
		case QEvent::MouseButtonRelease:
			if(this->mouse_pressed_buttons & Qt::LeftButton)
				this->mouse_cursor_show_timed(true);
			this->mouse_pressed_buttons = Qt::NoButton;
			break;
		case QEvent::MouseButtonDblClick:
			this->timer_doubleclick.start(DISPQT_VIDEOWIDGET_DOUBLECLICK_TIMEOUTMS);
			this->timer_singleclick->stop();
			this->fullsrc_curr = !is_video_fullscreen();
			emit ((DispQtVideoPlayer *)this->parent_widget)->signal_video_switch_fullscreen();
			if(this->singleclick_event) {
				this->main_window->mainwin_handle_keypresscode(kb[51].c); // start again playing
				this->singleclick_event = false;
			}
			this->mouse_pressed_buttons = Qt::NoButton;
			//mpxplay_debugf(DISPQT_DEBUG_OUTPUT, "DC se:%d", (int)this->singleclick_event);
			break;
		case QEvent::MouseMove:
			if(this->mouse_pressed_buttons & Qt::LeftButton){ // drag and move video surface
				int move_x = this->mouse_last_globalpos_x - me->globalX();
				int move_y = this->mouse_last_globalpos_y - me->globalY();
				if((move_x >= 5) || (move_y >= 5)){  // then it's a move event, disable singleclick event  FIXME: still not enough (sometimes the pause is activated)
					this->timer_singleclick->stop();
					QApplication::setOverrideCursor(Qt::OpenHandCursor);
					this->is_cursor_overrided = true;
				}
				this->video_surface_move(move_x, move_y);
				this->mouse_last_globalpos_x = me->globalX();
				this->mouse_last_globalpos_y = me->globalY();
				//mpxplay_debugf(DISPQT_DEBUGOUT_EVENT, "move event x:%d", this->mouse_last_globalpos_x);
			}
			else if((this->mouse_pressed_buttons == Qt::NoButton) && this->is_video_fullscreen()){
				this->mouse_cursor_show_timed(true);
				if(!(me->modifiers() & Qt::ControlModifier))  // feature: if Ctrl button is pressed, main window does not appear
					this->main_window->mainwin_video_check_show(me->globalX(), me->globalY());
			}
			accepted = false;
			break;
		case QEvent::Wheel:
			{
				QWheelEvent *we = static_cast<QWheelEvent*>(event);
				//mpxplay_debugf(DISPQT_DEBUGOUT_EVENT, "video wheel event %d", we->delta());
				if(me->modifiers() & Qt::ControlModifier){  // FIXME: even if mainwin is hidden, it catches the wheel control on that surface area, zoom doesn't work
					this->video_zoom_step(we->globalX(), we->globalY(), (we->delta() < 0)? -1 : 1);
				}else{
					this->main_window->mainwin_handle_keypresscode(kb[(we->delta() < 0)? 83 : 81].c);  // volume up / down
					if(this->main_window->gui_config->mainwin_control & DISPQT_CONFIG_MAINWINCTRL_SHOW_AVMIXER)
						emit this->main_window->signal_video_mainwin_wakeup(true, true);
				}
			}
			break;
		default: accepted = false;
			break;
	}
	if(accepted)
		event->accept();
	else
		accepted = QObject::event(event);
	return accepted;
}
