#include <stdio.h>
#include "avicapwnd.h"
#include "v4lwindow.h"
#include <except.h>
#include "capproc.h"
#include "ccap.h"
#include <qpushbutton.h>
#include <qlabel.h>
#include <qtabwidget.h>
#include <qtimer.h>
#include <qframe.h>
#include <qpainter.h>
#include <qmessagebox.h>
#include <default.h>
#include "cpuinfo.h"
#include <fourcc.h>
#include "vidcapreg.h"
#include <math.h>

using namespace std;

/*
 *  Constructs a AviCapDialog which is a child of 'parent', with the 
 *  name 'name' and widget flags set to 'f' 
 */
AviCapDialog::AviCapDialog( V4LWindow* pWnd )
    : AviCapDlg( 0 ),
    m_pWnd(pWnd), m_pProgress(0), m_bStarted(false)
{
    connect(CloseButton, SIGNAL(clicked()), this, SLOT(close()));
    connect(StartButton, SIGNAL(clicked()), this, SLOT(start()));
    connect(SegmentButton, SIGNAL(clicked()), this, SLOT(segment()));
    SegmentButton->setEnabled(false);
    ProgressText->setText("Press START to begin capturing"); 
    m_pTimer=new QTimer;
    m_pCapproc=0;
    m_pCC=pWnd->getcc();
    if(m_pCC)
	m_pCC->addref();
}

void AviCapDialog::start()
{
    disconnect(StartButton, SIGNAL(clicked()), this, SLOT(start()));
    connect(StartButton, SIGNAL(clicked()), this, SLOT(stop()));
    StartButton->setText("Stop");
    connect(m_pTimer, SIGNAL(timeout()), this, SLOT(updateGraphs()));
    m_pTimer->start(500);
    try
    {
	CaptureConfig conf;
	conf.load();
	m_pCapproc = new CaptureProcess(m_pWnd->m_pDev, &conf, m_pCC);
    }
    catch(FatalError& e)
    {
	QMessageBox::critical(this, "Error", e.GetDesc());
	m_pCapproc = 0;
    }
    if (RI("IsSegmented", 1))
	SegmentButton->setEnabled(true);
    m_pProgress=new CaptureProgress;
    m_pCapproc->setMessenger(m_pProgress);
    m_bStarted=true;
}

void AviCapDialog::segment()
{
    if(m_pCapproc)
	m_pCapproc->segment();
}

void AviCapDialog::stop()
{
    m_pTimer->stop();
    m_bStarted=false;
    delete m_pCapproc;
    delete m_pProgress;
    m_pCapproc=0;
    m_pProgress=0;
    disconnect(StartButton, SIGNAL(clicked()), this, SLOT(stop()));
    connect(StartButton, SIGNAL(clicked()), this, SLOT(start()));
    SegmentButton->setEnabled(false);
    StartButton->setText("Start");
}

void AviCapDialog::updateGraphs()
{
    char s[1024];
    static int call=0;
    QPainter* qp;
    int iHeight;
    int iWidth;
    int iMaxFrame=0;
    int i;
    call+=10;
    m_pProgress->lock();
    sprintf(s,
    "Capturing into file:\n %s\n"
    "Video frame rate: %.2f frames/s\n"
    "Video resolution: %dx%d\n",
    m_pProgress->filename, 
    m_pProgress->framerate, 
    m_pProgress->xdim, m_pProgress->ydim);
    
    if(m_pProgress->audio_freq)
	sprintf(s+strlen(s),
	"Audio: %d Hz, %d bit, %s\n",
	m_pProgress->audio_freq, m_pProgress->audio_ssize, (m_pProgress->audio_channels==1)?"mono":"stereo");
    else
	sprintf(s+strlen(s), "No audio\n");	    
        
    sprintf(s+strlen(s),
    "\n\n"
    "Elapsed: %f s\n"
    "Written video: \n"
    "   %Ld Kb\n"
    "   %d frames\n"
    "   %f s\n"
    "Written audio: \n"
    "  %Ld Kb\n"
    "  %f s\n"
    "Synch fix: %d frames\n"
    "File size: %Ld Kb\n"
    "Frame drop in capture thread: %d frames\n"
    "Frame drop in encoder: %d frames\n"
    "Capture buffer usage: %d %%\n",
    m_pProgress->enc_time/freq/1000., 
    m_pProgress->video_bytes/1024, m_pProgress->video_frames, m_pProgress->video_time,
    m_pProgress->audio_bytes/1024, m_pProgress->audio_time,
    m_pProgress->synch_fix,
    m_pProgress->file_size/1024,
    m_pProgress->dropped_cap,
    m_pProgress->dropped_enc,
    int(100.*m_pProgress->buffer_occupancies[(m_pProgress->buffer_head+m_pProgress->history_size-1)%m_pProgress->history_size]/m_pProgress->max_frames)
    );
    ProgressText->setText(s);
    if(CaptureTab->currentPageIndex()!=1)
	goto finish;
    qp=new QPainter(Frame3_2);
    iHeight=Frame3_2->height();
    iWidth=Frame3_2->width();
    for(i=0; i<m_pProgress->video_frame_len; i++)
    {
	int index = m_pProgress->video_frame_head - i - 1;
	while(index<0)
	    index += m_pProgress->history_size;
	index %= m_pProgress->history_size;
	if((m_pProgress->video_frame_sizes[index] & ~0x40000000)>iMaxFrame)
	    iMaxFrame=m_pProgress->video_frame_sizes[index];
    }
    if(iMaxFrame<10)
	iMaxFrame=10;
    else if(iMaxFrame<100)
	iMaxFrame=100;
    else if(iMaxFrame<1000)
	iMaxFrame=1000;
    else if(iMaxFrame<10000)
	iMaxFrame=10000;
    else if(iMaxFrame<100000)
	iMaxFrame=100000;
    else iMaxFrame=1000000;
    if(iMaxFrame<1000)
	sprintf(s, "%d bytes", iMaxFrame);
    else if(iMaxFrame<1000000)
	sprintf(s, "%d kb", iMaxFrame/1000);
    else
	sprintf(s, "%d mb", iMaxFrame/1000000);
    MaxFrameSizeText->setText(s);
    for(i=iWidth; i>=0; i--)
    {
	int index = i-iWidth;
	if(index<-m_pProgress->video_frame_len)
	{
	    qp->setPen(QColor(0,0,0));
	    qp->moveTo(i, iHeight);
	    qp->lineTo(i, 0);
	    continue;
	}
	index += m_pProgress->video_frame_head;
	while(index<0)
	    index += m_pProgress->history_size;
	index %= m_pProgress->history_size;
	float t=(m_pProgress->video_frame_sizes[index] & ~0x40000000)/(float)iMaxFrame;
	if(t>1)t=1;
	if(m_pProgress->video_frame_sizes[index] & 0x40000000)
	    qp->setPen(QColor(255, 0, 0));
	else
	    qp->setPen(QColor(0, 255, 0));
	qp->moveTo(i, iHeight);
	qp->lineTo(i, iHeight*(1-t));
	if(t<1)
	{
	    qp->setPen(QColor(0, 0, 0));
	    qp->lineTo(i, 0);
	}
    }
    delete qp;
    qp=new QPainter(Frame3);
    iHeight=Frame3->height();
    iWidth=Frame3->width();
    for(i=0; i<iWidth; i++)
    {
	int index = i-iWidth;
	if(index<-m_pProgress->buffer_len)
	{
	    qp->setPen(QColor(0,0,0));
	    qp->moveTo(i, iHeight);
	    qp->lineTo(i, 0);
	    continue;
	}
	index += m_pProgress->buffer_head;
	while(index<0)
	    index += m_pProgress->history_size;
	index %= m_pProgress->history_size;
	float t=m_pProgress->buffer_occupancies[index]/(double)m_pProgress->max_frames;
	if(t>1)t=1;
	qp->setPen(QColor(0, 255, 0));
	qp->moveTo(i, iHeight);
	qp->lineTo(i, iHeight*(1-t));
	if(t<1)
	{
	    qp->setPen(QColor(0, 0, 0));
	    qp->lineTo(i, 0);
	}
    }
    delete qp;
finish:
    m_pProgress->unlock();
    int finished;
    std::string error;
    m_pCapproc->getState(finished, error);
    if(finished)
    {
	printf("Finished\n");
	stop();
	if(error.size())
	    QMessageBox::critical(this, "Error", error.c_str());
    }
}

bool AviCapDialog::close()
{
    m_pWnd->unregisterCapDialog();
    // no need to delete child widgets, Qt does it all for us
    if(m_bStarted)
	stop();
    delete m_pTimer;
    delete m_pCapproc;
    delete m_pProgress;
    if(m_pCC)
	m_pCC->release();
    return QWidget::close();
}

/*  
 *  Destroys the object and frees any allocated resources
 */
AviCapDialog::~AviCapDialog()
{
}

#include "avicapwnd_p.moc"
#include "avicapwnd.moc"
