package com.yems.painter.control;

import java.util.List;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.util.Log;
import android.view.SurfaceHolder;

import com.yems.painter.common.Commons;
import com.yems.painter.entity.BrushPreset;
import com.yems.painter.entity.UndoState;
import com.yems.painter.serializable.SerializablePaint;
import com.yems.painter.serializable.SerializablePath;
import com.yems.painter.serializable.ShapeRepositories;

/**
 * @description: ¸ºÔð»­°å»æÖÆµÄÏß³Ì
 * @date: 2015-3-11 ÏÂÎç4:47:19
 * @author: yems
 */
public class PainterThreadControl extends Thread {
	private String TAG = "PainterThread";

	/** ¿ØÖÆsurfaceView½çÃæµÄÏÔÊ¾ */
	private SurfaceHolder mHolder;
	/** ×Ô¶¨Òå»­²¼ÊµÀý */
	PainterCanvasControl mPainterCanvas;
	/** »­±ÊÊµÀý¶ÔÏó */
	public Paint mBrush;
	/** »­±Ê³ß´ç */
	private float mBrushSize;
	/** ¼ÇÂ¼×îºó»­±ÊXÖáÎ»ÖÃµã£¬ÓÃÀ´Ïû³ý¾â³Ý */
	private int mLastBrushPointX;
	/** ¼ÇÂ¼×îºó»­±ÊYÖáÎ»ÖÃµã£¬ÓÃÀ´Ïû³ý¾â³Ý */
	private int mLastBrushPointY;
	/** »­²¼µÄ±³¾°É« */
	private int mCanvasBgColor;
	/** »æÖÆÍ¼ÐÎµÄ»­²¼ */
	private Canvas mCanvas;
	/** ÓÃÓÚ»º´æ»­²¼ÉÏ»æÖÆµÄÍ¼ÐÎ */
	private Bitmap mBitmap;
	/** ±êÊ¶µ±Ç°»æÖÆÏß³ÌÊÇ·ñ´¦ÓÚ¼¤»î×´Ì¬£¬tureÊÇ£»false·ñ */
	private boolean mIsActive;
	/** »­±ÊµÄÔËÐÐ×´Ì¬£¨ÐÝÃß¡¢×¼±¸¡¢ÉèÖÃ£© */
	private int mStatus;
	/** ³·ÏúÍ¼ÐÎ²Ù×÷µÄ¶ÔÏó */
	private UndoState mState;

	/**
	 * @param surfaceHolder
	 * @param painterCanvas
	 */
	public PainterThreadControl(SurfaceHolder surfaceHolder,
			PainterCanvasControl painterCanvas) {
		// base data
		mHolder = surfaceHolder;
		this.mPainterCanvas = painterCanvas;

		// defaults brush settings
		mBrushSize = 2;
		mBrush = new Paint();
		mBrush.setAntiAlias(true);
		mBrush.setColor(Color.rgb(0, 0, 0));
		mBrush.setStrokeWidth(mBrushSize);
		mBrush.setStrokeCap(Cap.ROUND);

		Commons.currentColor = Color.rgb(0, 0, 0);
		Commons.currentSize = 2;

		// default canvas settings
		mCanvasBgColor = Color.WHITE;

		// set negative coordinates for reset last point
		mLastBrushPointX = -1;
		mLastBrushPointY = -1;
	}

	@Override
	public void run() {
		waitForBitmap();

		while (isRun()) {
			Canvas canvas = null;
			try {
				canvas = mHolder.lockCanvas();
				synchronized (mHolder) {
					switch (mStatus) {
					case Commons.READY: {
						if (canvas != null) {
							canvas.drawBitmap(mBitmap, 0, 0, null);
						}
						break;
					}
					case Commons.SETUP: {
						if (canvas != null) {
							canvas.drawColor(mCanvasBgColor);
							canvas.drawLine(50,
									(mBitmap.getHeight() / 100) * 35,
									mBitmap.getWidth() - 50,
									(mBitmap.getHeight() / 100) * 35, mBrush);
						}
						break;
					}
					}
				}
			} finally {
				if (canvas != null) {
					mHolder.unlockCanvasAndPost(canvas);
				}
				if (isFreeze()) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	/**
	 * @return
	 * @description: »ñÈ¡µ±Ç°»­±Ê
	 * @date: 2015-3-16 ÏÂÎç2:11:47
	 * @author: yems
	 */
	public Paint getmBrush() {
		return mBrush;
	}

	/**
	 * @param bitmap
	 *            Òª»¹Ô­µ½»­°åÉÏµÄÍ¼Æ¬
	 * @param matrix
	 *            Ð¯´ø×ÅbitmapÐý×ªµÄ½Ç¶ÈÖµ
	 * @description: »¹Ô­Ö¸¶¨µÄbitmapÍ¼Æ¬µ½»­°åÉÏ
	 * @date: 2015-3-16 ÏÂÎç2:12:02
	 * @author: yems
	 */
	public void restoreBitmap(Bitmap bitmap, Matrix matrix) {
		mCanvas.drawBitmap(bitmap, matrix, new Paint(Paint.FILTER_BITMAP_FLAG));
	}

	/**
	 * @param preset
	 * @description: µ±»­±ÊµÄÑÕÉ«¡¢³ß´ç¸Ä±äÊ±µ÷ÓÃ¸Ãº¯Êý
	 * @date: 2015-3-16 ÏÂÎç2:15:14
	 * @author: yems
	 */
	public void setPreset(BrushPreset preset) {
		mBrush.setColor(preset.currentColor);
		mBrushSize = preset.currentSize;
		mBrush.setStrokeWidth(mBrushSize);
	}

	/**
	 * 
	 * @description: ¿ªÊ¼»æÖÆÇ°£¬Çå³ýÎ»ÖÃµãµÄ±ê¼ÇÖµ
	 * @date: 2015-3-16 ÏÂÎç2:15:58
	 * @author: yems
	 */
	public void clearBrushPoint() {
		mLastBrushPointX = -1;
		mLastBrushPointY = -1;
	}

	/**
	 * @param x
	 *            xÖá×ø±êÖµ
	 * @param y
	 *            yÖá×ø±êÖµ
	 * @description: »æÖÆÍ¼ÐÎ
	 * @date: 2015-3-12 ÉÏÎç11:17:26
	 * @author£º yems
	 */
	public void draw(int x, int y) {
		Log.i("paths", "mCanvas---" + mCanvas + ",mBrush--" + mBrush);
		if (mLastBrushPointX > 0) {
			if (mLastBrushPointX - x == 0 && mLastBrushPointY - y == 0) {
				return;
			}
			if (mCanvas == null) {
				// µÚÒ»´Î½øÈëAPP£¬ÓÉÓÚÏµÍ³Surface´´½¨µÄÑÓÊ±ÐÔ£¬´ËÊ±mCanvas»¹Î´ÊµÀý»¯Íê³É£¬·þÎñ¶Ë·¢ËÍ¹ýÀ´µÄÊý¾Ý²»ÄÜÂíÉÏ»æÖÆ
				try {
					sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				mCanvas.drawLine(x, y, mLastBrushPointX, mLastBrushPointY,
						mBrush);
			} else {
				mCanvas.drawLine(x, y, mLastBrushPointX, mLastBrushPointY,
						mBrush);
			}

		} else {
			if (mCanvas == null) {
				// µÚÒ»´Î½øÈëAPP£¬ÓÉÓÚÏµÍ³Surface´´½¨µÄÑÓÊ±ÐÔ£¬´ËÊ±mCanvas»¹Î´ÊµÀý»¯Íê³É£¬·þÎñ¶Ë·¢ËÍ¹ýÀ´µÄÊý¾Ý²»ÄÜÂíÉÏ»æÖÆ
				try {
					sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				mCanvas.drawCircle(x, y, mBrush.getStrokeWidth() * .5f, mBrush);
			} else {
				mCanvas.drawCircle(x, y, mBrush.getStrokeWidth() * .5f, mBrush);
			}
		}
		mLastBrushPointX = x;
		mLastBrushPointY = y;
	}

	/**
	 * @param bitmap
	 *            Òª¼ÓÔØµÄ±³¾°Í¼
	 * @param clear
	 *            true ±íÊ¾ÏÈÇå³ý»­°åÔÚ¼ÓÔØ±³¾°Í¼£¬false±íÊ¾Ö±½Ó¼ÓÔØ±³¾°Í¼
	 * @description: ÉèÖÃµ±Ç°»­°åµÄ±³¾°
	 * @date: 2015-3-16 ÏÂÎç2:19:11
	 * @author: yems
	 */
	public void setBitmap(Bitmap bitmap, boolean clear) {
		mBitmap = bitmap;
		if (clear) {
			mBitmap.eraseColor(mCanvasBgColor);
		}
		mCanvas = new Canvas(mBitmap);
	}

	/**
	 * 
	 * @description: Çå³ý»­°åËùÓÐÍ¼ÐÎÊý¾Ý
	 * @date: 2015-3-16 ÏÂÎç2:19:25
	 * @author: yems
	 */
	public void clearBitmap() {
		mBitmap.eraseColor(mCanvasBgColor);
		if (ShapeRepositories.getInstance().getUndoCaches().size() != 0) {
			ShapeRepositories.getInstance().getUndoCaches().clear();
		}
		Commons.lastLocalPath = null;
		Commons.lastRemotePath = null;
	}

	/**
	 * @return
	 * @description: »ñÈ¡µ±Ç°»æÖÆµÄÍ¼ÐÎ
	 * @date: 2015-3-16 ÏÂÎç2:19:48
	 * @author: yems
	 */
	public Bitmap getBitmap() {
		return mBitmap;
	}

	/**
	 * 
	 * @description: ±íÊ¾¿ªÆô»æÖÆÏß³Ì
	 * @date: 2015-3-16 ÏÂÎç2:23:24
	 * @author: yems
	 */
	public void on() {
		mIsActive = true;
	}

	/**
	 * 
	 * @description: ±íÊ¾¹Ø±Õ»æÖÆÏß³Ì
	 * @date: 2015-3-16 ÏÂÎç2:23:42
	 * @author: yems
	 */
	public void off() {
		mIsActive = false;
	}

	/**
	 * 
	 * @description: ±íÊ¾ÐÝÃß£¨ÔÝÍ££©»æÖÆÏß³Ì
	 * @date: 2015-3-16 ÏÂÎç2:24:12
	 * @author: yems
	 */
	public void freeze() {
		mStatus = Commons.SLEEP;
	}

	/**
	 * 
	 * @description: ±íÊ¾»æÖÆÏß³ÌÒÑ¾­×¼±¸ºÃ£¬¿ÉÒÔ»æÖÆÁË
	 * @date: 2015-3-16 ÏÂÎç2:24:29
	 * @author: yems
	 */
	public void activate() {
		mStatus = Commons.READY;
	}

	/**
	 * 
	 * @description: »­°å´¦ÓÚÉèÖÃ»­±Ê²ÎÊýµÄ×´Ì¬
	 * @date: 2015-3-16 ÏÂÎç2:25:26
	 * @author: yems
	 */
	public void setup() {
		mStatus = Commons.SETUP;
	}

	/**
	 * @return
	 * @description: ÅÐ¶Ï»­°åÊÇ·ñ´¦ÓÚ¶³½á£¨»æÖÆÏß³ÌÐÝÃß£©µÄ×´Ì¬
	 * @date: 2015-3-16 ÏÂÎç2:26:08
	 * @author: yems
	 */
	public boolean isFreeze() {
		return (mStatus == Commons.SLEEP);
	}

	/**
	 * @return
	 * @description: ÅÐ¶Ï»­°åÊÇ·ñ´¦ÓÚÉèÖÃ»­±Ê²ÎÊýµÄ×´Ì¬
	 * @date: 2015-3-16 ÏÂÎç2:27:31
	 * @author: yems
	 */
	public boolean isSetup() {
		return (mStatus == Commons.SETUP);
	}

	/**
	 * @return
	 * @description: ÅÐ¶Ï»­°åÊÇ·ñ´¦ÓÚ×¼±¸ºÃ»æÖÆµÄ×´Ì¬
	 * @date: 2015-3-16 ÏÂÎç2:27:34
	 * @author: yems
	 */
	public boolean isReady() {
		return (mStatus == Commons.READY);
	}

	/**
	 * @return
	 * @description: ÅÐ¶Ï»æÖÆÏß³ÌÊÇ·ñ´¦ÓÚÆô¶¯µÄ×´Ì¬
	 * @date: 2015-3-16 ÏÂÎç2:27:36
	 * @author: yems
	 */
	public boolean isRun() {
		return mIsActive;
	}

	/**
	 * 
	 * @description: ³·Ïú²Ù×÷£¨»Ö¸´ÉÏÒ»´ÎµÄÍ¼ÐÎÊý¾Ý£©
	 * @date: 2015-3-12 ÏÂÎç12:53:39
	 * @author£º yems
	 */
	public void undo() {
		int undoSize = ShapeRepositories.getInstance().getUndoCaches().size();
		if (undoSize != 0) {
			undoRepaint();
			// »Ö¸´Ò»´ÎÀúÊ·Êý¾Ý£¬¶ÔÓ¦¼¯ºÏÀï±£´æµÄÊý¾Ý¾ÍÒªÒÆ³ýµô£¬±ÜÃâÏÂ´ÎÖ´ÐÐ³·Ïú²Ù×÷Ê±£¬ÓÖ³öÏÖ¸ÃÍ¼ÐÎ
			ShapeRepositories.getInstance().getUndoCaches()
					.remove(undoSize - 1);

		} else {
			mBitmap.eraseColor(mCanvasBgColor);
			mPainterCanvas.changed(false);
			Commons.lastLocalPath = null;
			Commons.lastRemotePath = null;
		}
	}

	/**
	 * 
	 * @description: ³·Ïú²Ù×÷Ê±£¬ÖØ»æÖÆÍ¼ÐÎ
	 * @date: 2015-3-12 ÏÂÎç4:44:39
	 * @author£º yems
	 */
	private void undoRepaint() {
		mBitmap.eraseColor(mCanvasBgColor);
		repaintAllShapes(ShapeRepositories.getInstance().getUndoCaches());
	}

	/**
	 * @return
	 * @description: »ñÈ¡»­²¼µÄµ±Ç°±³¾°É«
	 * @date: 2015-3-16 ÏÂÎç2:32:51
	 * @author: yems
	 */
	public int getBackgroundColor() {
		return mCanvasBgColor;
	}

	/**
	 * @param state
	 * @description: ÉèÖÃ³·ÏúÍ¼ÐÎ²Ù×÷µÄ¶ÔÏó
	 * @date: 2015-3-16 ÏÂÎç2:33:20
	 * @author: yems
	 */
	public void setState(UndoState state) {
		this.mState = state;
	}

	/**
	 * 
	 * @description: µÈ´ý»­²¼±³¾°Í¼ÊµÀýµÄ´´½¨
	 * @date: 2015-3-16 ÏÂÎç2:35:01
	 * @author: yems
	 */
	private void waitForBitmap() {
		while (mBitmap == null) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 
	 * @description: Èç¹û¿Í»§¶ËÊÇµÚÒ»´ÎÁ¬½Óµ½·þÎñ¶Ë£¬Ôò»æÖÆÈ«²¿Í¼ÐÎ£»·ñÔòÖ»»æÖÆ×îºóÒ»¸ö
	 * @date: 2015-3-12 ÏÂÎç4:10:24
	 * @author£º yems
	 */
	public void repaintNewShape(List<SerializablePath> paths) {
		int size = paths.size();
		clearBrushPoint();

		// »ñÈ¡¼¯ºÏÖÐ×îºóÒ»¸öÍ¼ÐÎÊý¾Ý£¨·þÎñ¶Ë´«¹ýÀ´µÄ×îÐÂÍ¼ÐÎÊý¾Ý£©
		SerializablePath newSerializablePath = paths.get(size - 1);
		float srcScreenWidth = newSerializablePath.getScreenWidth();
		float srcScreenHeight = newSerializablePath.getScreenHeight();
		SerializablePaint serializablePaint = newSerializablePath
				.getSerializablePaint();

		updatePaintParams(serializablePaint);

		// ÔÚÆÁÄ»ÏñËØÏàÍ¬µÄÉè±¸ÉÏ»æÍ¼£¬²»ÓÃ×ª»»×ø±êÖµ
		if (checkScreenDisplay(srcScreenWidth, srcScreenHeight)) {
			int pointCount = newSerializablePath.points.size(); // Ã¿Ò»ÌõÂ·¾¶µÄ×é³ÉµÄµãÊý
			for (int j = 0; j < pointCount; j++) {
				int x = (int) newSerializablePath.points.get(j).getX();
				int y = (int) newSerializablePath.points.get(j).getY();
				draw(x, y);
			}
		} else {
			// ²»Í¬ÏñËØµÄÉè±¸ÉÏ»æÍ¼£¬ÐèÒª×ª»»×ø±êÖµ
			int pointCount = newSerializablePath.points.size(); // Ã¿Ò»ÌõÂ·¾¶µÄ×é³ÉµÄµãÊý
			for (int j = 0; j < pointCount; j++) {
				int x = (int) newSerializablePath.points.get(j).getX();
				int y = (int) newSerializablePath.points.get(j).getY();
				draw((int) (x * (Commons.CURRENT_SCREEN_WIDTH / srcScreenWidth)),
						(int) (y * (Commons.CURRENT_SCREEN_HEIGHT / srcScreenHeight)));
			}
		}
		clearBrushPoint();
		resetColorAndSize();
	}

	/**
	 * ÖØ»æÖÆËùÓÐµÄÍ¼ÐÎÊý¾Ý£¨µ±ÓÐÒ»¸öÐÂµÄ¿Í»§¶ËºóÐø½ÓÈëÍ¨µÀÊ±£¬·þÎñ¶ËÔ­ÓÐµÄÍ¼ÐÎÊý¾ÝÐèÒªÒ»´ÎÐÔÖØ»æÖÆµ½¸ÃÐÂ¿Í»§¶Ë£©
	 */
	public void repaintAllShapes(List<SerializablePath> paths) {
		// List<SerializablePath> paths = MetadataRepositories.getInstance()
		// .getBufferShapes();
		int size = paths.size();
		Log.i("paths", "ÖØ»æÖÆËùÓÐµÄÍ¼ÐÎÊý¾Ý£¬Í¼ÐÎÊýÄ¿Îª---" + size);

		for (int i = 0; i < paths.size(); i++) {
			clearBrushPoint();
			// ±éÀú»ñÈ¡¼¯ºÏÖÐÃ¿Ò»¸öÍ¼ÐÎÊý¾Ý£¨·þÎñ¶Ë´«¹ýÀ´µÄËùÓÐÍ¼ÐÎÊý¾Ý£©
			SerializablePath serializablePath = paths.get(i);
			float srcScreenWidth = serializablePath.getScreenWidth();
			float srcScreenHeight = serializablePath.getScreenHeight();
			SerializablePaint serializablePaint = serializablePath
					.getSerializablePaint();
			updatePaintParams(serializablePaint);

			// ÔÚÆÁÄ»·Ö±æÂÊÏàÍ¬µÄÉè±¸ÉÏ»æÍ¼£¬²»ÓÃ×ª»»×ø±êÖµ
			if (checkScreenDisplay(srcScreenWidth, srcScreenHeight)) {
				int pointCount = serializablePath.points.size(); // Ã¿Ò»ÌõÂ·¾¶µÄ×é³ÉµÄµãÊý
				for (int j = 0; j < pointCount; j++) {
					int x = (int) serializablePath.points.get(j).getX();
					int y = (int) serializablePath.points.get(j).getY();
					draw(x, y);
				}
			} else {
				// ²»Í¬ÏñËØµÄÉè±¸ÉÏ»æÍ¼£¬ÐèÒª×ª»»×ø±êÖµ
				int pointCount = serializablePath.points.size(); // Ã¿Ò»ÌõÂ·¾¶µÄ×é³ÉµÄµãÊý
				for (int j = 0; j < pointCount; j++) {
					int x = (int) serializablePath.points.get(j).getX();
					int y = (int) serializablePath.points.get(j).getY();
					draw((int) (x * (Commons.CURRENT_SCREEN_WIDTH / srcScreenWidth)),
							(int) (y * (Commons.CURRENT_SCREEN_HEIGHT / srcScreenHeight)));
				}
			}
			clearBrushPoint();
			resetColorAndSize();
		}
	}

	/**
	 * ¼ì²âÉè±¸¼äµÄÆÁÄ»·Ö±æÂÊÊÇ·ñÏàÍ¬
	 * 
	 * @param srcScreenWidth
	 * @param srcScreenHeight
	 * @return
	 */
	private boolean checkScreenDisplay(float srcScreenWidth,
			float srcScreenHeight) {
		return srcScreenWidth == Commons.CURRENT_SCREEN_WIDTH
				&& srcScreenHeight == Commons.CURRENT_SCREEN_HEIGHT;
	}

	private void resetColorAndSize() {
		mBrush.setStrokeWidth(Commons.currentSize);
		mBrush.setColor(Commons.currentColor);
	}

	/**
	 * @param serializablePaint
	 * @description:  ¸üÐÂ»­±ÊµÄ²ÎÊý£¨ÑÕÉ«¡¢³ß´ç£©
	 * @date: 2015-3-16 ÏÂÎç2:38:05
	 * @author: yems
	 */
	private void updatePaintParams(SerializablePaint serializablePaint) {
		// ¼ÇÂ¼µ±Ç°Éè±¸»­±ÊµÄ²ÎÊýÖµ£¬ÔÚ¶àÌ¨Éè±¸¼ä
		Commons.currentColor = mBrush.getColor();
		Commons.currentSize = mBrush.getStrokeWidth();

		mBrush.setStrokeWidth(serializablePaint.getSize());
		mBrush.setColor(serializablePaint.getColor());
	}
}
