///<reference path="all.ts"/>
module jg {
	/**
	 * 図形を現すクラス。クリッピング領域の指定にも使える
	 */
	export class Shape extends E {
		/** Shapeの描画スタイル。塗りつぶすか外周かを指定。変更する際はsetStyleを利用 */
		style: ShapeStyle;
		/** Shapeの形状。円か四角 */
		type: ShapeType;
		/** 同期対象オブジェクト */
		syncObj: any;
		/** 同期処理を行う関数 */
		syncFunc: (shape: Shape) => void;
		/** Math.PI * 2 */
		static PI_200_PER: number = Math.PI * 2;
		/** クリッピング領域にするかどうかを指定。変更する場合はこのプロパティを直接操作せず、setClipメソッドを利用する */
		clip:boolean;

		/**
		 * 新しいShapeクラスを生成する
		 * @param width 横幅。
		 * @param height 縦幅。ShapeTypeがArcの場合無視される
		 * @param style Shapeの描画スタイル。デフォルトはShapeStyle.Stroke（線）
		 * @param color Shapeの色。デフォルトは黒
		 * @param type Shapeの形状。デフォルトはShapeType.Rect（四角）
		 */
		constructor(width:number, height:number, style?:ShapeStyle, color?:any, type?:ShapeType) {
			super();
			this.x = 0;
			this.y = 0;
			this.width = width;
			this.height = height;
			this.style = style ? style : ShapeStyle.Stroke;
			if (color)
				this.setColor(color);
			this.type = type ? type : ShapeType.Rect;
		}

		/**
		 * このオブジェクトをクリップモードにする。またはクリップモードを解除する。
		 * クリップモードとなったShapeは描画されず、以降に描画されるオブジェクトの描画領域を制限する。
		 */
		setClip(value:boolean) {
			this.clip = value;
			if (this.clip)
				this.disableTransform = true;
			else
				delete this.disableTransform;
		}

		/**
		 * Shapeの描画スタイルを変更する
		 */
		setStyle(style:ShapeStyle) {
			this.style = style;
			this.setColor(this.getColor());
		}

		/**
		 * Shapeの線の太さを変更する
		 */
		setLineWidth(width:number) {
			this.setDrawOption("lineWidth", width);
		}
		/**
		 * Shapeの線の太さを取得する
		 */
		getLineWidth() {
			return this.getDrawOption("lineWidth");
		}

		/**
		 * Shapeの色を指定する
		 * @param color 指定する色。CSS Color形式やグラデーションなどで指定
		 */
		setColor(color:any) {
			if (this.style == ShapeStyle.Stroke)
				this.setDrawOption("strokeStyle", color);
			else
				this.setDrawOption("fillStyle", color);
		}
		/**
		 * Shapeの色を取得する
		 */
		getColor() {
			if (this.style == ShapeStyle.Stroke)
				return this.getDrawOption("strokeStyle");
			else
				return this.getDrawOption("filltyle");
		}

		/**
		 * このShapeを特定のオブジェクトに同期させる
		 * @param syncObj 同期するオブジェクト。
		 * @param syncFunc 同期に利用する関数。例えばこの関数内でshape.x = this.xなどとやれば、ShapeのX座標は常に同期する
		 */
		synchronize(syncObj:any, syncFunc:(shape:Shape) => void) {
			this.syncObj = syncObj;
			this.syncFunc = syncFunc;
		}

		draw(context:CanvasRenderingContext2D) {
			//arc, rect
			//style: fill, stroke
			if (this.syncObj)
				this.syncFunc.call(this.syncObj, this);
			if (this.clip) {
				//bad code. 回転などをサポートするための苦肉の処置
				context.save();
				context.translate(this.x, this.y);
				if (this.options)
					this.scene.game.renderer.useDrawOption(this, context);
			}
			context.beginPath();
			switch(this.type) {
				case ShapeType.Rect:
					context.rect(
						0,
						0,
						this.width,
						this.height
					);
					break;
				case ShapeType.Arc:
					var w2 = this.width / 2;
					context.arc(
						w2,
						w2,
						w2,
						0,
						Shape.PI_200_PER,
						false
					);
					break;
			}

			if (this.clip) {
				context.restore();
				context.clip();
			} else if (this.style == ShapeStyle.Fill)
				context.fill();
			else
				context.stroke();
		}
	}
}