#include <config.h>
#include <creators.h>
#include <version.h>
#include <stdlib.h>
#include <unistd.h>
#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

#include <qdragobject.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qmessagebox.h>
#include <qgroupbox.h>
#include <qpainter.h>
#include <qpopupmenu.h>
#include <qprogressbar.h>
#include <qpushbutton.h>
#include <qslider.h>
#include <qstrlist.h>
#include <qtimer.h>
#include <qvbox.h>
#include "mywidget.h"
#include "MyConfigImpl.h"

extern MyWidget* m;

static const char* helptxt =
    "<h3>Usage:</h3>"
    "aviplay [your-file] [subtitle-file]<br>"
    "<h3>Key bindings:</h3>"
    "Keypad '+' - volume up.<br>"
    "Keypad '-' - volume down.<br>"
    "Cursor right or PageUp - next keyframe.<br>"
    "Cursor left or PageDown - previous keyframe.<br>"
    "Cursor up - 60 seconds forward.<br>"
    "Cursor down - 60 seconds backward.<br>"
    "Enter - display next frame (use in pause mode).<br>"
    "Home - movie begin.<br>"
    "End - movie end.<br>"
    "F - toggles fullscreen/windowed mode.<br>"
    "M - toggles fullscreen/windowed mode with maximization.<br>"
    "Q - quit<br>"
    "X - stop<br>"
    "V - play<br>"
    "[, ] - adjust a-v sync by 0.1 second.<br>"
    "C, P or Space - pause<br>"
    "F, Escape or Alt + Enter - toggles fullscreen/windowed mode.<br>"
    "1,2,3 - switch zoom 0.5x, 1x, 2x.<br>"
    "Left-click in player window - pause/play.<br>"
    "Right-click in movie window brings up zoom/fullscreen menu.<br>"
    //"Double-click in player window when paused/stopped "
    //"to bring up configuration menu.<br>"
    ;

static const char* abouttxt =
    "AVI player version %.2f<br>"
    "(C) 2000 - 2001 Eugene Kuznetsov, Zdenek Kabelac <br>"
    "Based on avifile ( <a href=\"http://divx.euro.ru\">http://divx.euro.ru/</a>).<br>"
    "Distributed under the GNU Public Licence (GPL) version 2.<br>"
    "Special thanks to: "
    "<ul>"
    "<li>Authors of Wine project for Win32 DLL loading code."
    "<li>Avery Lee for AVI and ASF parser and his VirtualDub."
    "<li>Hiroshi Yamashita for porting sources to FreeBSD."
    "<li>Jürgen Keil for porting sources to Solaris 8 x86."
    "<li>Árpád Gereöffy (A'rpi/ESP-team) - helping to understand some internal details."
    "<li>All people from XMPS & avifile mailing lists for their patience and support."
    "</ul>";

using namespace std;
using namespace Creators;

#if !HAVE_UNSETENV
static void unsetenv(const char *name)
{
    extern char **environ;
    char **ep;
    int len = strlen(name);
    for (ep = environ; *ep; ep++)
    {
	if (strncmp(*ep, name, len) == 0 && (*ep)[len] == '=')
	{
	    while ((ep[0] = ep[1]) != NULL)
		ep++;
	    break;
	}
    }
}
#endif


#if !HAVE_SETENV
static void setenv(const char *name, const char *val, int _xx)
{
    char *env = new char[strlen(name) + strlen(val) + 2];

    strcpy(env, name);
    strcat(env, "=");
    strcat(env, val);
    putenv(env);
}
#endif

DrawEvent g_event;

void MyWidget::readConfig()
{
    if (player)
    {
	// FIMXE
	bool ht;
	char* vcodecs = 0;
	char* acodecs = 0;

        player->Get(player->DISPLAY_FRAME_POS, &m_bDisplayFramePos,
		    player->AUTOREPEAT, &m_bAutorepeat,
		    player->USE_HTTP_PROXY, &ht,
		    player->VIDEO_CODECS, &vcodecs,
		    player->AUDIO_CODECS, &acodecs,
		    0);
	if (ht)
	{
	    char* proxy = 0;
	    player->Get(player->HTTP_PROXY, &proxy, 0);
	    if (proxy)
	    {
		if (strlen(proxy))
		    setenv("HTTP_PROXY", proxy, 1);
                free(proxy);
	    }
	}
	else unsetenv("HTTP_PROXY");

	if (vcodecs)
	{
	    SortVideoCodecs(vcodecs);
            free(vcodecs);
	}
	if (acodecs)
	{
	    SortAudioCodecs(acodecs);
            free(acodecs);
	}
    }
}

void MyWidget::reseek_func()
{
    if (!player)
        return;

    double pos = scroller->value();
    pthread_mutex_lock(&g_event.mutex);
    if (g_event.data)
	pthread_cond_broadcast(&g_event.cond);
    _in_reseek=1;
    pthread_mutex_unlock(&g_event.mutex);
    player->ReseekExact(pos);
    updatePos();
    is_tracking=0;
    _in_reseek=0;
}

void killer(int z)
{
    printf("quit_flag=1\n");
}

void MyWidget::draw_slot()
{
/*
    pthread_mutex_lock(&g_event.mutex);
    if(renderer)
	renderer->Draw(g_event.data);
    pthread_cond_broadcast(&g_event.cond);
    pthread_mutex_unlock(&g_event.mutex);
*/
}

PixmapButton::PixmapButton(const char* ficon, const char* name, QWidget* parent):QPushButton(name, parent)
{
    char filename[1024];

    sprintf(filename, "%s/%s.ppm", SHARE_PATH, ficon);
    m_pm.load(filename);
    setPixmap(m_pm);
    setFixedSize(m_pm.width() + 4, m_pm.height() + 4);
}

void PixmapButton::paintEvent(QPaintEvent* pe)
{
    QPushButton::paintEvent(pe);
    //return;
    QPainter p(this);
    p.drawPixmap(2 , 2, m_pm);
    p.flush();
}

#define __MODULE__ "AVI player widget"
int MyWidget::initPlayer(AviPlayerInitParams& uapip)
{
    apip = uapip;

    last_slider = 0;
    if (scroller)
	scroller->setValue(0);

    try
    {
	endPlayer();

	if (popup)
	{
	    delete popup;
	    popup = 0;
	}

	player = CreateAviPlayer2(this, x11Display(), apip.filename, apip.subname);

	readConfig();
	//if (quality == 11)
	//    player->SetDecodingMode(IVideoDecoder::REALTIME_QUALITY_AUTO);
	l_status->setText("Opening...");
	_start_timer->start(1000); // large timeout for debugging
	if (vbar)
	    volume_func(vbar->value());
    }
    catch(FatalError& error)
    {
	endPlayer();
	throw;
    }
    catch(...)
    {
	cerr<<"Unknown exception"<<endl;
    }
    return 0;
}

void MyWidget::starter_slot()
{
    if (!player || !player->IsOpened())
	return;
    if (!player->IsValid())
    {
	_start_timer->stop();
	endPlayer();
	/* may be show a message box here? */
	l_status->setText("Failed to open");
	return;
    }
    if (player->IsRedirector())
    {
	_start_timer->stop();
	vector<string> urls;
	player->GetURLs(urls);
	endPlayer();
	if (!urls.size())
	{
	    cout<<"Redirector with no entries?"<<endl;
	    return;
	}
	if (urls.size() > 1)
	{
	    cout<<"Multi-URL redirectors aren't yet properly supported, sorry"<<endl;
	    cout<<"Contents of the redirector: "<<endl;
	    for (unsigned i = 0; i < urls.size(); i++)
		cout<<urls[i]<<endl;
	    cout<<"Attempting to open default first entry"<<endl;
	}
	AviPlayerInitParams ip;
        ip.filename = urls[0].c_str();
	initPlayer(ip);
	return;
    }
    _start_timer->stop();

    if (apip.width && apip.height)
        player->Resize(apip.width, apip.height);

    //move(100,100);
    setCaption(_filename.c_str());
    //	Scroll bar
    double len = player->GetVideoLengthTime();
    if (len == 0)
        len = player->GetAudioLengthTime();

    scroller->setMinValue(0);
    scroller->setMaxValue((int)len);

    int step = int(len)/40;
    scroller->setLineStep((step < 1) ? 1 : (step > 100) ? 100 : step);
    scroller->repaint();

    _timer->start(1000);

    play_func();

    cout<<"Player started"<<endl;

    if (apip.seek > 0.0)
	player->ReseekExact(apip.seek);

    if (apip.maximize)
        send_maximize();
    else if (apip.fullscreen)
        send_fullscreen();
}

void MyWidget::endPlayer()
{
    _timer->stop();
    delete player;
    player=0;
}

void MyWidget::updatePosDisplay(int pos)
{

    if (!player)
        return;

    double percent;
    IAviPlayer::State state = player->GetState(&percent);

    if (state == IAviPlayer::Playing || state == IAviPlayer::Paused)
    {
	char timing[50];
	double len = player->GetLengthTime();
	double stream_time = pos;//player->GetPos();
	char* spos = timing;

	//cout << "pos " << pos << "  " << stream_time << endl;
	if (stream_time >= 3600)
	    spos += sprintf(spos, "%d:", int(stream_time/3600));

	spos += sprintf(spos, "%02d:%02d", int(stream_time/60)%60,
			int(stream_time)%60);

	if (m_bDisplayFramePos)
            // more precise timeing with frame position
	    spos += sprintf(spos, ".%03d", int(stream_time*1000)%1000);

	if (len >= 3600)
	    spos += sprintf(spos, "/%d:", int(len/3600));
	else
	    spos += sprintf(spos, "/");

	spos += sprintf(spos, "%02d:%02d", int(len/60)%60, int(len)%60);

        if (m_bDisplayFramePos)
	    spos += sprintf(spos, " (%d)", player->GetFramePos());

	l_time->setText(timing);

	if (pbar)
	{
	    int prog;
            player->Get(player->QUERY_AVG_QUALITY, &prog, 0);
	    pbar->setProgress(prog);
	}
    }
}

void MyWidget::updatePos()
{
    if (!player)
	return;

    QPainter painter(this);

    double pos=player->GetPos();

    //if (pos > 40)
    //    quit_func();

    if (!is_tracking)
    {
        m_bSettingScroller = true;
	scroller->setValue((int)pos);
	m_bSettingScroller = false;
    }
    char dropstring[100];
#ifdef USE_SDL
    int w=384;
    //int h=50;
#else
    int w=width();
    int h=height();
#endif
    double percent;
    IAviPlayer::State state = player->GetState(&percent);

    switch(state)
    {
    case IAviPlayer::Invalid:
	strcpy(dropstring, "");
	break;
    case IAviPlayer::Opening:
	strcpy(dropstring, "Opening...");
	break;
    case IAviPlayer::Buffering:
	sprintf(dropstring, "Buffering: %d%%", int(100*percent));
	break;
    case IAviPlayer::Paused:
	strcpy(dropstring, "Paused");
	break;
    case IAviPlayer::Stopped:
	strcpy(dropstring, "Stopped");
	break;
    case IAviPlayer::Playing:
	{
	    int drop;
	    player->Get(player->QUERY_AVG_DROP, &drop, 0);
	    if (drop > 0)
		sprintf(dropstring, "Drop: %d%%", drop);
	    else
		strcpy(dropstring, "Playing...");
	}
	break;
    }

    l_status->setText(dropstring);

    if(w > 90 && is_tracking != 1)
    	updatePosDisplay((int)pos);
}

MyWidget::MyWidget(int width, int height)
{
    player = 0;
    popup = 0;
    about_popup = 0;
    resize_count = 1;
    is_tracking = 0;
    vollast = -1;
    _in_reseek = 0;
    m_bKeyProcessed = false;
    resize(width, height);

    QVBoxLayout* top_vbl = new QVBoxLayout(this, 0);
    top_vbl->setMargin(2);
    top_vbl->setSpacing(2);

    QGroupBox* line1_gb = new QGroupBox(this);
    //line1_gb->setBackgroundColor(QColor(0,255,255));
    line1_gb->setFrameStyle(QFrame::NoFrame);
    top_vbl->addWidget(line1_gb);

    QBoxLayout* line1_hbl = new QHBoxLayout(line1_gb, 0);
    line1_hbl->setSpacing(4);

    QHBox* controls_gb = new QHBox(line1_gb);
    controls_gb->setFrameStyle(QFrame::NoFrame);
    line1_hbl->addWidget(controls_gb);

    b_open = new PixmapButton("open", "", controls_gb);
    b_pause = new PixmapButton("pause", "", controls_gb);
    b_play = new PixmapButton("play", "", controls_gb);
    b_stop = new PixmapButton("stop", "", controls_gb);

    scroller=new QSlider(line1_gb, "Slider1");
    scroller->setOrientation(QSlider::Horizontal);
    scroller->setTickmarks(QSlider::Both);
    scroller->setMaximumHeight(18);
    scroller->setMinValue(0);
    scroller->setMaxValue(120);
    scroller->setLineStep(10);

    line1_hbl->addWidget(scroller);

    b_about=new PixmapButton("about", "", line1_gb);
    line1_hbl->addWidget(b_about);

    // Here we can set an icon for the application.
    // Does anyone know how to draw an AVI player? :) No? Well,
    // then let's leave this for a while.

    QPixmap pm;
    pm.load(SHARE_PATH"/test.png");
    setIcon(pm);

    QGroupBox* line2_gb = new QGroupBox(this);
    line2_gb->setFrameStyle(QFrame::NoFrame);
    //line2_gb->setBackgroundColor(QColor(0,255,255));
    top_vbl->addWidget(line2_gb);


    QBoxLayout* line2_hbl = new QHBoxLayout(line2_gb, 0);
    line2_hbl->setSpacing(4);

    b_opensub = new PixmapButton("open", "", line2_gb);
    line2_hbl->addWidget(b_opensub);

    b_mute = new PixmapButton("mute", "", line2_gb);
    line2_hbl->addWidget(b_mute);

    vbar=new QSlider(line2_gb, "SliderVolume");
    vbar->setOrientation(QSlider::Horizontal);
    vbar->setMinValue(0);
    vbar->setMaxValue(MAX_VBAR);
    vbar->setPageStep(5);
    vbar->setMaximumHeight(15);
    vbar->setMaximumWidth(80);
    vbar->setValue(MAX_VBAR);
    //vbar->setTickmarks(QSlider::Above);
    line2_hbl->addWidget(vbar);

    pbar = new QProgressBar(line2_gb);
    pbar->setTotalSteps(100);
    pbar->setMaximumHeight(15);
    pbar->setMaximumWidth(50);
    pbar->setProgress(0);
    line2_hbl->addWidget(pbar);

    l_status=new QLabel(line2_gb, "LabelDrop");
    line2_hbl->addWidget(l_status);
    line2_hbl->addStretch(100);

    l_time=new QLabel(line2_gb, "LabelTime");
    line2_hbl->addWidget(l_time);

    connect(scroller, SIGNAL(sliderReleased()), this, SLOT(reseek_func()));
    connect(scroller, SIGNAL(sliderPressed()), this, SLOT(slider_func()));
    connect(scroller, SIGNAL(sliderMoved(int)), this, SLOT(moved_func(int)));
    connect(scroller, SIGNAL(valueChanged(int)), this, SLOT(changed_func(int)));

    //connect(scroller, SIGNAL(sliderPressed()), this, SLOT(slider_func()));
    //connect(scroller, SIGNAL(sliderMoved(int)), this, SLOT(moved_func(int)));
    connect(vbar, SIGNAL(valueChanged(int)), this, SLOT(volume_func(int)));

    connect(b_pause, SIGNAL(clicked()), this, SLOT(pause_func()));
    connect(b_open, SIGNAL(clicked()), this, SLOT(open_func()));
    connect(b_stop, SIGNAL(clicked()), this, SLOT(stop_func()));
    connect(b_play, SIGNAL(clicked()), this, SLOT(play_func()));
    connect(b_about, SIGNAL(clicked()), this, SLOT(about_func()));
    connect(b_mute, SIGNAL(clicked()), this, SLOT(mute_func()));
    connect(b_opensub, SIGNAL(clicked()), this, SLOT(opensub_func()));

    _timer=new QTimer;
    _start_timer=new QTimer;
    QObject::connect(_timer, SIGNAL(timeout()), this, SLOT(updatePos()));
    QObject::connect(_start_timer, SIGNAL(timeout()),
		     this, SLOT(starter_slot()));

    pthread_mutex_init(&mutex, 0);
    /*
     const char *path = getenv("WIN32_PATH");
     if(path==0)
     path=WIN32_PATH;
     SetCodecPath(path);
     */
    setAcceptDrops(TRUE);
}

MyWidget::~MyWidget()
{
    delete player;
    delete popup;
    delete about_popup;
}

void MyWidget::help()
{
    QMessageBox::information(this, "AVI player usage", helptxt);
}

void MyWidget::about()
{
    char s[1024];
    sprintf(s, abouttxt, AVIFILE_VERSION);
    QMessageBox::information(this, "About", s);
}

void MyWidget::dropEvent(QDropEvent* e)
{
    QStrList i;
    QUriDrag::decode(e, i);
    const char* uri=i.first();

    if (!uri || strlen(uri) < 6)
	return;

    QString file;

    if (0 == qstrnicmp(uri,"file:/",6) )
    {
	uri += 6;
	if ( uri[0] != '/' || uri[1] == '/' )
	{
	    // It is local.
	    file = QUriDrag::uriToUnicodeUri(uri);
	    if ( (uri[1] == '/') && (uri[0]=='/') )
		file.remove(0,1);
	    else
		file.insert(0,'/');
	    try
	    {
		cerr<<file.ascii()<<endl;
		AviPlayerInitParams ip;
                ip.filename = file.ascii();
		initPlayer(ip);
	    }
	    catch(...)
	    {
	    }
	}
    }
}

void MyWidget::dragEnterEvent(QDragEnterEvent* event)
{
    event->accept(QUriDrag::canDecode(event));
}

void MyWidget::moved_func(int value)
{
    updatePosDisplay(value);
}
