// ScanLogicPuzzle.cpp: ScanLogicPuzzle クラスのインプリメンテーション
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "shitarabianLogic.h"
#include "ScanLogicPuzzle.h"

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

#define		END_STRING  ( 0x00 )
#define		END_LINE	( 0x0A )
#define		BLOCK_WHITE	( 0xA0 )
#define		BLOCK_BLACK	( 0xA1 )

//////////////////////////////////////////////////////////////////////
// 構築/消滅
//////////////////////////////////////////////////////////////////////

ScanLogicPuzzle::ScanLogicPuzzle()
:iSetSizeX	( 0 )
,iSetSizeY	( 0 )
,bEnable	( FALSE )
{

}

ScanLogicPuzzle::~ScanLogicPuzzle()
{

}

//スキャン後の文字列の出力
CString ScanLogicPuzzle::GetScaned()
{
	return strScanLog;
}
CString ScanLogicPuzzle::GetQuestion()
{
	return strQuestion;
}

//全体の処理
BOOL ScanLogicPuzzle::Scan( uchar* pucLogic )
{
	MakeLogic( pucLogic );

	if ( bEnable == TRUE )
	{
		ScanY( ( uchar* )( ( LPCTSTR )strScanLog ) );
		ScanX( ( uchar* )( ( LPCTSTR )strScanLog ) );
		SetScaned( &strScanLog );
	}
	return bEnable;
}

//前処理
void ScanLogicPuzzle::MakeLogic( uchar* pucLogic )
{
	int 
		iElem = 0,
		iSetBlockNum = 0,
		iCount = 1,
		iWhiteNum = 0;

	while( pucLogic[iElem] != END_STRING )
	{
		if ( pucLogic[iElem] == 0x81 &&
		   ( pucLogic[iElem + 1] == BLOCK_WHITE || pucLogic[iElem + 1] == BLOCK_BLACK ) )
		{
			strScanLog += pucLogic[iElem++];
			strScanLog += pucLogic[iElem++];
			bEnable = TRUE;
		}
		else if ( pucLogic[iElem] == END_LINE )
		{
			strScanLog += pucLogic[iElem++];
		}
		else
		{
			iElem++;
		}
	}
	iSetBlockNum = GetLongLine( ( uchar* )( ( LPCTSTR )strScanLog ) );

	for ( iElem = 0; iElem < strScanLog.GetLength(); iElem++ )
	{
		if ( strScanLog.GetAt( iElem ) == END_LINE )
		{
			if ( iSetBlockNum > iCount )
			{
				iWhiteNum = ( iSetBlockNum - iCount ) / 2;
				for ( iCount = 0; iCount < iWhiteNum; iCount++ )
				{
					strScanLog.Insert( iElem , "□" );
					iElem += 2;
				}
			}
			iCount = 0;
		}
		iCount++;
	}
	if ( iSetBlockNum > iCount )
	{
		iWhiteNum = ( iSetBlockNum - iCount ) / 2;
		for ( iCount = 0; iCount < iWhiteNum; iCount++ )
		{
			strScanLog.Insert( iElem , "□" );
		}
	}
}

//Ｘ方向の処理
void ScanLogicPuzzle::ScanX( uchar* pucLogic )
{
	int		
		iBlackNum	= 0,						//"■"
		iSetSize	= 0;
	uchar	
		ucNum[4];
	BOOL	
		bZero		= TRUE;
	
	//"■"の判定
	while ( *pucLogic != END_STRING )
	{
		if ( *pucLogic == BLOCK_BLACK )
		{
			iBlackNum++;
			bZero = FALSE;
		}
		else if ( *pucLogic == BLOCK_WHITE && iBlackNum > 0 )
		{
			aScanNumX.Add( FixNum( iBlackNum , ucNum ) );
			iSetSize++;
			iBlackNum = 0;
		}
		else if ( *pucLogic == END_LINE )
		{
			if ( iBlackNum > 0 || bZero == TRUE )
			{
				aScanNumX.Add( FixNum( iBlackNum , ucNum ) );
				iSetSize++;
				iBlackNum = 0;
			}
			aScanNumX.Add( END_LINE );
			if ( iSetSizeX < iSetSize )
			{
				iSetSizeX = iSetSize;
			}
			iSetSize = 0;
			bZero = TRUE;
		}
		*pucLogic++;
	}
	if ( iBlackNum > 0 || bZero == TRUE )
	{
		aScanNumX.Add( FixNum( iBlackNum , ucNum ) );
		iSetSize++;
		iBlackNum = 0;
	}
	aScanNumX.Add( END_LINE );
	if ( iSetSizeX < iSetSize )
	{
		iSetSizeX = iSetSize;
	}
	FixSize( &aScanNumX , iSetSizeX );
}

//Ｙ方向の処理
void ScanLogicPuzzle::ScanY( uchar* pucLogic )
{
	uchar 
		ucNum[4];
	int 
		iBlackNum	= 0,
		iCount		= 0,
		iElem		= 1,
		iEnd		= 0,
		iSetSize	= 0;
	BOOL 
		bZero		= TRUE;

	iEnd = GetLongLine( pucLogic );
	Divide( &aDivLogic , pucLogic );

	while ( iElem < iEnd )
	{
		while( iCount < aDivLogic.GetSize() )
		{
			if( iElem < aDivLogic.GetAt( iCount ).GetLength() )
			{
				if ( ( uchar )( aDivLogic.GetAt( iCount ).GetAt( iElem ) ) == BLOCK_BLACK )
				{
					iBlackNum++;
					bZero = FALSE;
				}
				else if ( iBlackNum > 0 )
				{
					aScanNumY.Add( FixNum( iBlackNum , ucNum ) );
					iSetSize++;
					iBlackNum = 0;
				}
			}
			iCount++;
		}
		if ( iBlackNum > 0 || bZero == TRUE )
		{
			aScanNumY.Add( FixNum( iBlackNum , ucNum ) );
			iSetSize++;
			iBlackNum = 0;
		}
		aScanNumY.Add( END_LINE );

		if ( iSetSizeY < iSetSize )
		{
			iSetSizeY = iSetSize;
		}
		iSetSize = 0;
		
		bZero = TRUE;
		iElem += 2;
		iCount = 0;
	}
	FixSize( &aScanNumY , iSetSizeY );
}

//スキャンした値をセットする
void ScanLogicPuzzle::SetScaned( CString* pstrSet )
{
	int 
		iCount		= 0,
		iSpaceNum	= 0,
		isxElem		= 0,
		isyElemY	= 0,
		isyElemX	= 0,
		idlElem		= 0;
	CString 
		strSpace;

	pstrSet->Empty();

	//余白の作成
	iSpaceNum = iSetSizeX;
	while ( iSpaceNum > 0 )
	{
		strSpace += "　 ";
		iSpaceNum--;
	}
	
	//Ｙ方向の値を並び替えながら挿入
	while ( aScanNumY.GetAt( isyElemX ) != END_LINE )
	{
		//余白の挿入
		*pstrSet += strSpace;
		strQuestion += strSpace;
		
		isyElemY = isyElemX;
		while ( isyElemY < aScanNumY.GetSize() )
		{
			*pstrSet += aScanNumY.GetAt( isyElemY );
			strQuestion += aScanNumY.GetAt( isyElemY );
			isyElemY += iSetSizeY + 1;
		}
		*pstrSet += 0x0D;
		*pstrSet += END_LINE;

		strQuestion += 0x0D;
		strQuestion += END_LINE;

		isyElemX++;
	}
	
	//Ｘ方向の値とロジック本体の挿入
	while ( isxElem < aScanNumX.GetSize() )
	{
		while ( aScanNumX.GetAt( isxElem ) != END_LINE )
		{
			*pstrSet += aScanNumX.GetAt( isxElem );
			strQuestion += aScanNumX.GetAt( isxElem++ );
		}
		*pstrSet += aDivLogic.GetAt( idlElem++ );
		*pstrSet += 0x0D;
		*pstrSet += END_LINE;
		
		strQuestion += strWhiteBlock;
		strQuestion += 0x0D;
		strQuestion += END_LINE;

		isxElem++;
	}
}

//改行ごとに文字列を分ける
void ScanLogicPuzzle::Divide( CStringArray* pstrArray , uchar* pucLogic )
{
	int 
		iLine = 0,
		iElem = 0;
	
	iLine = GetLongLine( pucLogic );
	uchar* pucTemp = new uchar[iLine];

	int iWhiteBlockNum = iLine / 2;
	
	while( iWhiteBlockNum > 0 )
	{
		strWhiteBlock += "□";
		iWhiteBlockNum--;
	}

	while ( *pucLogic != END_STRING )
	{
		if ( *pucLogic == END_LINE )
		{
			pucTemp[iElem] = END_STRING;
			pstrArray->Add( pucTemp );
			iElem = 0;
			*pucLogic++;
		}
		pucTemp[iElem++] = *pucLogic++;
		if ( *pucLogic == END_STRING )
		{
			pucTemp[iElem] = END_STRING;
		}
	}
	pstrArray->Add( pucTemp );
	delete [] pucTemp;
}

//スキャンした数を２バイト文字でまとめる
uchar* ScanLogicPuzzle::FixNum ( int iNum , uchar* ucpNum )
{	
	int iElem  = 0;

	if ( iNum < 10 )
	{
		//"１"〜"９"を生成
		ucpNum[iElem++] = 0x82;
		ucpNum[iElem++] = 0x4F + iNum;
		ucpNum[iElem++] = 0x20;
	}
	else if ( iNum < 100 )
	{
		//"10"〜"99"を生成
		ucpNum[iElem++] = 0x30 + ( iNum / 10 );
		ucpNum[iElem++] = 0x30 + ( iNum % 10 );
	}
	else
	{
		//100以上はとりあえず"??"でごまかす
		ucpNum[iElem++] = 0x3F;					
		ucpNum[iElem++] = 0x3F;
	}
	ucpNum[iElem] = END_STRING;

	return ucpNum;
}

//スキャンした値の修正
void ScanLogicPuzzle::FixSize( CStringArray* paScaned , int iFixSize )
{
	int		
		iaElem = 0,
		iaSpace = 0,
		iCount = 0,
		iSpace = 0;

	while ( iaElem < paScaned->GetSize() )
	{
		if ( paScaned->ElementAt( iaElem ) == END_LINE )
		{
			iSpace = iFixSize - iCount;						//"　 " スペースを入れる数
			if ( iSpace > 0 )
			{
				while ( iSpace > 0 )
				{
					paScaned->InsertAt( iaSpace , "　 " );
					iaElem++;
					iSpace--;
				}
			}
			iaSpace += iFixSize + 1 ;
			iCount = 0;
		}
		else
		{
			iCount++;
		}
		iaElem++;
	}
}	

//一番長い行の文字列のバイト数を返す
int ScanLogicPuzzle::GetLongLine( uchar* pucLogic )
{
	int 
		iLong	= 0,
		iCount	= 1;

	while ( *pucLogic != END_STRING )
	{
		if ( *pucLogic == END_LINE )
		{
			if ( iLong < iCount )
			{
				iLong = iCount;
			}
			iCount = 0;
		}
		pucLogic++;
		iCount++;
	}
	if ( iLong < iCount )
	{
		iLong = iCount;
	}
	return iLong;
}
