/***********************************************************************
 * VirtualDub Modification for OGM
 *
 * Copyright (C) 2002 Cyrius
 *
 * 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 (see the file COPYING); if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * or visit http://www.gnu.org/copyleft/gpl.html
 *
 ***********************************************************************
 *
 *
 *
 */

#include <windows.h>
#include <commctrl.h>
#include <crtdbg.h>
#include <vfw.h>

#include "../resource.h"
#include "../gui.h"
#include "../audio.h"

#include "../AudioSource.h"
#include "../VideoSource.h"
#include "../InputFile.h"

#include "OGMDubStatus.h"

extern HWND g_hWnd;

///////////////////////////////////////////////////////////////////////////

IDubStatusHandler *CreateOGMDubStatusHandler(ogm_stream *ogm_streams) {
	return new OGMDubStatus(ogm_streams);
}

///////////////////////////////////////////////////////////////////////////

extern char g_szInputAVIFileTitle[];
extern HINSTANCE g_hInst;
extern HWND g_hWnd;

///////////////////////////////////////////////////////////////////////////

OGMDubStatus::OGMDubStatus(ogm_stream *ogm_streams)
: DubStatus() {
	this->ogm_streams = ogm_streams;
}

void OGMDubStatus::StatusTimerProc(HWND hWnd) {
	DWORD dwProgress;
	__int64 lProjSize;
	char buf[256];

	LONG	totalVSamples	= pvinfo->end_src - pvinfo->start_src;
//	LONG	totalASamples	= painfo->end_src - painfo->start_src;
	LONG	totalASamples	= audioStreamSource ? audioStreamSource->GetLength() : 0;
	LONG	totalA2Samples	= audio2StreamSource ? audio2StreamSource->GetLength() : 0;
	LONG	curVSample		= pvinfo->cur_proc_src - pvinfo->start_src;
	LONG	curASample		= audioStreamSource ? audioStreamSource->GetSampleCount() : 0;
	LONG	curA2Sample		= audio2StreamSource ? audio2StreamSource->GetSampleCount() : 0;
	char	*s;
	bool	bPreloading = false;

	/////////////

	curVSample -= opt->video.frameRateDecimation * pvinfo->nLag;

	if (curVSample<0) {
		curVSample = 0;
		bPreloading = true;
	}

	dwProgress = (curVSample>totalVSamples ? 4096 : MulDiv(curVSample, 4096, totalVSamples))
				+(curASample>totalASamples ? 4096 : MulDiv(curASample, 4096, totalASamples))
				+(curA2Sample>totalA2Samples ? 4096 : MulDiv(curA2Sample, 4096, totalA2Samples));

	//if (!totalASamples || !totalVSamples || pvinfo->fAudioOnly) dwProgress *= 2;
	dwProgress *= 3;
	dwProgress /= (totalASamples?1:0) + (totalA2Samples?1:0) + (totalVSamples?1:0);

	dwLastTicks2 = dwLastTicks1;
	dwLastTicks1 = dwTicks;
	dwTicks = GetTickCount() - dwStartTime;

	if (bPreloading) {
		SetDlgItemText(hWnd, IDC_CURRENT_VFRAME, "Preloading...");
	} else {
		wsprintf(buf, "%ld/%ld", curVSample, totalVSamples);
		SetDlgItemText(hWnd, IDC_CURRENT_VFRAME, buf);
	}

	wsprintf(buf, "%ld/%ld", curASample, totalASamples);
	SetDlgItemText(hWnd, IDC_CURRENT_ASAMPLE, buf);
 
	wsprintf(buf, "%ld/%ld", curA2Sample, totalA2Samples);
	SetDlgItemText(hWnd, IDC_CURRENT_ASAMPLE2, buf);
 
	//size_to_str(buf, pvinfo->total_size);
	// Ogg Page ~4kB
	// Page = 27 bytes + n (nb segments) bytes for header
	// total_size / nb_processed = bytes per frame (1 frame = 1 Packet)
	// bytes_per_frame / 255 + 1 = nb of segments per Packet
	// total_size / 4096 ~ nb of Pages processed so far
	__int64 video_size = pvinfo->total_size;
	video_size += pvinfo->processed + (video_size / (__int64)255) + (video_size / (__int64)4096) * (__int64)27;
	size_to_str(buf, video_size);

	if (pvinfo->processed) {
		__int64 divisor = pvinfo->processed*(__int64)pvinfo->usPerFrame;

		s=buf; while(*s) ++s;
		wsprintf(s, " (%3ldKB/s)", (long)((((pvinfo->total_size+1023)/1024)*1000000i64 + divisor - 1) / divisor));
	}

	SetDlgItemText(hWnd, IDC_CURRENT_VSIZE, buf);

	lProjSize = 0;

	// For audio streams, number of segments is already taken into account
	__int64 audio_size = painfo->total_size + (painfo->total_size / (__int64)4096) * (__int64)27;
	if (totalASamples && curASample) {
		__int64 divisor = (__int64)min(totalASamples, curASample);// * wf->nSamplesPerSec;

		//lProjSize += ((__int64)painfo->total_size * 
		//				(__int64)totalASamples + divisor/2) / divisor;
		lProjSize += (audio_size * 
						(__int64)totalASamples + divisor/2) / divisor;
	}
	//size_to_str(buf, painfo->total_size);
	size_to_str(buf, audio_size);
	SetDlgItemText(hWnd, IDC_CURRENT_ASIZE, buf);
	audio_size = pa2info->total_size + (pa2info->total_size / (__int64)4096) * (__int64)27;
	if (totalA2Samples && curA2Sample) {
		__int64 divisor = (__int64)min(totalA2Samples, curA2Sample);// * wf->nSamplesPerSec;

		//lProjSize += ((__int64)pa2info->total_size * 
		//				(__int64)totalA2Samples + divisor/2) / divisor;
		lProjSize += (audio_size * 
						(__int64)totalA2Samples + divisor/2) / divisor;
	}
	ogm_stream *stream = ogm_streams;
	LONG t_a_samples = 0;
	LONG c_a_sample = 0;
	__int64 a_size = 0;
	while(stream) {
		a_size = stream->aInfo.total_size + (stream->aInfo.total_size / (__int64)4096) * (__int64)27;
		audio_size += a_size;
		// the audioStream may not have been created yet
		if(stream->audioStream && (t_a_samples=stream->audioStream->GetLength()) && (c_a_sample=stream->audioStream->GetSampleCount())) {
			__int64 divisor = (__int64)min(t_a_samples, c_a_sample);// * wf->nSamplesPerSec;

			lProjSize += (a_size * 
							(__int64)t_a_samples + divisor/2) / divisor;
		}
		stream = stream->next;
	}
	size_to_str(buf, audio_size);
	SetDlgItemText(hWnd, IDC_CURRENT_ASIZE, buf);

	if (totalVSamples && curVSample) {
		long divisor = min(totalVSamples, curVSample);

		//lProjSize += ((__int64)pvinfo->total_size * totalVSamples + divisor/2) / divisor;
		lProjSize += (video_size * totalVSamples + divisor/2) / divisor;
	}

	if (lProjSize) {
		//lProjSize += 2048 + 16;

		__int64 kilobytes = (lProjSize+1023)>>10;

		if (kilobytes < 65536)
			wsprintf(buf, "%ldK", kilobytes);
		else {
			kilobytes = (lProjSize*100) / 1048576;
			wsprintf(buf, "%ld.%02dMB", (LONG)(kilobytes/100), (LONG)(kilobytes%100));
		}
		SetDlgItemText(hWnd, IDC_PROJECTED_FSIZE, buf);
	} else {
		SetDlgItemText(hWnd, IDC_PROJECTED_FSIZE, "unknown");
	}

	ticks_to_str(buf, dwTicks);
	SetDlgItemText(hWnd, IDC_TIME_ELAPSED, buf);

	if (dwProgress > 16) {
		ticks_to_str(buf, MulDiv(dwTicks,12288/*8192*/,dwProgress));
		SetDlgItemText(hWnd, IDC_TIME_REMAINING, buf);
	}

	lFrameDiff2 = lFrameDiff1;
	lFrameDiff1 = pvinfo->processed-lastFrame;
	lastFrame += lFrameDiff1;

	{
		long fps10;

		fps10 = MulDiv(lFrameDiff1 + lFrameDiff2, 10000, dwTicks - dwLastTicks2);

		wsprintf(buf, "%ld.%c fps",fps10/10, (fps10%10) + '0');
		SetDlgItemText(hWnd, IDC_FPS, buf);
	}

	if (GetWindowLong(g_hWnd, GWL_STYLE) & WS_MINIMIZE) {
		long lNewProgress = (dwProgress*25)/(3072)/*2048*/;

		if (iLastTitleMode != TITLE_MINIMIZED || lLastTitleProgress != lNewProgress) {
			guiSetTitle(g_hWnd, IDS_TITLE_DUBBING_MINIMIZED, lNewProgress, g_szInputAVIFileTitle);

			iLastTitleMode = TITLE_MINIMIZED;
			lLastTitleProgress = lNewProgress;
		}
	} else {
		if (iLastTitleMode != TITLE_NORMAL) {
			iLastTitleMode = TITLE_NORMAL;
			guiSetTitle(g_hWnd, IDS_TITLE_DUBBING, g_szInputAVIFileTitle);
		}
	}
}
