/*-----------------------------------------------------------------------------
[名称]	ShitarabianPlugInWall.cpp
[概要]	したらびあんプラグイン壁紙クラスの実装
[備考]	なし
[履歴]	2003-01-25	NC		コメント付加(moralog)
-----------------------------------------------------------------------------*/

//-----------------------------------------------------------------------------
// インクルード
//-----------------------------------------------------------------------------
#include "stdafx.h"
#include "shitarabian.h"
#include "ShitarabianPlugInWall.h"
#include "EditDrawer.h"
#include "Common.h"
#include "ExeCommon.h"
#include "PlugInWallDlg.h"
#include "HiddenDecoder.h"
#include "DocumentIF.h"
#include "SettingPath.h"

#define IMGCTL_RUNTIME
#include "imgctl.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//-----------------------------------------------------------------------------
// ファイル内変数
//-----------------------------------------------------------------------------
// please! こらこら、メンバに持てよ
static CPlugInWallDlg	f_Walldlg;		// 壁紙設定ダイアログ [-] (-)
static CBitmap			bmpWall;		// 表示用ビットマップデータ [整形済] (-)

HMODULE			m_hImgctl = NULL;		// imgctrlハンドラ [-] (-)
BOOL			m_bWallEnable = FALSE;	// 壁紙機能有効フラグ [-] (TRUE:有効、FALSE:無効)
static BOOL		bInitialine = FALSE;	// 初期化フラグ [-] (TRUE:初期済み、FALSE:未初期化)
static UINT		m_uiGray = 0;			// グレー度 [-] (0〜255)
static int		m_iRed = 0;				// 赤輝度 [-] (0〜255)
static int		m_iGreen = 0;			// 緑輝度 [-] (0〜255)
static int		m_iBlue = 0;			// 青輝度 [-] (0〜255)

static int		m_iOffsetX = 0;			// X軸オフセット [pixel] (-)
static int		m_iOffsetY = 0;			// Y軸オフセット [pixel] (-)
static BOOL		m_bResize = FALSE;		// リサイズ要求 [-] (TRUE:リサイズする、FALSE:リサイズしない)
static int		m_iSizeX = 0;			// 画像指定幅 [pixel] (-)
static int		m_iSizeY = 0;			// 画像指定高さ [pixel] (-)


/*-----------------------------------------------------------------------------
[名称]	コンストラクタ
[機能]	インスタンスの生成。
[戻値]	なし
[備考]	imgctrlをロードする。
-----------------------------------------------------------------------------*/
CShitarabianPlugInWall::CShitarabianPlugInWall()
{
	m_hImgctl = LoadLibrary( "imgctl.dll" );
}


/*-----------------------------------------------------------------------------
[名称]	デストラクタ
[機能]	インスタンスの破棄。
[戻値]	なし
[備考]	imgctrlの解放。
-----------------------------------------------------------------------------*/
CShitarabianPlugInWall::~CShitarabianPlugInWall()
{
	CloseImage();

	if ( m_hImgctl != NULL )
	{
		FreeLibrary( m_hImgctl );
	}
}


/*-----------------------------------------------------------------------------
[名称]	プラグイン名称取得
[機能]	プラグイン名称の取得。
[戻値]	const char*		プラグイン名称 [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
const char*		CShitarabianPlugInWall::GetPlugInName()
{
	return( "壁紙 ver1.4a" );
}


/*-----------------------------------------------------------------------------
[名称]	壁紙描画ハンドラ
[機能]	壁紙の描画。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void		CShitarabianPlugInWall::OnDrawWall(
	CDocumentIF*	pDocIF,		// I  :ドキュメントIF [-] (-) :-
	CDC*			pDstDC,		//   O:描画先DC [-] (-) :-
	int				iLeft,		// I  :描画矩形左端 [pixel] (-) :-
	int				iTop,		// I  :描画矩形上端 [pixel] (-) :-
	int				iWidth,		// I  :描画矩形幅 [pixel] (-) :-
	int				iHeight		// I  :描画矩形高さ [pixel] (-) :-
)
{
	// warning C4100:警告の無視
	pDocIF;

	if ( m_bWallEnable )
	{
		CDC		WallDC;
		WallDC.CreateCompatibleDC( pDstDC );
		CBitmap*	pbmpWall = GetBitmap();
		if ( pbmpWall != NULL )
		{
			CBitmap*	pOld = WallDC.SelectObject( pbmpWall );

			BITMAP	tBitmap;
			pbmpWall->GetBitmap( &tBitmap );
			int		iBitmapWidth = tBitmap.bmWidth;
			int		iBitmapHeight = tBitmap.bmHeight;

			iLeft -= m_iOffsetX;
			iTop -= m_iOffsetY;

			pDstDC->BitBlt(
				0,
				0,
				min( iBitmapWidth - iLeft, iWidth ),
				min( iBitmapHeight - iTop, iHeight ),
				&WallDC,
				iLeft,
				iTop,
				SRCCOPY
			);

			WallDC.SelectObject( pOld );
		}
	}
}


/*-----------------------------------------------------------------------------
[名称]	設定編集ハンドラ
[機能]	壁紙設定ダイアログの表示。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void	CShitarabianPlugInWall::OnSetting(
	CDocumentIF*	pDoc		// I  :ドキュメントIF [-] (-) :-
)
{
	// ダイアログコントロールの値を設定する
	{
		f_Walldlg.m_bWallEnable = m_bWallEnable;
		f_Walldlg.m_strImageFileName = m_strFileName;
		f_Walldlg.m_iGray = m_uiGray;
		f_Walldlg.m_uiRed = m_iRed;
		f_Walldlg.m_uiGreen = m_iGreen;
		f_Walldlg.m_uiBlue = m_iBlue;
		f_Walldlg.m_bEffect = ( m_hImgctl != NULL );
		f_Walldlg.m_iOffsetX = m_iOffsetX;
		f_Walldlg.m_iOffsetY = m_iOffsetY;
		f_Walldlg.m_uiSizeX = 100;
		f_Walldlg.m_uiSizeY = 100;
		f_Walldlg.m_bResize = m_bResize;

		// ビットマップの大きさ
		CBitmap*	pbmpWall = GetBitmap();
		if ( pbmpWall != NULL )
		{
			BITMAP	tBitmap;
			pbmpWall->GetBitmap( &tBitmap );
			int		iBitmapWidth = tBitmap.bmWidth;
			int		iBitmapHeight = tBitmap.bmHeight;

			f_Walldlg.m_uiSizeX = iBitmapWidth;
			f_Walldlg.m_uiSizeY = iBitmapHeight;
		}
	}

	// ダイアログの表示
	f_Walldlg.Attatch( pDoc, this );
	if ( IDOK == f_Walldlg.DoModal() )
	{
		// 設定の反映
		ReflectFromDialog( pDoc );

		pDoc->SetAllUpdate();
		pDoc->ReDraw();
	}
}


/*-----------------------------------------------------------------------------
[名称]	設定反映
[機能]	壁紙設定ダイアログの壁紙設定をビューに反映して再描画する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void	CShitarabianPlugInWall::ReflectFromDialog(
	CDocumentIF*	pDoc		// I  :ドキュメントIF [-] (-) :-
)
{
	m_bWallEnable = f_Walldlg.m_bWallEnable;
	m_strFileName = f_Walldlg.m_strImageFileName;
	m_uiGray = f_Walldlg.m_iGray;
	m_iRed = f_Walldlg.m_uiRed;
	m_iGreen = f_Walldlg.m_uiGreen;
	m_iBlue = f_Walldlg.m_uiBlue;
	m_iOffsetX = f_Walldlg.m_iOffsetX;
	m_iOffsetY = f_Walldlg.m_iOffsetY;
	m_iSizeX = f_Walldlg.m_uiSizeX;
	m_iSizeY = f_Walldlg.m_uiSizeY;
	m_bResize = f_Walldlg.m_bResize;

	Reflect( pDoc );
}


/*-----------------------------------------------------------------------------
[名称]	設定反映
[機能]	壁紙設定をビューに反映して再描画する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void	CShitarabianPlugInWall::Reflect(
	CDocumentIF*	pDoc		// I  :ドキュメントIF [-] (-) :-
)
{
	// 新規読み込みをさせるために既存のBITMAPを削除する
	CloseImage();
	GetBitmap();

	// 色を落としてみる
	ToGray(
		(USHORT)m_uiGray,
		m_iRed,
		m_iGreen,
		m_iBlue
	);

	// please! imgctrlがあるときはその機能で縮小したい(ToGrayの中で)
	// 画像大きさを反映
	if( m_bResize )
	{
		// 目的の大きさのビットマップを作り
		CDC			dcMem;
		CBitmap		bmpMem;
		CBitmap*	pOldBMP;
		{
			HDC	hdc = ::GetDC( NULL );
			dcMem.CreateCompatibleDC( CDC::FromHandle( hdc ) );
			bmpMem.CreateCompatibleBitmap(
				CDC::FromHandle( hdc ),
				m_iSizeX,
				m_iSizeY
			);
			::ReleaseDC( NULL, hdc );

			pOldBMP = dcMem.SelectObject( &bmpMem );
		}

		CDC			dcSrc;
		CBitmap*	pOldBMPSrc;
		{
			HDC	hdc = ::GetDC( NULL );
			dcSrc.CreateCompatibleDC( CDC::FromHandle( hdc ) );
			pOldBMPSrc = dcSrc.SelectObject( &bmpWall );
			::ReleaseDC( NULL, hdc );
		}

		BITMAP	tBitmap;
		bmpWall.GetBitmap( &tBitmap );
		int		iBitmapWidth = tBitmap.bmWidth;
		int		iBitmapHeight = tBitmap.bmHeight;

		// StretchBlt
		dcMem.StretchBlt(
			0,0, m_iSizeX, m_iSizeY,
			&dcSrc,
			0,0,
			iBitmapWidth, iBitmapHeight,
			SRCCOPY
		);

		// bmpWallを差し替える
		CloseImage();

		{
			HDC	hdc = ::GetDC( NULL );
			bmpWall.CreateCompatibleBitmap(
				CDC::FromHandle( hdc ),
				m_iSizeX,
				m_iSizeY
			);
			::ReleaseDC( NULL, hdc );

			dcSrc.SelectObject( bmpWall );

			dcSrc.BitBlt(
				0,0, m_iSizeX, m_iSizeY,
				&dcMem,
				0,0,
				SRCCOPY
			);
			dcSrc.SelectObject( pOldBMPSrc );

			bInitialine = TRUE;
		}
	}

	// 描画させる
	pDoc->SetAllUpdate();
	pDoc->ReDraw();
}


/*-----------------------------------------------------------------------------
[名称]	画像読み込み
[機能]	ファイルから画像を読み込む。
[戻値]	CBitmap*	画像 [-] (-)
[備考]	なし
-----------------------------------------------------------------------------*/
CBitmap* CShitarabianPlugInWall::GetBitmap()
{
	if ( !bInitialine )
	{
		if ( !m_strFileName.IsEmpty() )
		{
			CFileStatus	status;
			BOOL	bExists = CFile::GetStatus( m_strFileName, status );
			if ( bExists )
			if ( OpenImage( m_strFileName, &bmpWall ) )
			{
				bInitialine = TRUE;
				return( &bmpWall );
			}
		}

		// 無効なファイルだったようなのでファイル名を初期化しておく
		m_strFileName = _T("");
		return( NULL );
	}
	return( &bmpWall );
}


/*-----------------------------------------------------------------------------
[名称]	画像破棄
[機能]	読み込み済みの画像を破棄する。
[戻値]	なし
[備考]	なし
-----------------------------------------------------------------------------*/
void CShitarabianPlugInWall::CloseImage()
{
	HGDIOBJ hBitmap = bmpWall.Detach();
	DeleteObject( hBitmap );

	bInitialine = FALSE;
}


/*-----------------------------------------------------------------------------
[名称]	画像読み込み
[機能]	ファイルから画像を読み込む。
[戻値]	BOOL	読み込み結果 [-] (TRUE:成功、FALSE:失敗)
[備考]	なし
-----------------------------------------------------------------------------*/
BOOL CShitarabianPlugInWall::OpenImage(
	CString&		strFileName,		// I  :ファイル名称 [-] (-) :-
	CBitmap*		pBitmap				//   O:画像 [-] (-) :-
) 
{
	// もしビットマップとして読めたらうれしいね。
	{
		HBITMAP		hBitmap = (HBITMAP)LoadImage(
						NULL,
						strFileName,
						IMAGE_BITMAP,
						0,
						0,
						LR_LOADFROMFILE
		);
		if ( hBitmap != NULL )
		{
			pBitmap->Attach( hBitmap );
			return( TRUE );
		}
	}

	// Susie-Pluginを使用した画像読み込み
	int		iResult;
	CHiddenDecoder	Decoder;
	{
		// PluginFolderの設定
		Decoder.PluginFolder(
			CSettingPath::GetInstance()->GetFolderPath()
		);

		// サポートしているかを検査
		{
			FILE*	dw = fopen( strFileName, "r+b" );
			char *data;
			char buff[3000];

			/* dwはファイルハンドル */
			DWORD ReadBytes;
			memset(buff, 0, 3000);
			ReadBytes = fread( buff, 1, 3000, dw );

			if ( ReadBytes == 0 )
			{
				fclose( dw );
				return( FALSE );
			}
			data = buff;

			// フォーマット確認
			iResult = Decoder.IsSupportedCore(
				strFileName.GetBuffer(strFileName.GetLength()),
				(unsigned long)data
			);
			fclose( dw );
		}

		// 画像情報を得る
		PictureInfo	tPictureInfo;
		{
			tPictureInfo.hInfo = NULL;

			int		iGetPictureInfo;
			iGetPictureInfo = Decoder.GetPictureInfoCore(
				(char*)((LPCSTR)strFileName),
				0,	// offset
				0,	// on disk
				&tPictureInfo
			);
			if ( tPictureInfo.hInfo != NULL )
			{
				::LocalUnlock(tPictureInfo.hInfo);
				::LocalFree(tPictureInfo.hInfo);
				tPictureInfo.hInfo	= NULL;
			}
		}

		// 画像を得る
		HLOCAL	hBmpInfo = NULL;
		HLOCAL	hBmp = NULL;
		{
			int		iGetPicture;
			iGetPicture = Decoder.GetPictureCore(
				(char*)((LPCSTR)strFileName),
				0,
				0,			// on disk
				&hBmpInfo,
				&hBmp,
				NULL,		// callback
				0
			);
			if (( hBmpInfo == NULL ) ||
				( hBmp == NULL ))
			{
				// 画像の取得に失敗
				ErrorLog( "画像の取得", "Decoder::GetPictureCore()" );
				return( FALSE );
			}

			//取得ハンドルからメモリをロックする（DIBデータを確保する）
			LPBITMAPINFO	pBmpInfo;	//イメージからの取得のLPBITMAPINFO
			LPBYTE			pBmp;		//イメージからの取得のビット配列

			pBmp = (LPBYTE) LocalLock(hBmp); 
			pBmpInfo = (LPBITMAPINFO) LocalLock(hBmpInfo);

			HDC	hdc = ::GetDC( NULL );

			// 表示用DIBを作成する
			HBITMAP hBitmap = ::CreateDIBitmap(
				hdc,
				(LPBITMAPINFOHEADER)pBmpInfo,
				CBM_INIT,
				pBmp,
				pBmpInfo,
				DIB_RGB_COLORS
			);

			::ReleaseDC( NULL, hdc );

			// 確保させたメモリを解放
			if (hBmp){
				::LocalUnlock(hBmp);
				::LocalFree(hBmp);
				hBmp	= NULL;
			}
			if (hBmpInfo){
				::LocalUnlock(hBmpInfo);
				::LocalFree(hBmpInfo);
				hBmpInfo	= NULL;
			}
			pBitmap->Attach( hBitmap );
		}
	}
	return( TRUE );
}


/*-----------------------------------------------------------------------------
[名称]	グレースケール化・輝度反映。
[機能]	グレースケール・輝度反映処理。
[戻値]	BOOL	処理結果 [-] (TRUE:成功、FALSE:失敗)
[備考]	imgctrl使用。
-----------------------------------------------------------------------------*/
BOOL	CShitarabianPlugInWall::ToGray(
	WORD	wGray,				// グレー度 [-] (0〜255)
	int		RedEffect,			// 赤輝度 [-] (0〜255)
	int		GreenEffect,		// 緑輝度 [-] (0〜255)
	int		BlueEffect			// 青輝度 [-] (0〜255)
)
{
	// ライブラリが存在するのなら、エフェクト用DIBを作成する
	if ( m_hImgctl != NULL )
	{
		CBitmap*	pbmpWall = GetBitmap();
		CDC		DC;
		DC.CreateCompatibleDC( NULL );

		{
			BITMAP	tBitmap;
			::GetObject( (HBITMAP)(*pbmpWall), sizeof(BITMAP), &tBitmap );

			// BITMAPINFO取得
			BITMAPINFO	tBitmapInfo;
			tBitmapInfo.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );

            memset( &tBitmapInfo, 0, sizeof(tBitmapInfo) );

            tBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
            tBitmapInfo.bmiHeader.biWidth = tBitmap.bmWidth;
            tBitmapInfo.bmiHeader.biHeight = tBitmap.bmHeight;
            tBitmapInfo.bmiHeader.biPlanes = tBitmap.bmPlanes;
            tBitmapInfo.bmiHeader.biBitCount = tBitmap.bmBitsPixel;

			int iResult = ::GetDIBits(
				DC.m_hDC,					// handle to device context
				(HBITMAP)(*pbmpWall),		// handle to bitmap
				0,
				100,							// number of scan lines to copy
				NULL,						// address of array for bitmap bits
				&tBitmapInfo,				// address of structure with bitmap data
				DIB_RGB_COLORS				// RGB or palette index
			);
			if ( iResult == 0 )
			{
				return( FALSE );
			}

			UINT		uiColorFlag;
			switch ( tBitmapInfo.bmiHeader.biBitCount )
			{
			case 1:
				uiColorFlag = DIB_PAL_COLORS;
				// ごめん、未対応。RGBQUAD用意するのがめんどくさい。
				return( FALSE );
				break;

			default:
				uiColorFlag = DIB_RGB_COLORS;
				break;
			}

			int		iWidth = tBitmapInfo.bmiHeader.biWidth;
			int		iHeight = tBitmapInfo.bmiHeader.biHeight;
			int		iDepth = tBitmapInfo.bmiHeader.biBitCount;

			long	nBit = iWidth * iHeight * iDepth;
			char* pBitmapBits = new char[ nBit + sizeof(BITMAPFILEHEADER) ];


			// BITMAPINFO取得
			iResult = ::GetDIBits(
				DC.m_hDC,					// handle to device context
				(HBITMAP)(*pbmpWall),		// handle to bitmap
				0,
				tBitmapInfo.bmiHeader.biHeight,
				pBitmapBits,				// address of array for bitmap bits
				&tBitmapInfo,				// address of structure with bitmap data
				uiColorFlag					// RGB or palette index
			);
			if ( iResult == 0 )
			{
				delete [] pBitmapBits;
				return( FALSE );
			}

			// HDIB作成
			HDIB	hDib = NULL;
			{
				//HDIB CreateDIB(const BITMAPINFO *pbmi, LPCVOID pvData)
				CREATEDIB		fnCreateDIB = NULL;
				fnCreateDIB = (CREATEDIB)GetProcAddress( m_hImgctl, "CreateDIB" );
				if ( fnCreateDIB != NULL )
				{
					hDib = fnCreateDIB( &tBitmapInfo, pBitmapBits );
				}
			}

			if ( hDib != NULL )
			{
				// グレイスケール化
				GRAYDIB		fnGrayDIB = NULL;
				fnGrayDIB = (GRAYDIB)GetProcAddress( m_hImgctl, "GrayDIB" );
				if ( fnGrayDIB != NULL )
				{
					fnGrayDIB( hDib, (USHORT)(wGray%256) );
				}

				// 明度調整
				TONEDIB		fnToneDIB = NULL;
				fnToneDIB = (TONEDIB)GetProcAddress( m_hImgctl, "ToneDIB");
				if ( fnToneDIB != NULL )
				{
					fnToneDIB(
						hDib,
						(short)RedEffect,
						(short)GreenEffect,
						(short)BlueEffect
					);
				}

				// bmpWallへ転送
				{
					BITMAP	tBitmap;
					pbmpWall->GetBitmap( &tBitmap );
					int		iBitmapWidth = tBitmap.bmWidth;
					int		iBitmapHeight = tBitmap.bmHeight;

					DIBDIBITS		fnDIBDIBits = NULL;
					fnDIBDIBits = (DIBDIBITS)GetProcAddress( m_hImgctl, "DIBDIBits" );
					if ( fnDIBDIBits != NULL )
					{
						CBitmap*	pOld;
						pOld = DC.SelectObject( pbmpWall );

						fnDIBDIBits(
							DC.m_hDC,
							0,
							0,
							iBitmapWidth,
							iBitmapHeight,
							hDib,
							0,
							0,
							SRCCOPY
						);

						DC.SelectObject( pOld );
					}
				}

				DELETEDIB		fnDeleteDIB = NULL;
				fnDeleteDIB = (DELETEDIB)GetProcAddress( m_hImgctl, "DeleteDIB" );
				if ( fnDeleteDIB != NULL )
				{
					fnDeleteDIB( hDib );
				}
			}

			delete [] pBitmapBits;
		}
	}

	return( TRUE );
}