
#include <fourcc.h>
#include <cpuinfo.h>
#include <configfile.h>
#include <playerwidget.h>
#include "aviplay2.h"
#include "RegAccess.h"
#include <iostream>

using namespace std;
#define __MODULE__ "AviPlayer2"

AviPlayer2::AviPlayer2(PlayerWidget* pw, Display* _dpy,
		       const char* filename, const char* subname) throw(FatalError)
    : AviPlayer(filename, GetPhysicalDepth(_dpy), subname),
    m_pParent(pw), m_pDpy(_dpy), m_iResizeCount(1)
{
    if (!GetVideoLengthTime())
	return;
    m_pKillhandler = killHandler;
    m_pKillhandlerArg = (void*)this;

    if (!m_pParent)
	m_pParent = this;

    bool useyuv;
    Get(USE_YUV, &useyuv, 0);
    CreateVideoRenderer(useyuv);
}

AviPlayer2::~AviPlayer2()
{
    m_pKillhandler = 0; // no longer VALID !!!
}

int AviPlayer2::Refresh()
{
    for (unsigned i = 0; i < m_VideoRenderers.size(); i++)
	m_VideoRenderers[i]->Refresh();
    return 0;
}

// should be redesigned - only first one will get resize event for now
int AviPlayer2::Resize(int& new_w, int& new_h)
{
    if (m_VideoRenderers.size() > 0)
    {
	int pres;
        Get(VIDEO_PRESERVE_ASPECT, &pres, 0);
	if (pres)
	{
	    double ratio = GetWidth() / (double) GetHeight();
	    //cout << "W " << GetWidth() << " H " << GetHeight() << "  ratio: " << ratio << endl;
	    new_h = int(new_w / ratio + 0.5);
	}
	return m_VideoRenderers[0]->Resize(new_w, new_h);
    }
    return 0;
}

int AviPlayer2::setUseYUV(bool useyuv)
{
    bool useyuvold;
    Get(USE_YUV, &useyuvold, 0);
    if (m_pVideostream && useyuvold != useyuv)
    {
    	bool pl = IsPlaying();
	if (pl)
	    lockThreads("setUseYUV");
        double pos = GetPos();
	m_pVideostream->StopStreaming();
	m_pVideostream->StartStreaming();
	//cout << "YUV change detected" << endl;
	CreateVideoRenderer(useyuv);

	double posn = m_pVideostream->SeekTimeToKeyFrame(pos);
        if (m_pAudiostream && posn + 5 < pos)
	    Reseek(posn); // complet reseek
	if (pl)
	    unlockThreads();
    }
    return 0;
}

int AviPlayer2::setFont(const char* fn)
{
    for (unsigned i = 0; i < m_VideoRenderers.size(); i++)
    {
	m_VideoRenderers[i]->SetFont(fn);
    }
    return 0;
}


int AviPlayer2::ToggleFullscreen(bool maximize)
{
    if (m_VideoRenderers.size() > 0)
	return m_VideoRenderers[0]->ToggleFullscreen(maximize);
    return 0;
}

void AviPlayer2::UpdateResize()
{
    int w, h;
    switch(m_iResizeCount % 3)
    {
    case 0:
	w=GetWidth()/2; h=GetHeight()/2;
	break;
    case 1:
	w=GetWidth(); h=GetHeight();
	break;
    case 2:
	w=GetWidth()*2; h=GetHeight()*2;
	break;
    }
    Resize(w, h);
}

void AviPlayer2::CreateVideoRenderer(bool useyuv)
{
    while (m_VideoRenderers.size() > 0)
    {
	VideoRenderer* vr = m_VideoRenderers.back();
	m_VideoRenderers.pop_back();
	delete vr;
    }

#ifndef WITHOUT_X
    if (m_pDpy)
    {
	bool sub = HasSubtitles();

	/* this exotic construction is a workaround for 'internal compiler error' when compiling with egcs 2.91.66 */
	m_VideoRenderers.push_back(0);
	VideoRenderer*& renderer = m_VideoRenderers.back();
        // so users should really upgrade their ancient c++ compilers...

	if (useyuv && !renderer)
	{
            // checking for YUY2 first - fastest!
	    static const unsigned long tryFcc[] = { fccYUY2, fccYV12, fccUYVY, fccYUY2, 0 };
	    static const char* tryFccS[] = { "YUY2", "YV12", "UYVY",  "YUY2 forced" };
	    int i = 0;

	    while (!renderer && tryFcc[i])
	    {
		try
		{
		    // we always allow to use last entry when HW acceleration
		    // is requested - it is giving hw scalable picture
		    if (!tryFcc[i + 1] ||  SetColorSpace(tryFcc[i], true) == 0) {
			renderer = CreateYUVRenderer(m_pParent, m_pDpy, GetWidth(), GetHeight(), tryFcc[i], sub);
			if (tryFcc[i] )
			{
			    if (tryFcc[i + 1] && SetColorSpace(tryFcc[i], false)) //shouldn't happen
				throw FATAL("Error setting YUV decoder output");

			    m_pVideostream->GetDecoder()->SetDestFmt(BitmapInfo::BitCount(tryFcc[i]),
								     tryFcc[i]);
			}
			//cerr << tryFccS[i] << " format supported by decoder" << endl;
		    }
		}
		catch(FatalError& e)
		{
		    e.PrintAll();
		    delete renderer;
		    renderer=0;
		}
		i++;
	    }
	}

	if (!renderer)
	{
	    renderer = CreateFullscreenRenderer(m_pParent, m_pDpy, GetWidth(), GetHeight(), sub);
	    int result = m_pVideostream->GetDecoder()->SetDestFmt(m_iDepth);
	    //cout << "SHOULD SET " << endl;
	    //m_pVideostream->GetDecoder()->SetDestFmt(BitmapInfo::BitCount(tryFcc[i]),
	    //    				     tryFcc[i]);
	}

	if (renderer)
	{
	    char* fs;
	    Get(SUBTITLE_FONT, &fs, 0);
	    if (fs)
	    {
                renderer->SetFont(fs);
                free(fs);
	    }
	}

    }
#endif

    bool vbuffer = m_bVideoBuffered;
    bool vdirect = m_bVideoDirect;

    if (vbuffer)
    {
	m_bVideoBuffered = false;
	// never fill directly variable which have side effect
	// like the following two memeber
	setVideoBuffered(vbuffer);
    }
    if (vdirect)
    {
        m_bVideoDirect = false;
	setVideoDirect(vdirect);
    }
}


void AviPlayer2::PW_showconf_func()
{
} //double-click

void AviPlayer2::PW_stop_func()
{
    Stop();
} //'x'

void AviPlayer2::PW_pause_func()
{
    Pause(true);
}//'c'

void AviPlayer2::PW_play_func()
{
    if (!IsPlaying())
	Start();
    else
	Pause(false);
} //'v'

void AviPlayer2::PW_quit_func()
{
} //'q'

void AviPlayer2::PW_menu_slot()
{
} //right-click

void AviPlayer2::PW_key_func(int sym, int mod)
{
} //key-func

void AviPlayer2::PW_middle_button()
{
    m_iResizeCount++;
    UpdateResize();
}

void AviPlayer2::PW_fullscreen()
{
    ToggleFullscreen();
} //alt+enter, esc

void AviPlayer2::PW_maximize_func()
{
    ToggleFullscreen(true);
} //maximalize

void AviPlayer2::PW_resize(int w, int h)
{
    Resize(w,h);
} //mouse resize

void AviPlayer2::PW_refresh()
{
    Refresh();
}//mouse resize

void AviPlayer2::killHandler(int, void*)
{
}

IAviPlayer2* CreateAviPlayer2(PlayerWidget* parent, Display* dpy,
			      const char* filename, const char* subname) throw(FatalError)
{
    AviPlayer2* p = new AviPlayer2(parent, dpy, filename, subname);
    p->UpdateResize();
    return p;
}
