#pragma once

#include <cassert>
#include <vector>

#include "OpenCVTextureSetter.h"


namespace lib_gl
{


//! OpenCV依存のビデオテクスチャクラス
class CvVideoTexture
{
public:
	CvVideoTexture(void);
	virtual ~CvVideoTexture(void);

	bool OpenFile( const char* filename );
	bool OpenWebcamera(void);

	void Release(void);

	bool LoadNextFrame( void );
	bool SetGLLastFrame( TEXTURE_MODE tex_mode = TEXTURE_NORMAL );
	bool SetGLNextFrame( TEXTURE_MODE tex_mode = TEXTURE_NORMAL );


	bool IsFromVideoFile(void) const;
	bool IsFromWebcamera(void) const;

	bool IsValid(void) const;
	bool IsLastFrame(void) const;

	double GetNextFrameTime(void) const;
	void   SetNextFrameTime(double i_time);

	double GetNextFrameIndex(void) const;
	void   SetNextFrameIndex(double i_index);

	double GetNextNormalizedFramePos(void) const;
	void   SetNextNormalizedFramePos(double i_pos);

	double GetWidth  (void) const;
	double GetHeight (void) const;

	double GetFPS(void) const;
	double GetInterval(void) const;

	double GetFrameCount(void) const;


	const CvCapture* GetCapture   (void) const { return m_Capture;   }
	const IplImage*  GetLastFrame (void) const { return m_LastFrame; }


private:
	double GetProperty( int i_propertyId ) const;
	void   SetProperty( int i_propertyId , double i_value );


private:
	CvCapture*   m_Capture;
	IplImage*    m_LastFrame;

	bool         m_VideoFileOpened;
	bool         m_WebcameraOpened;
};



inline CvVideoTexture::CvVideoTexture(void)
{
	m_Capture = NULL;
	m_LastFrame   = NULL;

	m_VideoFileOpened = false;
	m_WebcameraOpened = false;
}

inline CvVideoTexture::~CvVideoTexture(void)
{
	Release();
}


//! 動画ファイルを開く
inline bool CvVideoTexture::OpenFile( const char* filename )
{
	// 一旦閉じないと他のファイルは開かない.
	_ASSERTE( m_Capture == NULL );
	if( m_Capture != NULL )
		return false;

	m_Capture = cvCaptureFromFile( filename );
	if( m_Capture == NULL )
		return false;

	m_VideoFileOpened = true;
	return true;
}

//! Webカメラを開く
inline bool CvVideoTexture::OpenWebcamera(void)
{
	_ASSERTE( m_Capture == NULL );
	if( m_Capture != NULL )
		return false;

	m_Capture = cvCaptureFromCAM( CV_CAP_ANY );
	if( m_Capture == NULL )
		return false;

	m_WebcameraOpened = true;
	return true;
}


//! 動画を解放する.
inline void CvVideoTexture::Release(void)
{
	if( m_Capture != NULL )
	{
		cvReleaseCapture( &m_Capture );
		m_Capture    = NULL;
		m_LastFrame  = NULL;
	}

	m_VideoFileOpened = false;
	m_WebcameraOpened = false;
}


//! 次のフレームを取得する.
inline bool CvVideoTexture::LoadNextFrame( void )
{
	_ASSERTE( m_Capture != NULL );
	if( m_Capture == NULL )
		return false;

	m_LastFrame = cvQueryFrame( m_Capture );
	if( m_LastFrame == NULL )
		return false;

	return true;
}

//! 最後に読み込んだフレームをOpenGLのテクスチャにセットする.
inline bool CvVideoTexture::SetGLLastFrame( TEXTURE_MODE tex_mode )
{
	_ASSERTE( m_Capture != NULL );
	if( m_Capture == NULL || m_LastFrame == NULL )
		return false;

	return SetCVTexture( m_LastFrame , tex_mode );
}

//! 次のフレームを取得してOpenGLのテクスチャにセットする.
inline bool CvVideoTexture::SetGLNextFrame( TEXTURE_MODE tex_mode )
{
	_ASSERTE( m_Capture != NULL );
	if( m_Capture == NULL )
		return false;

	if( !LoadNextFrame() ) return false;
	if( !SetGLLastFrame( tex_mode ) ) return false;

	return true;
}


//! 現在開いている動画テクスチャが動画ファイルならtrueを返す.
inline bool CvVideoTexture::IsFromVideoFile(void) const
{
	if( !IsValid() )
		return false;

	return m_VideoFileOpened;
}

//! 現在開いている動画テクスチャがWebカメラならtrueを返す.
inline bool CvVideoTexture::IsFromWebcamera(void) const
{
	if( !IsValid() )
		return false;

	return m_WebcameraOpened;
}


//! ビデオが開かれているか確認する.
inline bool CvVideoTexture::IsValid(void) const
{
	return ( m_Capture != NULL );
}

//! 最後のフレームに到達したか確認する.
inline bool CvVideoTexture::IsLastFrame(void) const
{
	// TODO : シーク情報を正しく取得できない場合がある.

	// なぜか最大インデックス = フレーム数-2 となっているので下記条件になる.
	return ( GetFrameCount() - GetNextFrameIndex() <= 2 );
}

	
//! 次のフレームの時間を求める.
inline double CvVideoTexture::GetNextFrameTime(void) const
{
	return GetProperty( CV_CAP_PROP_POS_MSEC );
}

inline void CvVideoTexture::SetNextFrameTime(double i_time)
{
	SetProperty( CV_CAP_PROP_POS_MSEC , i_time );
}

//! 次のフレームのインデックスを求める.
inline double CvVideoTexture::GetNextFrameIndex(void) const
{
	return GetProperty( CV_CAP_PROP_POS_FRAMES );
}

inline void CvVideoTexture::SetNextFrameIndex(double i_index)
{
	SetProperty( CV_CAP_PROP_POS_FRAMES , i_index );
}

//! 次のフレームのビデオ内での正規化位置(0〜1)を求める.
inline double CvVideoTexture::GetNextNormalizedFramePos(void) const
{
	return GetProperty( CV_CAP_PROP_POS_AVI_RATIO );
}

inline void CvVideoTexture::SetNextNormalizedFramePos(double i_pos)
{
	SetProperty( CV_CAP_PROP_POS_AVI_RATIO , i_pos );
}

//! ビデオの横幅を取得する.
inline double CvVideoTexture::GetWidth(void) const
{
	return GetProperty( CV_CAP_PROP_FRAME_WIDTH );
}

//! ビデオの縦幅を取得する.
inline double CvVideoTexture::GetHeight(void) const
{
	return GetProperty( CV_CAP_PROP_FRAME_HEIGHT );
}

//! FPSを取得する.
inline double CvVideoTexture::GetFPS(void) const
{
	return GetProperty( CV_CAP_PROP_FPS );
}

//! フレーム間のインターバル(==FPSの逆数) を取得する.
inline double CvVideoTexture::GetInterval(void) const
{
	double fps = GetFPS();
	if( fps <= 0.0 )
		return 0.0;
	
	return 1000.0 / fps;
}

//! 総フレーム数を取得する.
inline double CvVideoTexture::GetFrameCount(void) const
{
	return GetProperty( CV_CAP_PROP_FRAME_COUNT );
}


inline double CvVideoTexture::GetProperty( int i_propertyId ) const
{
	_ASSERTE( m_Capture != NULL );
	if( m_Capture == NULL )
		return 0;

	return cvGetCaptureProperty( m_Capture , i_propertyId );
}

inline void CvVideoTexture::SetProperty( int i_propertyId , double i_value )
{
	_ASSERTE( m_Capture != NULL );
	if( m_Capture == NULL )
		return;

	cvSetCaptureProperty( m_Capture , i_propertyId , i_value );
}


}
