#pragma once
#include<DxLib.h>
#include<vector>
#include<string>
#include<memory>
#define NULL_HANDLE -1

namespace DXFW
{
	
/// <summary>Zマスクの種類</summary>
enum class ZMaskType
{
	Clear = DX_ZWRITE_CLEAR,///
	Mask  = DX_ZWRITE_MASK,///
};

/// <summary>説明</summary>
enum class RGBA
{
	SrcR = DX_RGBA_SELECT_SRC_R,///
	SrcG = DX_RGBA_SELECT_SRC_G,///
	SrcB = DX_RGBA_SELECT_SRC_B,///
	SrcA = DX_RGBA_SELECT_SRC_A,///
	BlendR = DX_RGBA_SELECT_BLEND_R,///
	BlendG = DX_RGBA_SELECT_BLEND_G,///
	BlendB = DX_RGBA_SELECT_BLEND_B,///
	BlendA = DX_RGBA_SELECT_BLEND_A///
};

/// <summary>説明</summary>
enum class ClipType
{
	Less    = DX_CMP_LESS,///
	Greater = DX_CMP_GREATER///
};

///	<summary>画像クラス。ロードしたファイルの描画等。</summary>
///	<example>
///	[サンプルコード:未完成]<BR>
/// サンプル説明<BR>
///	<code>
///	int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )<BR>
///	{<BR>
///		Dx::Initialise();<BR>
///		Dx::End();<BR>
///		return 0;<BR>
/// }<BR>
/// </code>	
/// </example>
class Image
{
friend class Anime;
friend class ImagePack;

private:
	bool isScreen;
	bool isAlphaChannel;
	int handle;
	bool isTrans;

	int width;
	int height;
	Image(int handle):
		handle(handle),
		isTrans(true),
		isAlphaChannel(false),
		isScreen(false)	
	{
		DxLib::GetGraphSize( this->GetHandle() , &width , &height );
	}
public:
	Image():
		handle(NULL_HANDLE),
		isTrans(true),
		isAlphaChannel(false),
		isScreen(false),
		width(0),
		height(0)
	{};

	///<summary>画像をメモリへ読み込む</summary>
	Image(const char *ファイル名)
	{
		Image::Load(ファイル名);
	}

	/// <summary>空のイメージを作成</summary>
	Image(int 幅 ,int 高さ , bool 透過フラグ , bool スクリーン用フラグ , bool αチャンネルフラグ ):
		isTrans(透過フラグ),
		isScreen(スクリーン用フラグ),
		isAlphaChannel(αチャンネルフラグ)
	{
		if( スクリーン用フラグ )
		{
			this->handle = DxLib::MakeScreen( 幅 , 高さ , αチャンネルフラグ);
		}
		else
		{
			this->handle = DxLib::MakeGraph( 幅 , 高さ );
		}
		DxLib::GetGraphSize( this->GetHandle() , &幅 , &高さ );
	}

	/// <summary>画像をメモリへ読み込む</summary>
	bool Load(const char *ファイル名)
	{
		if( this->handle != NULL_HANDLE) DxLib::DeleteGraph(this->handle);
		this->handle = DxLib::LoadGraph(ファイル名);
		this->isTrans = true;
		this->isScreen = false;
				
		DxLib::GetGraphSize( this->GetHandle() , &width , &height );
		return ( this->handle != -1 );
	}

	/// <summary>イメージをメモリから開放</summary>
	bool Release()
	{
		return (DxLib::DeleteGraph(this->handle) == 0);
	}
			
	/// <summary>空のイメージを作成</summary>
	int Make(int width,int 高さ,bool isTrans = true ,bool isScreen = false , bool isAlphaChannel = true )
	{
		if( this->handle != NULL_HANDLE) DxLib::DeleteGraph(this->handle);
		if( isScreen )
		{
			this->handle = DxLib::MakeScreen( width , 高さ , isAlphaChannel);
		}
		else
		{
			this->handle = DxLib::MakeGraph( width , 高さ );
		}
		this->isTrans = isTrans;
		this->isScreen = isScreen;
		this->isAlphaChannel = isAlphaChannel;
		this->width = width;
		this->height = 高さ;

		return this->handle;
	}

	/// <summary>元イメージの一部をコピーして、別イメージを作成</summary>
	int Copy(const Image& img,int x , int y,int width,int 高さ)
	{
		this->handle = DxLib::DerivationGraph( x , y , width , 高さ , img.handle);
		this->isTrans = img.isTrans;
		this->isScreen = false;
		this->isAlphaChannel = false;
		this->width = width;
		this->height = 高さ;
		return this->handle;
	}

	/// <summary>ハンドルを取得</summary>
	int GetHandle() const
	{
		return this->handle;
	}
			
	/// <summary>指定座標に描画</summary>
	bool Draw(int X座標,int Y座標 , bool 反転フラグ = false) const
	{
		if( 反転フラグ )
		{
			return !DxLib::DrawTurnGraph( X座標 , Y座標 , this->GetHandle() , this->isTrans );
		}else{					
			return !DxLib::DrawGraph( X座標 , Y座標 , this->GetHandle() , this->isTrans );
		}
	}
	bool ZMask(int X座標,int Y座標 , ZMaskType Zマスクタイプ ,  bool 反転フラグ = false) const
	{
		if( 反転フラグ )
		{
			return !DxLib::DrawTurnGraphToZBuffer( X座標 , Y座標 , this->GetHandle() , (int)Zマスクタイプ );
		}else{
			return !DxLib::DrawGraphToZBuffer( X座標 , Y座標 , this->GetHandle() , (int)Zマスクタイプ );
		}
	}	

	/// <summary>指定矩形内に描画</summary>
	bool DrawExtend(int X座標A,int Y座標A,int X座標B,int Y座標B ) const
	{
		return !DxLib::DrawExtendGraph( X座標A, Y座標A, X座標B, Y座標B , this->GetHandle() , this->isTrans );			
	}
	bool ZMaskExtend(int X座標A,int Y座標A,int X座標B,int Y座標B  , ZMaskType Zマスクタイプ) const
	{
		return !DxLib::DrawExtendGraphToZBuffer( X座標A, Y座標A, X座標B, Y座標B , this->GetHandle() , (int)Zマスクタイプ );
	}
		
	/// <summary>角度、拡大率を指定して描画</summary>
	bool DrawRotate(int x,int y,double 拡大率,double 角度,bool 反転フラグ = false ) const
	{
		return !DxLib::DrawRotaGraph( x , y , 拡大率 , 角度 , this->GetHandle() , this->isTrans , 反転フラグ );
	}
	bool DrawRotateZMask(int x,int y,double 拡大率,double 角度 , ZMaskType Zマスクタイプ ,bool 反転フラグ = false ) const
	{
		return !DxLib::DrawRotaGraphToZBuffer( x , y , 拡大率 , 角度 , this->GetHandle() , (int)Zマスクタイプ , 反転フラグ );
	}

	/// <summary>回転軸、角度、拡大率を指定して描画</summary>
	bool DrawRotateAxis(int x,int y,int X軸,int Y軸,double 拡大率,double 角度,bool 反転フラグ = false ) const
	{
		return !DxLib::DrawRotaGraph2( x , y , X軸 , Y軸 , 拡大率 , 角度 , this->GetHandle() , this->isTrans , 反転フラグ );
	}
	bool ZMaskRotateAxis(int x,int y,int X軸,int Y軸,double 拡大率,double 角度, ZMaskType Zマスクタイプ , bool 反転フラグ = false ) const
	{
		return !DxLib::DrawRotaGraph2ToZBuffer( x , y , X軸 , Y軸 , 拡大率 , 角度 , this->GetHandle() , (int)Zマスクタイプ , 反転フラグ );
	}

	/// <summary>回転軸、角度、拡大率を縦横別に指定して描画</summary>
	bool DrawRotateAxis(int x,int y,int X軸,int Y軸,double 拡大率X,double 拡大率Y,double 角度,bool 反転フラグ =false) const
	{	
		return !DxLib::DrawRotaGraph3( x , y , X軸 , Y軸 , 拡大率X , 拡大率Y , 角度 , this->GetHandle() , this->isTrans , 反転フラグ );
	}
	bool ZMaskRotateAxis(int x,int y,int X軸,int Y軸,double 拡大率X,double 拡大率Y,double 角度, ZMaskType Zマスクタイプ , bool 反転フラグ = false) const
	{
		return !DxLib::DrawRotaGraph3ToZBuffer( x , y , X軸 , Y軸 , 拡大率X , 拡大率Y , 角度 , this->GetHandle() , (int)Zマスクタイプ , 反転フラグ );
	}

	/// <summary>四角形に変形描画</summary>
	bool DrawModify(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4 ) const
	{
		return !DxLib::DrawModiGraph( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , this->GetHandle() , this->isTrans );
	}
	bool ZMaskModify(int x1,int y1,int x2,int y2,int x3,int y3,int x4,int y4 , ZMaskType Zマスクタイプ) const
	{
		return !DxLib::DrawModiGraphToZBuffer( x1 , y1 , x2 , y2 , x3 , y3 , x4 , y4 , this->GetHandle() , (int)Zマスクタイプ );
	}

	/// <summary>イメージの一部を指定して描画</summary>
	bool DrawPart(int destX,int destY,int srcX, int srcY, int 幅, int 高さ, bool 反転フラグ ) const
	{
		return !DxLib::DrawRectGraph( destX , destY , srcX , srcY , 幅 , 高さ , this->GetHandle() , this->isTrans , 反転フラグ );
	}
	bool ZMaskPart(int destX,int destY,int srcX, int srcY, int 幅, int 高さ , ZMaskType Zマスクタイプ , bool 反転フラグ = false) const
	{
		return !DxLib::DrawRectGraph( destX , destY , srcX , srcY , 幅 , 高さ , this->GetHandle() , (int)Zマスクタイプ , 反転フラグ );
	}

	///<summary>スクリーンの一部をイメージに取り込む</summary>
	///指定した座標を右上にして、スクリーンからImageと同じ大きさコピーする
	int LoadScreen(int x,int y)
	{
		int w,h;
		DxLib::GetGraphSize( this->GetHandle() , &w , &h );
		return DxLib::GetDrawScreenGraph( x , y , x + w , y + h , this->GetHandle() );
	}
			
	/// <summary>幅を取得</summary>
	int GetWidth() const
	{
		return width;
	}
			
	/// <summary>高さを取得</summary>
	int GetHeight() const
	{
		return height;
	}
			
	/// <summary>説明</summary>
	bool GetIsScreen() const
	{
		return this->isScreen;
	}
			
	/// <summary>αチャンネルフラグを取得</summary>
	bool GetIsAlphaChannel() const
	{
		return this->isAlphaChannel;
	}
			
	/// <summary>透過フラグを取得</summary>
	bool GetIsTrans() const
	{
		return this->isTrans;
	}
	
	///<summary>描画先にこのイメージに指定</summary>
	///Image::Makeでスクリーンフラグをtrueにした場合成功。
	bool SetDrawScreen()
	{
		if(this->isScreen)
		{
			return !DxLib::SetDrawScreen( this->GetHandle() );
		}
		return false;
	}
};
	
///	<summary>複数のImageをまとめるクラス</summary>
///	<example>
///	[サンプルコード:未完成]<br></br>
/// サンプル説明<br></br>
///	<code>
///	int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )<br></br>
///	{<br></br>
///		if( !Dx::Initialise() ) return -1;<br></br>
///		Dx::End();<br></br>
///		return 0;<br></br>
/// }<br></br>
/// </code>	
/// </example>
class ImagePack
{
protected:
	std::vector<Image*> images;
	int widthMax;
	int heightMax;
public:
	ImagePack():
		widthMax( 0 ),
		heightMax( 0 )
	{}
			
	///<summary>１つの画像を分割して読み込む</summary>
	ImagePack( const char *ファイル名 , int 総コマ数 , int コマ割り横,int コマ割り縦,int コマ幅,int コマ高さ )
	{
		ImagePack::Load(ファイル名,総コマ数 , コマ割り横, コマ割り縦 , コマ幅 , コマ高さ );

		int *buf = new int[総コマ数];

		if( DxLib::LoadDivGraph(ファイル名,総コマ数,コマ割り横,コマ割り縦,コマ幅,コマ高さ,buf) == 0 )
		{
			for(int i=0;i<総コマ数;i++)
			{
				this->Add( new Image(buf[i]) );
			}
		}

		delete [] buf;
	}

	///<summary>１つの画像を分割して読み込む</summary>
	///総コマ数=14,コマ割り横=4,コマ割り縦=4の場合
	///[ 0][ 1][ 2][ 3]
	///[ 4][ 5][ 6][ 7]
	///[ 8][ 9][10][11]
	///[12][13][  ][  ]
	///のように分割して、ImagePackのサイズは14になる
	virtual bool Load(const char *ファイル名 , int 総コマ数,int コマ割り横, int コマ割り縦 ,int コマ幅,int コマ高さ )
	{
		int *buf = new int[総コマ数];

		if( DxLib::LoadDivGraph(ファイル名,総コマ数,コマ割り横,コマ割り縦,コマ幅,コマ高さ,buf) == 0 )
		{
			for(int i=0;i<総コマ数;i++)
			{
				this->Add( new Image(buf[i]) );
			}
		}

		delete [] buf;
		return true;
	}

	///<summary>連番ファイルを一括して読み込む</summary>
	/// ファイル名の後に三桁の連番が付いたファイルを連続して読み込む
	/// 「ファイル名***.拡張子」
	virtual bool Load(const char *ファイル名 , const char *拡張子 , int 総コマ数 )
	{
		for(int i=0 ; i<総コマ数 ; i++)
		{ 
			char fileBuf[8];
			sprintf_s( fileBuf , 8 , "%03d." , i );

			std::string fileName = ファイル名;
			fileName += fileBuf;
			fileName += 拡張子;

			this->Add( new Image( fileName.c_str() ) );
		}
		return true;
	}
			
	///<summary>イメージを追加</summary>
	///イメージを末尾に追加する。
	virtual void Add(Image *追加イメージ)
	{
		images.push_back( 追加イメージ );
					
		this->widthMax  = max( this->widthMax  , 追加イメージ->GetWidth() );
		this->heightMax = max( this->heightMax , 追加イメージ->GetHeight() );
	}
	virtual void Add(const char *ファイル名)
	{
		Add( new Image( ファイル名 ) );
	}
			
	/// <summary>イメージをメモリから開放</summary>
	virtual void Release()
	{
		for( auto it : images)
		{
			it->Release();
		}

		images.clear();
	}
			
	/// <summary>要素数を取得</summary>
	int GetSize() const
	{
		return images.size();
	}
				
	/// <summary>最大幅を取得</summary>
	int GetWidth() const
	{
		return this->widthMax;
	}
			
	/// <summary>最大高さを取得</summary>
	int GetHeight() const
	{
		return this->heightMax;
	}
	
	Image* operator[](int index)
	{
		return images[index];
	}
};	
}