//==============================================================================================================================
//	変換ルーチンベースプログラム
//==============================================================================================================================
#define	SW_MODULE_FITPARTS

#define	MAX_EXTRY	10000

DWORD	mask_col;
#define	NO_MASK		0x80000000

typedef struct
{
	TCHAR	bname[_MAX_PATH];
	TCHAR	pname[_MAX_PATH];
	TCHAR	oname[_MAX_PATH];
	int		w;
	int		h;
	int		px;
	int		py;
//	int		sx;
//	int		sy;
}FILE_LIST;


//		
class FITPARTS
{
	BOOL		m_bInitialized;
	BOOL		m_bImplemented;
	
private:
	int			locate( LPCTSTR base_name, LPCTSTR parts_name, int *ax, int *ay, int optimize, int fitparam );
	int			fit_picture( LPCTSTR outname, LPCTSTR basename, LPCTSTR partsname, int x, int y );
	int			rev_picture(int ii);
	void		set_filelist( char *ptr, int len, int flag );
	void		out_filelist( LPCTSTR fname );
	
	int			search_combination(int ii);
	int			get_basenum(int ii);
	
	LPCTSTR		dpath( LPCTSTR path );
	LPCTSTR		opath( LPCTSTR path );
	
	TCHAR		m_cDataPath[_MAX_PATH];
	TCHAR		m_cOutPath[_MAX_PATH];
	
	FILE_LIST	m_List[MAX_EXTRY];
	int			m_iLEntry;
	
	TCHAR		m_cDWork[_MAX_PATH];
	int			m_iOldw, m_iOldh;
	
public:
	void		Initialize();
	int			Func( LPCTSTR _sParamString );
	int			func_rev( LPCTSTR _sParamString );
	void		Quit( BOOL _bExit );
	
	FITPARTS();
	~FITPARTS();
	
};


FITPARTS::FITPARTS()
 : m_bInitialized( NULL )
 , m_bImplemented( NULL )
{
	
	memset( (char*)m_List, 0, sizeof(FILE_LIST)*MAX_EXTRY );
	
	mask_col = 0;//NO_MASK;
}

FITPARTS::~FITPARTS()
{
	
}


void	FITPARTS::Initialize()
{
	
}

//		
void	FITPARTS::Quit( BOOL _bExit )
{
	
	if(m_bImplemented == FALSE)	return;
	m_bImplemented = FALSE;
	m_bInitialized = FALSE;
	//	終了処理は変換処理が実行された場合のみ行う
	
	
}


//		
//in:
//		char*	
//		int		長さ
//		int		0:サイズをデータから　1:サイズをリストから取得
void	FITPARTS::set_filelist( char *ptr, int len, int flag )
{
	int		ii,jj,k,val;
	TCHAR	work[_MAX_PATH];
	TCHAR	base[_MAX_PATH];
	char	*mem = NULL;
	BMPINFO bmp;
	
	
	m_iLEntry = 0;
	ii = jj = 0;
	while(ii < len){
		if(*(ptr+ii) == '\r' || *(ptr+ii) == '\n'){
			//	改行	次のデータへ
			ii++;
			if(*(ptr+ii) == '\n')	ii++;
			
			if(flag==0){
				if(m_List[m_iLEntry].oname[0] == 0){	//	出力ファイル名なし
					if(m_List[m_iLEntry].pname[0]==0){	//ベース
						STRING_cpy( m_List[m_iLEntry].oname,m_List[m_iLEntry].bname);
					}
					else{							//パーツ
						STRING_cpy( m_List[m_iLEntry].oname,m_List[m_iLEntry].pname);
					}
				}
			}
			
			m_iLEntry++;
			if(m_iLEntry >= MAX_EXTRY){
				Message_error( TEXT("ファイルが多すぎます") );
				return;
			}
			
			m_List[m_iLEntry].bname[0] = 
			m_List[m_iLEntry].pname[0] = 
			m_List[m_iLEntry].oname[0] = 0;
			m_List[m_iLEntry].px = m_List[m_iLEntry].py = -1;
			jj = 0;
		}else if(*(ptr+ii)=='\t'){
			jj++;
			ii++;
		}else if(*(ptr+ii)==','){
			jj++;
			ii++;
		}else{
			k = 0;
			while(*(ptr+ii) != '\t' && *(ptr+ii) != ',' && *(ptr+ii) != '\r' && *(ptr+ii) != '\n' && ii<len){
				work[k++] = *(ptr+ii++);
			}
			work[k] = 0;
			
			switch(jj){
				case 0:	//	ベース絵は省略可なだけで全てのデータにセットされる
					STRING_cpy(m_List[m_iLEntry].bname,work);
					STRING_cpy(base,work);
					if(flag==0){
						if( MEM_TargetRead( &mem, dpath(work) ) == 0 ){
							Message_error( TEXT("%s not read"), work );
							break;
						}
						bmp = BMP_GetRECTinfo(mem);
						m_List[m_iLEntry].w = bmp.Width;
						m_List[m_iLEntry].h = bmp.Height;
						mem_del(mem);
					}
					break;
				case 1:
					STRING_cpy(m_List[m_iLEntry].pname,work);
					if(flag==0){
						if( MEM_TargetRead( &mem, dpath(work) ) == 0 ){
							Message_error( TEXT("%s not read"), work );
							break;
						}
						bmp = BMP_GetRECTinfo(mem);
						m_List[m_iLEntry].w = bmp.Width;
						m_List[m_iLEntry].h = bmp.Height;
						mem_del(mem);
					}
					STRING_cpy( m_List[m_iLEntry].bname, base );
					break;
				case 2:	//	出力ファイル名
					STRING_cpy( m_List[m_iLEntry].oname, work );
					break;
			
				case 3:
					if(flag)	m_List[m_iLEntry].w = STRING_atoi(work);
					break;
				case 4:
					if(flag)	m_List[m_iLEntry].h = STRING_atoi(work);
					break;
			
				case 5:
					m_List[m_iLEntry].px = STRING_atoi(work);
					break;
				case 6:
					m_List[m_iLEntry].py = STRING_atoi(work);
					break;
				case 7:
					val = STRING_atoi(work);
					break;
				case 8:
					val = STRING_atoi(work);
					break;
			}
			
		}
		
		
	}
	
}


//		
void	FITPARTS::out_filelist( LPCTSTR fname )
{
	int		ii;
	
	
	FILE_delete(fname);
	
//	FILE_printf(fname,"base	parts	out	w	h	px	py\r\n");
	
	for(ii=0 ; ii<m_iLEntry ; ii++){
		if(m_List[ii].pname[0] != 0){
			FILE_printf( fname, TEXT("	%s	%s	%d	%d	%d	%d\r\n"), m_List[ii].pname, m_List[ii].oname, m_List[ii].w, m_List[ii].h, m_List[ii].px, m_List[ii].py );
		}else if(m_List[ii].bname[0] != 0){
			if(m_List[ii].oname[0]==0)	FILE_printf( fname, TEXT("%s			%d	%d\r\n"), m_List[ii].bname, m_List[ii].w, m_List[ii].h );
			else						FILE_printf( fname, TEXT("%s		%s	%d	%d\r\n"), m_List[ii].bname, m_List[ii].oname, m_List[ii].w, m_List[ii].h );
		}else{
			FILE_printf( fname, TEXT("\r\n") );
		}
		
	}
	
}


//		
int		FITPARTS::search_combination(int ii){
/*	int		jj,len;
	char	*mem,*mem_base,*mem_parts;
	
	
	mem = mem_base = NULL;
	len = MEM_TargetRead(&mem,dpath(m_List[ii].bname));
	if(len==0)	return 0;
	len = BMP_to32RGB( mem, &mem_base );
	mem_del(mem);
	
	jj = ii+1;
	while(m_List[jj].pname[0] != 0 && jj<m_iLEntry){
		
		mem = mem_parts = NULL;
		len = MEM_TargetRead(&mem,dpath(m_List[jj].pname));
		if(len==0)	return 0;
		len = BMP_to32RGB( mem, &mem_parts );
		mem_del(mem);
		
		
		
		
		
		
		mem_del(mem_parts);
		jj++;
	}
*/	
	return 1;
}

//		
int		FITPARTS::Func( LPCTSTR _sParamString )
{
	CSwbParam	cParam( _sParamString );							///< パラメータ処理.

	char	*mem = NULL;
	int		ii, ax, ay, len, bs;
	LPCTSTR	sName, sPath1, sPath2;
	
	
	/// 引数の取り出し.
	sName   = cParam.GetPath();		///< ターゲットファイル (GetFilePath(0)としても同じ).
	sPath1  = cParam.GetOutPath();
	sPath2  = cParam.GetString( 2 );
	
	
	if(m_bImplemented == TRUE )	return TRUE;	//１回だけ
	
	len = MEM_TargetRead( &mem, sName );
	if(len == 0)	return FALSE;
	m_bImplemented = TRUE;	//	実行済みフラグ
	
	STRING_cpy( m_cDataPath, sPath1 );
	STRING_cpy( m_cOutPath,  sPath2 );
	
	//	リスト読み込み
	Message_win( TEXT("searching...") );
	set_filelist( mem, len, 0 );
	
	mem_del(mem);
	
	Message_win( TEXT("fiting") );
	m_iOldw = m_iOldh = 0;
	
	//	位置調べ
	bs = 0;
	ax = ay = 0;
	for(ii=0 ; ii<m_iLEntry ; ii++){
		if(m_List[ii].pname[0] == 0){
			bs = ii;			//	最後のベース保存
			ax = ay = 0;	//	ベースなら
		}
		if(m_List[ii].bname[0] == 0 || m_List[ii].pname[0] == 0)	continue;	//ベースが指定されない事はないが念のため
		
		if(m_List[ii].px < 0 || m_List[ii].py < 0){		//	置き位置未設定
			
			//											最適化あり,適合80%以上
			if( locate( m_List[ii].bname,m_List[ii].pname,&ax,&ay,1,80)==100)	m_List[bs].oname[0] = 0;
			if( m_List[ii].px < 0)	m_List[ii].px = ax;
			if( m_List[ii].py < 0)	m_List[ii].py = ay;
		}else{
			Message_printf( TEXT("%s  already printing."), m_List[ii].bname );
		}
	}
	
	Message_win( TEXT("outing") );
	//	重ね
	for(ii=0 ; ii<m_iLEntry ; ii++){
/*			if(m_List[ii].pname[0]==0){		//	ベースデータ
			search_combination(ii);
			continue;
		}
*/
		if(m_List[ii].oname[0] == 0)	continue;
		fit_picture( m_List[ii].oname, m_List[ii].bname, m_List[ii].pname, m_List[ii].px, m_List[ii].py );
	}
	
	//	リストを出力
	out_filelist( sName );
	
	return TRUE;
}


//		
int		FITPARTS::func_rev( LPCTSTR _sParamString )
{
	CSwbParam	cParam( _sParamString );							///< パラメータ処理.

	char	*mem=NULL;
	int		ii,len;
	LPCTSTR	sName, sPath1, sPath2;
	
	
	/// 引数の取り出し.
	sName   = cParam.GetPath();		///< ターゲットファイル (GetFilePath(0)としても同じ).
	sPath1  = cParam.GetOutPath();
	sPath2  = cParam.GetString( 2 );
	
	
	if(m_bImplemented == TRUE )	return TRUE;	//１回だけ
	
	len = MEM_TargetRead(&mem, sName );
	if(len == 0)	return FALSE;
	m_bImplemented = TRUE;	//	実行済みフラグ
	
	STRING_cpy( m_cDataPath, sPath1 );
	STRING_cpy( m_cOutPath,  sPath2 );
	
	//	リスト読み込み
	Message_win( TEXT("searching...") );
	set_filelist(mem,len,1);
	
	mem_del(mem);
	
	Message_win( TEXT("outing") );
	//	重ね
	for(ii=0 ; ii<m_iLEntry ; ii++){
		if(m_List[ii].oname[0] == 0)	continue;
		
		rev_picture(ii);
		
	}
	
	//	リストを出力
	out_filelist( sName );
	
	return TRUE;
}




//		フィットする場所を探す
int		FITPARTS::locate( LPCTSTR basename, LPCTSTR partsname, int *ax, int *ay, int optimize, int fitparam )
{
	u_int	x, y, sx, sy, len, sa;
	float	ag, agreement, max;
	char	*mem, *mem_base, *mem_parts;
	BMPINFO bmp_base, bmp_parts;
	DWORD	col1, col2;
	int		r1, g1, b1, r2, g2, b2;
	DWORD	*ctbl1, *ctbl2;
	
	
	mem = mem_base = NULL;
	len = MEM_TargetRead( &mem, dpath(basename) );
	if(len==0)	return 0;
	len = BMP_to32RGB( mem, &mem_base );
	mem_del(mem);
	bmp_base = BMP_GetRECTinfo(mem_base);
	
	mem = mem_parts = NULL;
	len = MEM_TargetRead( &mem, dpath(partsname) );
	if(len==0)	return 0;
	len = BMP_to32RGB( mem, &mem_parts );
	mem_del(mem);
	bmp_parts = BMP_GetRECTinfo(mem_parts);
	
	
	if(bmp_base.Width == bmp_parts.Width && bmp_base.Height == bmp_parts.Height)	return 0;
	if(bmp_base.Width < bmp_parts.Width || bmp_base.Height < bmp_parts.Height)		return 0;
	
	ctbl1 = ctbl2 = NULL;
	mem_alloc(DWORD,ctbl1,bmp_base.Width*bmp_base.Height);
	for(y=0 ; y<bmp_base.Height ; y++)
		for(x=0 ; x<bmp_base.Width ; x++)
			ctbl1[y*bmp_base.Width+x] = BMP_getpixel(&bmp_base,x,y);
	
	mem_alloc(DWORD,ctbl2,bmp_parts.Width*bmp_parts.Height);
	for(y=0 ; y<bmp_parts.Height ; y++)
		for(x=0 ; x<bmp_parts.Width ; x++)
			ctbl2[y*bmp_parts.Width+x] = BMP_getpixel(&bmp_parts,x,y);
	
	if(mask_col != NO_MASK){
		mask_col = BMP_getpixel(&bmp_base,0,0);	//マスクカラー応急
		
		//	判定するための総ドット数
		max = 0;
		for(y=0 ; y<bmp_parts.Height ; y++)
			for(x=0 ; x<bmp_parts.Width ; x++)
				if(ctbl2[y*bmp_parts.Width+x] != mask_col)	max++;
	}else{
		max = (float)(bmp_parts.Width*bmp_parts.Height);
	}
	
	//	前回と大きさが同じなら同じ場所をまず照合してみる
	if(m_iOldw == (int)bmp_parts.Width && m_iOldh == (int)bmp_parts.Height){	//	前回のものと大きさが同じだ
		ag = 0.f;
		for(sy=0 ; sy<bmp_parts.Height ; sy++){
			for(sx=0 ; sx<bmp_parts.Width ; sx++){
				col1 = ctbl1[(*ay+sy)*bmp_base.Width+(*ax+sx)];
				col2 = ctbl2[(sy)*bmp_parts.Width+(sx)];
				
				if(col1 == col2)	ag++;
				else{
					//	あいまい検証
					r1 = GetRValue(col1);
					g1 = GetGValue(col1);
					b1 = GetBValue(col1);
					r2 = GetRValue(col2);
					g2 = GetGValue(col2);
					b2 = GetBValue(col2);
					
					sa = (255-abs(r1-r2)) + (255-abs(g1-g2)) + (255-abs(b1-b2));
					ag += (float)sa / 765.f;	//765 = (255+255+255)
				//	_printf("%d:%d,%d:%d,%d:%d  %d:%f%\n",r1,r2,g1,g2,b1,b2,sa,(float)sa / 765.f);
				}
			}
		#if 0
			//	最適化処理	同じ所を１度調べるだけだからいらないか
			if(optimize==1 && sy==0){
				if(ag < (float)bmp_parts.Width * (fitparam/100))	break;
			}
		#endif
		}
		
	 	if((int)(ag * 100.f / max) > fitparam){
			Message_printf( TEXT("%s  %d%"), partsname, (int)(ag * 100.f / max) );
			mem_del(ctbl1);
			mem_del(ctbl2);
			mem_del(mem_parts);
			mem_del(mem_base);
			return (int)(ag * 100.f / max);
		}
	}
	
	m_iOldw = bmp_parts.Width;
	m_iOldh = bmp_parts.Height;
	
	*ax = *ay = 0;
	agreement = 0.f;
	for(y=0 ; y<bmp_base.Height-bmp_parts.Height ; y++){
		for(x=0 ; x<bmp_base.Width-bmp_parts.Width ; x++){
			
			ag = 0.f;
			for(sy=0 ; sy<bmp_parts.Height ; sy++){
				for(sx=0 ; sx<bmp_parts.Width ; sx++){
					col1 = ctbl1[(y+sy)*bmp_base.Width+(x+sx)];
					col2 = ctbl2[(sy)*bmp_parts.Width+(sx)];
					
					if(mask_col != col2){
						if(col1 == col2)	ag++;
						else{
							//	あいまい検証
							r1 = GetRValue(col1);
							g1 = GetGValue(col1);
							b1 = GetBValue(col1);
							r2 = GetRValue(col2);
							g2 = GetGValue(col2);
							b2 = GetBValue(col2);
							
							sa = (255-abs(r1-r2)) + (255-abs(g1-g2)) + (255-abs(b1-b2));
							ag += (float)sa / 765.f;	//765 = (255+255+255)
							
						//	_printf("%d:%d,%d:%d,%d:%d  %d:%f%\n",r1,r2,g1,g2,b1,b2,sa,(float)sa / 765.f);
							
						}
					}
				}
				
				//	最適化処理
				if(optimize==1 && sy==0){
					if(ag < (float)bmp_parts.Width * (fitparam/100))	break;
				}
				
			}
			
			if(ag > agreement){	//最も適合する位置と数値を更新
				agreement = ag;
				*ax = x;
				*ay = y;
				if(agreement >= max){
					x = bmp_parts.Width;
					y = bmp_parts.Height;
				}
			}
			
		}
	}
	
	Message_printf( TEXT("%s %d,%d  (%d:%d)%d%"), partsname, *ax, *ay, (int)agreement, (int)max, (int)(agreement * 100.f / max) );
//	_printf("%s %s %d,%d  %d/%d",basename,partsname,*ax,*ay,(int)agreement,(int)max);
	
	mem_del(ctbl1);
	mem_del(ctbl2);
	
	mem_del(mem_parts);
	mem_del(mem_base);
	
	return (int)(agreement * 100.f / max);
}


//		重ねたデータを作成
int		FITPARTS::fit_picture( LPCTSTR outname, LPCTSTR basename, LPCTSTR partsname, int ax, int ay )
{
	char	*mem, *mem_base, *mem_parts;
	BMPINFO bmp_base, bmp_parts;
	u_int	x, y, len, len2;
	
	
	mem = mem_base = NULL;
	len = MEM_TargetRead( &mem, dpath(basename) );
	if(len==0)	return 0;
	len = BMP_to32RGB( mem, &mem_base );
	mem_del(mem);
	bmp_base = BMP_GetRECTinfo(mem_base);
	
	
	if(partsname[0] != 0){
		mem = mem_parts = NULL;
		MEM_TargetRead( &mem, dpath(partsname) );
		len2 = BMP_to32RGB( mem, &mem_parts );
		mem_del(mem);
		bmp_parts = BMP_GetRECTinfo(mem_parts);
		
		
		for(y=0 ; y<bmp_parts.Height ; y++)
			for(x=0 ; x<bmp_parts.Width ; x++){
				if((x+ax)<0 || (y+ay)<0 || (x+ax) >= bmp_base.Width || (y+ay) >= bmp_base.Height)	continue;
				
				if(mask_col == NO_MASK){
					BMP_setpixel(&bmp_base,ax+x,ay+y,BMP_getpixel(&bmp_parts,x,y));
				}else{
					if(mask_col != BMP_getpixel(&bmp_parts,x,y))
						BMP_setpixel(&bmp_base,ax+x,ay+y,BMP_getpixel(&bmp_parts,x,y));
				}
				
			}
		
		mem_del(mem_parts);
	}
	
	file_targetwrite(opath(outname),mem_base,len);
	
	mem_del(mem_base);
	
	return 1;
}


int		FITPARTS::get_basenum(int ii)
{
	while(m_List[ii].pname[0]!=0 && ii>0)	ii--;
	
	return ii;
}

//		
int		FITPARTS::rev_picture(int ii)
{
	char	*fmem,*nmem;
	BMPINFO fbmp,nbmp;
	int		iLen,iNLen,iBs,x,y,w,h;
	float	fPw,fPh;
	
	
	fmem = NULL;
	iLen = MEM_TargetRead(&fmem,opath(m_List[ii].oname));
	if(iLen==0)	return 0;
	fbmp = BMP_GetRECTinfo(fmem);
	
	if(m_List[ii].pname[0] == 0){	//^ベースだ
		file_targetwrite( dpath(m_List[ii].bname),fmem,iLen);
		mem_del(fmem);
		return 1;
	}
	
	
	iBs = get_basenum(ii);
	fPw = (float)fbmp.Width / (float)m_List[iBs].w;
	fPh = (float)fbmp.Height / (float)m_List[iBs].h;
	
	w = (int)(m_List[ii].w *fPw);
	h = (int)(m_List[ii].h *fPh);
	
	Message_printf( TEXT("%d%%,%d%%"), (int)(fPw * 100.f), (int)(fPh * 100.f) );
	
	iNLen = BMP_Create( &nmem, w,h, 32, 72,72);
	if(iNLen<=0)	return FALSE;
	nbmp = BMP_GetRECTinfo(nmem);
	
	for(y=0 ; y<h ; y++)
		for(x=0 ; x<w ; x++)
			BMP_setpixel( &nbmp, x, y, BMP_getpixel( &fbmp, (int)(m_List[ii].px *fPw)+x, (int)(m_List[ii].py *fPh)+y ));
	
	
	file_targetwrite( dpath(m_List[ii].pname),nmem,iNLen);
	
	mem_del(nmem);
	mem_del(fmem);
	
	//	
	m_List[ii].px = (int)(m_List[ii].px *fPw);
	m_List[ii].py = (int)(m_List[ii].py *fPh);
//	m_List[ii].w = w;
//	m_List[ii].h = h;
	
	return 1;
}


LPCTSTR		FITPARTS::dpath(LPCTSTR path){
	STRING_cpy(m_cDWork,m_cDataPath);
	catyen(m_cDWork);
	STRING_cat(m_cDWork,path);
	return m_cDWork;
}
LPCTSTR		FITPARTS::opath(LPCTSTR path){
	STRING_cpy(m_cDWork,m_cOutPath);
	catyen(m_cDWork);
	STRING_cat(m_cDWork,path);
	return m_cDWork;
}


FITPARTS	*pC_fparts = NULL;
