
#pragma once

#include <windows.h>

#include <list>
#include <string>
#include <fstream>
#include <sstream>

#include "CBitMap.h"

using namespace std;

class RgbColor
{
	BYTE	Red;
	BYTE	Green;
	BYTE	Blue;
public:
	explicit RgbColor()
		: Red( 0), Green( 0), Blue( 0) {}
	explicit RgbColor( const BYTE red, const BYTE green, const BYTE blue)
		: Red( red), Green( green), Blue( blue) {}
	RgbColor( const RgbColor &rhs)
		: Red( rhs.Red), Green( rhs.Green), Blue( rhs.Blue){}

	BYTE GetRed() const{ return Red;}
	BYTE GetGreen() const{ return Green;}
	BYTE GetBlue() const{ return Blue;}

	const RgbColor & operator +=( const RgbColor &rhs)
	{
		this->Red += rhs.Red;
		this->Green += rhs.Green;
		this->Blue += rhs.Blue;
		return *this;
	}

	RgbColor operator +( const RgbColor &rhs) const
	{
		RgbColor	tmp( *this);
		tmp += rhs;
		return tmp;
	}

	// スカラー倍
	const RgbColor &operator *=( const int rhs)
	{
		this->Red *= rhs;
		this->Green *= rhs;
		this->Blue *= rhs;
		return *this;
	}
	RgbColor operator *( const int rhs) const
	{
		RgbColor	tmp( *this);
		tmp *= rhs;
		return tmp;
	}

	const RgbColor &operator /=( const int rhs)
	{
		this->Red /= rhs;
		this->Green /= rhs;
		this->Blue /= rhs;
		return *this;
	}
	RgbColor operator /( const int rhs) const
	{
		RgbColor tmp( *this);
		tmp /= rhs;
		return tmp;
	}

	bool operator ==( const RgbColor &rhs) const
	{
		return this->Red == rhs.Red && this->Green == rhs.Green && this->Blue == rhs.Blue;
	}
	bool operator !=( const RgbColor &rhs) const
	{
		return !( *this == rhs);
	}

	const RgbColor &operator >>=( const int rhs)
	{
		this->Red >>= rhs;
		this->Green >>= rhs;
		this->Blue >>= rhs;
		return *this;
	}
	RgbColor operator >>( const int rhs) const
	{
		RgbColor tmp( *this);
		tmp >>= rhs;
		return tmp;
	}

	const RgbColor &operator <<=( const int rhs)
	{
		this->Red <<= rhs;
		this->Green <<= rhs;
		this->Blue <<= rhs;
		return *this;
	}
	RgbColor operator <<( const int rhs) const
	{
		RgbColor tmp( *this);
		tmp <<= rhs;
		return tmp;
	}

	// 色の差の二乗和を返す
	int Distance( const RgbColor &rhs) const
	{
		int Sub   = this->Red - rhs.Red;
		int Total = Sub * Sub;
		Sub    = this->Green - rhs.Green;
		Total += Sub * Sub;
		Sub    = this->Blue - rhs.Blue;
		Total += Sub * Sub;

		return Total;
	}

};

// このパレットを使用している画素の座標
class PixelCoordinates
{
	int	m_x;
	int	m_y;
public:
	explicit PixelCoordinates( const int x, const int y)
		: m_x( x), m_y( y) {}

	PixelCoordinates( const PixelCoordinates &rhs)
		: m_x( rhs.m_x), m_y( rhs.m_y) {}

	int x() const { return m_x;}
	int y() const { return m_y;}

	// mergeメソッドのためだけ・・・
	bool operator <( const PixelCoordinates &rhs) const
	{
		return true;
	}
};


typedef list< PixelCoordinates> PixelList;

// パレット中の一色分のデータ
class PaletteCell
{
	RgbColor		m_Color;
	PixelList	m_PixelList;
public:
	explicit PaletteCell(){}
	explicit PaletteCell( const RgbColor &Color): m_Color( Color){}
	explicit PaletteCell( const RgbColor &Color, const PixelCoordinates &Pixel): m_Color( Color)
	{
		m_PixelList.push_back( Pixel);
	}
	explicit PaletteCell( const RgbColor &Color, const PixelList &Pixel): m_Color( Color), m_PixelList( Pixel){}

	RgbColor GetColor() const { return m_Color;}
	PixelList GetPixelList() const { return m_PixelList;}
	int GetPixelListSize() const { return m_PixelList.size();}

	// 中間色を作成する
	RgbColor NaturalColor( const PaletteCell &rhs) const
	{
// 値がオーバーフローするのでintとして取り出して処理
		DWORD tmpsCl = m_Color.GetRed();
		DWORD tmprCl = rhs.m_Color.GetRed();
		DWORD dest[ 3];
		dest[ 0] = ( tmpsCl * rhs.m_PixelList.size() + tmprCl * m_PixelList.size()) /
			( m_PixelList.size() + rhs.m_PixelList.size());
		tmpsCl = m_Color.GetGreen();
		tmprCl = m_Color.GetGreen();
		dest[ 1] = ( tmpsCl * rhs.m_PixelList.size() + tmprCl * m_PixelList.size()) /
			( m_PixelList.size() + rhs.m_PixelList.size());
		tmpsCl = m_Color.GetBlue();
		tmprCl = m_Color.GetBlue();
		dest[ 2] = ( tmpsCl * rhs.m_PixelList.size() + tmprCl * m_PixelList.size()) /
			( m_PixelList.size() + rhs.m_PixelList.size());

		_ASSERT( dest[ 0] < 256);
		_ASSERT( dest[ 1] < 256);
		_ASSERT( dest[ 2] < 256);

		return RgbColor( dest[ 0], dest[ 1], dest[ 2]);


//		return ( m_Color * rhs.m_PixelList.size() + rhs.m_Color * m_PixelList.size()) /
//			( m_PixelList.size() + rhs.m_PixelList.size());
	}
	// パレットを結合する
	// 指定されたパレットとの中間色を作成して結合する
	// そのとき指定されたパレットの画素リストもmergeするので，要素数はなくなる
	void Merge( PaletteCell *rhs)
	{
		m_Color = NaturalColor( *rhs);
//		rhs->m_Color = 0;	// 色を削除する
		m_PixelList.merge( rhs->m_PixelList);
	}

	// パレットの色を比べる
	bool CompareColor( const RgbColor &rhs) const
	{
		return m_Color == rhs;
	}
	bool CompareColor( const PaletteCell &rhs) const
	{
		return CompareColor( rhs.m_Color);
	}

	void AddPixelCoordinates( const PixelCoordinates &rhs)
	{
		m_PixelList.push_back( rhs);
	}
	void AddPixelList( const PixelList &rhs)
	{
		for ( PixelList::const_iterator i = rhs.begin(); i != rhs.end(); ++i)
			m_PixelList.push_back( *i);
	}
	void AddPixelList( const PaletteCell &rhs)
	{
		AddPixelList( rhs.m_PixelList);
	}
};


typedef list< PaletteCell> Palette;


typedef list< Palette> PaletteList;


void MakeFont( const char *infile, const char *outfile);
void MakeFontChips( const char *infile, const char *outfile);

void CreateFontFromPaletteBmp( BYTE *bmp, const Palette &SourcePalette, const int width, const int height);

void CreatePalette( Palette &DestinationPalette, unsigned char *bmp, const int width, const int height);
void CreatePaletteCips( Palette &DestinationPalette, unsigned char *bmp, const int width, const int height,
					   int x, int y, int square);
int SearchMinimumDistance( Palette::iterator begin, Palette::iterator end,
								  Palette::iterator &first, Palette::iterator &second);

// 指定パレットの色を減色する
// カラー数を指定
void ReducePalette( Palette &palette, const int color);

// パレットから，指定の色をもつパレットを探す
Palette::iterator FindColor( Palette::iterator first, Palette::iterator last, const RgbColor &Target);
Palette::const_iterator FindColor( Palette::const_iterator first, Palette::const_iterator last, const RgbColor &Target);

void AddPixelList( PixelList &dest, const PixelList &source);

// パレット数複数のとき
void CreatePaletteCips( Palette &DestinationPalette, unsigned char *bmp, const int width, const int height,
					   int x, int y, int square = 8);
PaletteList::iterator SearchIncludedPalette( PaletteList &List, const Palette &tmpPalette);





// 似通ったパレットを探すときに使う
class ColorVector
{
private:
	DWORD	Red;
	DWORD	Green;
	DWORD	Blue;
public:
	ColorVector() : Red( 0), Green( 0), Blue( 0) {}
	ColorVector( const RgbColor &rhs)
		: Red( rhs.GetRed()), Green( rhs.GetGreen()), Blue( rhs.GetBlue()) {}

	ColorVector operator =( const ColorVector &rhs)
	{
		Red = rhs.Red; Green = rhs.Green; Blue = rhs.Blue;
		return *this;
	}

	// ベクトルの加重平均を求める
	ColorVector WeightedMean( const int weight, const ColorVector &rhs, const int rhsweight)
	{
		ColorVector tmp;
		int sum = weight + rhsweight;
		tmp.Red = ( this->Red * rhsweight + rhs.Red * weight) / sum;
		tmp.Green = ( this->Green * rhsweight + rhs.Green * weight) / sum;
		tmp.Blue = ( this->Blue * rhsweight + rhs.Blue * weight) / sum;
		return tmp;
	}

	// ベクトル間の距離の平方数を返す
	DWORD DisVector( const ColorVector &rhs)
	{
		int sub = this->Blue - rhs.Blue;
		DWORD out = sub * sub;
		sub = this->Green - rhs.Green;
		out += sub * sub;
		sub = this->Red - rhs.Red;
		out += sub * sub;
		return out;
	}

};


ColorVector MakeVector( Palette::const_iterator begin, Palette::const_iterator end);
DWORD SerchMinimumPalette( PaletteList::iterator *first, PaletteList::iterator *second, PaletteList &Source);

void MergePalette( Palette &lhs, Palette &rhs);
void AddPalette( Palette &lhs, const Palette &rhs);
bool ComparePaletteColor( const Palette &lhs, const Palette &rhs);
bool PaletteIncluded( const Palette &lhs, const Palette &rhs);
PaletteList::iterator SearchSameColorPalette( PaletteList &List, const Palette &tmpPalette);
PaletteList::iterator SearchIncludedPalette( PaletteList &List, const Palette &tmpPalette);

int FindNearColorDistance( Palette::const_iterator begin, Palette::const_iterator end, const RgbColor &Target);

int PaletteDistance( Palette::const_iterator lhs_begin, Palette::const_iterator lhs_end,
						 Palette::const_iterator rhs_begin, Palette::const_iterator rhs_end);


void CreateFontFromPaletteText( ofstream &File, const Palette &SourcePalette, const int width, const int height);
void CreateFontFromPaletteChipsText( ofstream &File, const PaletteList &PalList, const int width, const int height);
void CheckBlock( char *buf, Palette::const_iterator begin, Palette::const_iterator end, const char value, const int MaxX, const int MaxY);

DWORD SerchMinimumPaletteSlow( PaletteList::iterator *first, PaletteList::iterator *second, PaletteList &Source);
void WriteBuffer( ofstream &out, const char *buf, const int width, const int height);


