module y4d_draw.drawbase;

private import std.string;

///	矩形を表している構造体
/**
	ただし、この矩形は、(left,top)を含み、(right,bottom)は
	含まないものとする。
*/
struct Rect {
	float	left   = 0.0;	//!< 左
	float	top	   = 0.0;	//!< 上
	float	right  = 0.0;	//!< 右
	float	bottom = 0.0;	//!< 下

	///	各データを設定する
	void setRect(float left_,float top_,float right_,float bottom_)	{
		left = left_;
		top  = top_;
		right = right_;
		bottom = bottom_;
	}

	/// 幅を取得する
	/**
		left - right をしているだけ。符号がマイナスになる場合もありうる。
	*/
	float getWidth() { return right - left; }

	///	高さを取得する
	/**
		bottom - top をしているだけ。符号がマイナスになる場合もありうる。
	*/
	float getHeight() { return bottom - top; }

	/// デバッグ用
	char[] toString() {
		char[] buffer;
		buffer ~= "left=" ~ std.string.toString(left);
		buffer ~= "top=" ~ std.string.toString(top);
		buffer ~= "right=" ~ std.string.toString(right);
		buffer ~= "bottom=" ~ std.string.toString(bottom);
		return buffer;
	}
}

struct RectInt {
	int	left   = 0;	//!< 左
	int	top	   = 0;	//!< 上
	int	right  = 0;	//!< 右
	int	bottom = 0;	//!< 下

	///	各データを設定する
	void setRect(int left_, int top_, int right_, int bottom_)	{
		left = left_;
		top  = top_;
		right = right_;
		bottom = bottom_;
	}

	/// 幅を取得する
	/**
		left - right をしているだけ。符号がマイナスになる場合もありうる。
	*/
	int getWidth() { return right - left; }

	///	高さを取得する
	/**
		bottom - top をしているだけ。符号がマイナスになる場合もありうる。
	*/
	int getHeight() { return bottom - top; }
	
	/// デバッグ用
	char[] toString() {
		char[] buffer;
		buffer ~= "left=" ~ std.string.toString(left);
		buffer ~= "top=" ~ std.string.toString(top);
		buffer ~= "right=" ~ std.string.toString(right);
		buffer ~= "bottom=" ~ std.string.toString(bottom);
		return buffer;
	}
}

///	サイズを表している構造体
struct Size {
	uint cx;	//!< 幅
	uint cy;	//!< 高さ

	///	各データを設定する
	void setSize(uint cx_,uint cy_){
		cx = cx_; cy = cy_;
	}
}

///	点を表している構造体
struct PointInt {
	int x = 0;		//!< x座標
	int y = 0;		//!< y座標

	///	各データを設定する
	void setPoint(int x_, int y_) {
		x = x_; y = y_;
	}
}

///	点を表している構造体
struct Point {
	float x = 0.0f;		//!< x座標
	float y = 0.0f;		//!< y座標

	///	各データを設定する
	void setPoint(float x_, float y_) {
		x = x_; y = y_;
	}
}

///	色
struct Color4ub {
	//	ディフォルトではr,g,b,a=255,255,255,255
	ubyte r=255,g=255,b=255,a=255; //!< 色情報

	///	色のリセット。r=g=b=a=255に。
	void resetColor() { r=g=b=a=255;}

	///	色のセット r,g,bは0～255。aは自動的に255になる。
	void	setColor(int r_,int g_,int b_) {
		r = cast(ubyte) r_; 
		g = cast(ubyte) g_; 
		b = cast(ubyte) b_; 
		a = 255;
	}

	///	色のセット r,g,b,aは0～255
	void	setColor(int r_,int g_,int b_,int a_) {
		setColor(r,g,b);
		a = cast(ubyte) a_;
	}

	///	色の掛け算
	Color4ub opMul(Color4ub color){
		Color4ub color_;
//		color_.r = r*color.r/255;
//	255で割るのは255足して256で割ればほぼ同じだ
/*
	詳しいことは、やね本2を見ること！
*/
		color_.r = cast(ubyte) ((r+255)*color.r >> 8);
		color_.g = cast(ubyte) ((g+255)*color.g >> 8);
		color_.b = cast(ubyte) ((b+255)*color.b >> 8);
		color_.a = cast(ubyte) ((a+255)*color.a >> 8);

		return color_;
	}
	
	/// 色情報の文字列表現を返却
	char[] toString() {
		return toString(r,g,b,a);
	}
	
	/// 色情報の文字列表現を返却
	static char[] toString(long rr, long gg, long bb, long aa) {
		static const uint RADIX = 16;
		char[] buffer = null;
		if (rr < RADIX) {
			buffer ~= "0";
		}
		buffer ~= std.string.toString(rr, RADIX);
		if (gg < RADIX) {
			buffer ~= "0";
		}
		buffer ~= std.string.toString(gg, RADIX);
		if (bb < RADIX) {
			buffer ~= "0";
		}
		buffer ~= std.string.toString(bb, RADIX);
		if (aa < RADIX) {
			buffer ~= "0";
		}
		buffer ~= std.string.toString(aa, RADIX);
		return buffer;
	}

	/// RRGGBB 文字列より、色情報を構築する
	/// 解析に失敗するとデフォルトカラー(255,255,255,255）が返る
	static Color4ub valueOf(char[] color) {
		Color4ub colorResult;
		if ( !(color is null) && color.length >= 6) {
			ubyte rr,gg,bb,aa=255;
			with (std.string) {
				// ごにょごにょする
				int index = 1;
				
				// 0..Fの文字から数値を逆引きして、それを８ビットにまとめて求める
				// そんな処理でいいかいな...
				if (color.length >= 8) {
					aa = cast(ubyte) find( hexdigits, color[length-index] );
					index++;
					aa |= (cast(ubyte) find( hexdigits, color[length-index] )) << 4;
					index++;
				}
				bb = cast(ubyte) find( hexdigits, color[length-index] );
				index++;
				bb |= (cast(ubyte) find( hexdigits, color[length-index] )) << 4;
				index++;
				
				gg = cast(ubyte) find( hexdigits, color[length-index] );
				index++;
				gg |= (cast(ubyte) find( hexdigits, color[length-index] )) << 4;
				index++;
				
				rr = cast(ubyte) find( hexdigits, color[length-index] );
				index++;
				rr |= (cast(ubyte) find( hexdigits, color[length-index] )) << 4;
				
			}
			colorResult.r = rr;
			colorResult.g = gg;
			colorResult.b = bb;
			colorResult.a = aa;
		}
		return colorResult;
	}
	
	unittest {
		assert( Color4ub.toString(0,0,0,0) == "00000000" );
		assert( Color4ub.toString(15,15,15,15) == "0F0F0F0F" );
	}

}

struct Color24 {
	ubyte r,g,b;
}
