package cn.wps.moffice.writer.render.base;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import cn.wps.base.BuildConfig;
import cn.wps.core.runtime.Platform;
import cn.wps.graphics.PointF;
import cn.wps.graphics.RectF;
import cn.wps.moffice.drawing.graphics.GraphicsCanvas;
import cn.wps.moffice.util.MetricsUtil;
import cn.wps.moffice.writer.cache.TypoDocument;
import cn.wps.moffice.writer.cache.TypoDrawing;
import cn.wps.moffice.writer.cache.TypoFootEndNote;
import cn.wps.moffice.writer.cache.TypoLayoutPage;
import cn.wps.moffice.writer.cache.TypoRectCoreImpl;
import cn.wps.moffice.writer.cache.pagelist.TypoLayoutPageIterator;
import cn.wps.moffice.writer.core.CoreThread;
import cn.wps.moffice.writer.core.FontAttribute;
import cn.wps.moffice.writer.render.CanvasController;
import cn.wps.moffice.writer.render.base.RenderSetting.RenderType;
import cn.wps.moffice.writer.render.color_mode.ColorModeRender;
import cn.wps.moffice.writer.render.drawing.DrawingRenderBuffer;
import cn.wps.moffice.writer.render.drawing.ReadAudioAnimControl;
import cn.wps.moffice.writer.render.drawing.TypoDrawingRender;
import cn.wps.moffice.writer.render.renderer.PageRender;
import cn.wps.moffice.writer.render.renderer.TextPreviewRender;
import cn.wps.moffice.writer.render.renderer.ThumbRender;
import cn.wps.moffice.writer.render.tool.RenderTool;
import cn.wps.moffice.writer.service.ZoomService;
import cn.wps.moffice.writer.util.UiAutomatorUtil;

/**
 * 可在子线程执行的render。原render在子线程执行,由于IViewSettings在主线程可变,数据一致性并不能保证。
 * 
 * @文件名		:	LayoutRenderBase.java
 * @创建者		:	LiKangning
 * @维护人		:	LiKangning
 * @创建时间	:	2014-2-12 下午6:01:06
 * @功能描述	:	TODO
 */
public abstract class LayoutRenderBase
{
	static final String TAG = BuildConfig.DEBUG ? LayoutRenderBase.class.getSimpleName() : null;

	final protected boolean				isMainInstance;
	/** 用于绘制不同配色背景 */
	final protected ColorModeRender		mColorModeRender;
	/** 配置参数 */
	final protected RenderSetting		setting;

	/** 排版数据 */
	protected TypoDocument				mTypoDocument;

	/** 绘制工具 */
	protected CanvasController			control;
	protected RenderEnv					env;
//	protected TypoLayoutPageIterator	mPageLock; // page读锁，使用的时候从typoDocument锁住，用完后请人工释放并致空
	
	private BalloonLineRender mBalloonLineRender; // 替换pageRender的方法,用于适配硬件加速
	
	public LayoutRenderBase() {
		this(false);
	}
	
	public LayoutRenderBase(boolean isMainInstance)
	{
		this.isMainInstance = isMainInstance;
		mColorModeRender = new ColorModeRender();
		setting = new RenderSetting();
	}
	
	public void dispose()
	{
		if (null != env)
		{
			env.dispose();
			env = null;
		}
		
		// 静态辅助变量只需要dispose一次
		if (isMainInstance)
		{
			Platform.getPicturePool().clear();
			RectF.clearPool();
			PointF.clearPool();
			TypoRectCoreImpl.clearPool();
			DrawingRenderBuffer.clearPool();
			PageRender.clearPool();
			RenderResult.clearPool();
		}
	}
	
	protected int mDrawWidth;
	protected int mDrawHeight;
	
	public void setDrawSize(int width, int height)
	{
		mDrawWidth = width;
		mDrawHeight = height;
	}
	
	protected int beginDraw(RenderType type, Canvas canvas, Rect clip, float zoom)
	{
		env.mZoom = zoom; // 对象绘制无法传这个值
		setting.isShowBalloons = env.getViewSettings().isShowBalloons();
		setting.colorMode = getColorMode();
		
		if (type == RenderType.TYPE_BALLOONS) {
			// TODO
			setting.setBalloonStrokeWidth(env.getViewSettings().getZoom(), env.getViewSettings().getBalloonsZoom());
		}
		
		prepare(type, zoom);
		
		int layoutMode = env.getViewSettings().getLayoutMode();
		if (null != clip)
			mColorModeRender.drawBackground(canvas, setting.colorMode, clip, mDrawWidth, mDrawHeight, layoutMode);
		
		control.setCanvas(canvas);
		
		control.getDrawer().initMinStroke(setting.minStroke);
		
		if (env.getGraphics() instanceof GraphicsCanvas)
			((GraphicsCanvas)env.getGraphics()).setCanvas(canvas, setting.minStroke);
		
		int saveCount = canvas.save();
		if (zoom != 0) {
			final float scale = zoom * MetricsUtil.point2pixel_x_ratio;
			canvas.scale(scale, scale);
		}
//		control.clear();
		return saveCount;
	}
	
	protected void endDraw(Canvas canvas, int saveCount)
	{
		if (saveCount > 0)
			canvas.restoreToCount(saveCount);
//		control.clear();
//		env.getBalloonTagMgr().clear();
	}
	
	private void prepare(RenderType type, float zoom)
	{
		setting.prepareSetting(type);
		prepare(zoom);
		
//		if (type == RenderType.TYPE_BALLOONS)
//			setting.setBalloonStrokeWidth(zoom, env.getViewSettings().getBalloonsZoom());
	}
	
	abstract protected void prepare(float zoom);
	abstract protected boolean doRender(RectF clip, RenderResult renderResult, float zoom, TypoLayoutPageIterator pageIt, boolean drawBackground);
	abstract protected RenderColorMode getColorMode();
	
	//////////////////////////////////////////////////////////////////////////////////////////////
	
	public boolean waitForRect(float top, float bottom, boolean waitLayout)
	{
		final float documentTop = mTypoDocument.getTop();
		final float documentBottom = mTypoDocument.getBottom();
		boolean hasDocumentData = documentTop < bottom && top < documentBottom;
		// bug195956-侧边栏大小改变频繁排版导致绘制时排版数据完全无效必须等锁
		if (documentTop >= documentBottom && !CoreThread.curThreadIsCoreThread())
		{
			mTypoDocument.getLayoutPageListObserver().waitRect(top, bottom);
			hasDocumentData = true;
		}
		else if (hasDocumentData && waitLayout)
		{
			float lockTop = Math.max(documentTop, top);
			float lockBottom = Math.min(documentBottom, bottom);
			mTypoDocument.getLayoutPageListObserver().waitRect(lockTop, lockBottom);
		}
		return hasDocumentData;
	}
	
	public void waitForBalloonsRect(float top, float bottom)
	{
		final float balloonsTop = mTypoDocument.getBalloonsTop();
		final float balloonsBottom = mTypoDocument.getBalloonsBottom();
		if (balloonsTop < bottom && top < balloonsBottom)
		{
			float lockTop = Math.max(balloonsTop, top);
			float lockBottom = Math.min(balloonsBottom, bottom);
			mTypoDocument.getLayoutPageListObserver().waitBalloonRect(lockTop, lockBottom);
		}
	}
	
	/**
	 * 正文普通绘制
	 */
	public boolean renderDocument(Canvas canvas, Rect clip)
	{
		return renderDocument(canvas, clip, RenderType.TYPE_NORMAL, null, env.getViewSettings().getZoom());
	}
	
	/**
	 * 正文缓存绘制
	 */
	public boolean renderDocument(Canvas canvas, Rect clip, RenderType renderType, RenderResult renderResult, float zoom)
	{
		return renderDocument(canvas, null, clip, renderType, renderResult, !CoreThread.curThreadIsCoreThread(), zoom, false, null);
	}
	
	/**
	 * 正文缓存绘制
	 */
	public boolean renderDocument(Canvas canvas, Bitmap bitmap, Rect clip, RenderType renderType, RenderResult renderResult, float zoom, boolean quick, IScrollMode scrollMode)
	{
		return renderDocument(canvas, bitmap, clip, renderType, renderResult, !CoreThread.curThreadIsCoreThread(), zoom, quick, scrollMode);
	}
	
	
	protected Bitmap bitmap;
	/**
	 * 正文缓存绘制
	 */
	private boolean mHasRenderDocument = false;
	public boolean renderDocument(Canvas canvas, Bitmap bitmap, Rect clip, RenderType renderType, RenderResult renderResult, boolean waitLayout, float zoom, boolean quick, IScrollMode scrollMode)
	{
		if (isMainInstance && !mHasRenderDocument)
			UiAutomatorUtil.onFirstRenderDocumentCreateBegin();
		this.bitmap = bitmap;
		boolean result = _renderDocument(canvas, clip, renderType, renderResult, waitLayout, zoom, quick, scrollMode);
		this.bitmap = null;
		if (isMainInstance && !mHasRenderDocument)
		{
			UiAutomatorUtil.onFirstRenderDocumentCreateFinish();
			mHasRenderDocument = true;
		}
		return result;
	}
	
	/**
	 * 绘制的入口 
	 */
	private boolean _renderDocument(Canvas canvas, Rect clip, RenderType type, RenderResult renderResult, boolean waitLayout, float zoom, boolean quick, IScrollMode scrollMode) 
	{
		final RectF ptRect = RectF.obtain();
		ZoomService.render2layout(clip, ptRect, zoom);
		
		boolean hasDocumentData = waitForRect(ptRect.top, ptRect.bottom, waitLayout);
		if (!hasDocumentData) {
			ptRect.recycle();
			return false;
		}
		TypoLayoutPageIterator pageIt = mTypoDocument.layoutPageIterator();
		if (null == pageIt) {
			ptRect.recycle();
			return false;
		}
		
		if (null != renderResult)
			renderResult.setZoom(zoom);
		int saveCount = 0;
		boolean result;
		try
		{
			setting.scrollMode = scrollMode;
			saveCount = beginDraw(type, canvas, quick ? null : clip, zoom);
			result = doRender(ptRect, renderResult, zoom, pageIt, quick);
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
		ptRect.recycle();
		pageIt.recycle();
		return result;
	}
	
	////////////////////////////////////////////////////////////////////////////////////////
	
	/**
	 * 放大镜绘制
	 */
	public void renderDocumentByMagnifier(Canvas canvas, float zoom, Rect clip, float factor)
	{
		canvas.save();
		canvas.translate(-clip.left, -clip.top);
		//放大镜模式下实际显示的rect大于绘制的rect,手动补上背景绘制
		if (mColorModeRender != null)
		{
			int bottom = clip.bottom;
			clip.bottom += clip.height();
			mColorModeRender.drawMagnifierBackground(canvas, getColorMode(), clip, mDrawWidth, mDrawHeight, env.getViewSettings().getLayoutMode(), factor);
			clip.bottom = bottom;
		}
		
		final RectF ptRect = RectF.obtain();
		ZoomService.render2layout(clip, ptRect, zoom);
		waitForRect(ptRect.top, ptRect.bottom, true);
		
		TypoLayoutPageIterator pageIt = mTypoDocument.layoutPageIterator();
		if (null == pageIt) {
			ptRect.recycle();
			canvas.restore();
			return;
		}
		
		int saveCount = 0;
		try {
			saveCount = beginDraw(RenderType.TYPE_MAGNIFIER, canvas, null, zoom);
			doRender(ptRect, null, zoom, pageIt, false);
		}
		// 放大镜操作崩溃,临时方案,忽略所有异常
		catch (Exception e) {
			
		}
		finally {
			endDraw(canvas, saveCount);
		}
		ptRect.recycle();
		pageIt.recycle();
		canvas.restore();
	}
	
	/**
	 * 预览字符串绘制
	 */
	public void renderPreviewText(Canvas canvas, FontAttribute attr, int width, int height, int drawWidth, int drawHeight)
	{
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_SCREEN_SHOT, canvas, null, env.getViewSettings().getZoom());
			
			final PageRender render = PageRender.obtain(env);
			TextPreviewRender.instance(render).renderText(attr, width, height);
			render.recycle();
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
	}
	
	/**
	 * 批注修订（Web版式）绘制
	 * @return 
	 */
	public boolean renderWebBalloonContent(Canvas canvas, float contentZoom, float balloonsZoom, Rect clip)
	{
		RectF ptRect = RectF.obtain();
		ZoomService.render2layout(clip, ptRect, balloonsZoom);
		
//		float balloonOffset2MainView_point = ZoomService.render2layout_y(balloonOffset2MainView, balloonsZoom);
//		setting.balloonOffset2MainView = balloonOffset2MainView_point;
		
		TypoLayoutPageIterator pageIt = mTypoDocument.layoutPageIterator();
		if (null == pageIt) {
			ptRect.recycle();
			return false;
		}
		
		boolean result = false;
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_BALLOONS, canvas, null, balloonsZoom);
			result = renderWebBalloonContent(canvas, ptRect, contentZoom, balloonsZoom, pageIt);
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
		
		ptRect.recycle();
		pageIt.recycle();
		return result;
	}

	private boolean renderWebBalloonContent(Canvas canvas, RectF clip, float contentZoom, float balloonsZoom, TypoLayoutPageIterator pageIt)
	{
		//drawBackground
		canvas.drawColor(RenderTool.getBalloonBackColor());
				
		final PageRender render = PageRender.obtain(env);
		TypoLayoutPage page = null;
		while (null != (page = pageIt.readLockNext()))
		{
			if (!PageRender.isBalloonPageValid(page, -1))
			{
				if (page.hasRevision() || page.hasComment())
					return false;
				continue;
			}
			
			float balloonsTop = page.balloons.getTop();
			float balloonsBottom = page.balloons.getBottom();
			if (balloonsTop > balloonsBottom)
			{
				//容错：有些样章修订undo后会出现排版数据错误
				TypoDrawing lastDrawing = page.balloons.getFloats().lastElement();
				if (lastDrawing != null)
					balloonsBottom = balloonsTop + lastDrawing.getBottom();	
			}
			
			if (balloonsTop < clip.bottom && clip.top < balloonsBottom)
			{
				render.renderBalloonPage(page, clip, balloonsZoom);
			}	
		}
		render.recycle();
		
		return true;
	}
	
	/**
	 * 批注修订（Web版式）绘制
	 * @return 
	 */
	public boolean renderWebBalloonLine(Canvas canvas, float contentZoom, float balloonsZoom, Rect clip, 
			int balloonOffset2MainView, Rect mainDocDrawingRect)
	{
		TypoLayoutPageIterator pageIt = mTypoDocument.layoutPageIterator();
		if (null == pageIt) {
			return false;
		}
		RectF ptRect = RectF.obtain();
		ZoomService.render2layout(clip, ptRect, balloonsZoom);
		
		float balloonOffset2MainView_point = ZoomService.render2layout_y(balloonOffset2MainView, balloonsZoom);
		setting.balloonOffset2MainView = balloonOffset2MainView_point;
		
		boolean result = renderWebBalloonLine(canvas, ptRect, contentZoom, balloonsZoom, mainDocDrawingRect, pageIt);
		
		ptRect.recycle();
		
		pageIt.recycle();
		return result;
	}

	private boolean renderWebBalloonLine(Canvas canvas, RectF clip, float contentZoom, float balloonsZoom, Rect mainDocDrawingRect, TypoLayoutPageIterator pageIt)
	{
		//转换成排版单位 
		float mainDocTop = ZoomService.render2layout_y(mainDocDrawingRect.top, balloonsZoom);
		float mainDocBottom = ZoomService.render2layout_y(mainDocDrawingRect.bottom, balloonsZoom);
		
		final PageRender render = PageRender.obtain(env);
		TypoLayoutPage page = null;
		while (null != (page = pageIt.readLockNext()))
		{
			if (!PageRender.isBalloonPageValid(page, -1))
			{
				if (page.hasRevision() || page.hasComment())
					return false;
				continue;
			}
			
			float balloonsTop = page.balloons.getTop();
			float balloonsBottom = page.balloons.getBottom();
			if (balloonsTop > balloonsBottom)
			{
				//容错：有些样章修订undo后会出现排版数据错误
				TypoDrawing lastDrawing = page.balloons.getFloats().lastElement();
				if (lastDrawing != null)
					balloonsBottom = balloonsTop + lastDrawing.getBottom();	
			}
			
			if (balloonsTop < clip.bottom && clip.top < balloonsBottom
					|| page.getTop() < mainDocBottom && mainDocTop < page.getBottom())
			{
					if (null == mBalloonLineRender) mBalloonLineRender = new BalloonLineRender(setting);
					mBalloonLineRender.renderBalloonLine(canvas, page, clip, contentZoom, balloonsZoom);
			}	
		}
		render.recycle();
		return true;
	}
	
	/**
	 * 批注修订（Page版式）绘制
	 */
	public boolean renderBalloonContent(Canvas canvas, int index, Rect clip, float balloonsZoom)
	{
		final TypoLayoutPageIterator pageIt = mTypoDocument.getPageList().tryReadLockLayoutPage(index);
		if (null == pageIt) {
			return false;
		}
		final TypoLayoutPage layoutPage = pageIt.getLockedPage();
		if (!PageRender.isBalloonPageValid(layoutPage, index))
		{
			canvas.drawColor(RenderTool.getBalloonBackColor());
			pageIt.recycle();
			return true;
		}
		
		canvas.drawColor(RenderTool.getBalloonBackColor());
		
		RectF ptRect = RectF.obtain();
		ZoomService.render2layout(clip, ptRect, balloonsZoom);
		
//		float balloonOffset2MainView_point = ZoomService.render2layout_y(balloonOffset2MainView, balloonsZoom);
//		balloonOffset2MainView_point += layoutPage.balloons.getTop();
//		setting.balloonOffset2MainView = balloonOffset2MainView_point;
		
		final PageRender render = PageRender.obtain(env);
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_BALLOONS, canvas, null, balloonsZoom);
			render.renderBalloonPage(layoutPage, ptRect, balloonsZoom);
		}
		finally
		{
			endDraw(canvas, saveCount);
		}


		
		pageIt.recycle();
		
		render.recycle();
		
		ptRect.recycle();
		return true;
	}
	
	/**
	 * 批注修订（单个记录）绘制
	 */
	public void renderBalloonContent(Canvas canvas, TypoLayoutPage page, TypoDrawing typoDrawing,
                                     Rect clip, float scale, ReadAudioAnimControl animControl)
	{
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_BALLOONS, canvas, null, scale);
			
			env.setCurrentPage(page);
			env.setReadAudioAnimControl(animControl);
			
			RectF visibleRect = RectF.obtain();
			ZoomService.render2layout(clip, visibleRect, scale);
			
			DrawingRenderBuffer render = DrawingRenderBuffer.obtain();
			
			if (null != typoDrawing)
			{
				env.setDrawBalloon(true);
				if (typoDrawing.getDrawingType() == TypoDrawing.TYPE_AUDIO_COMMENT) {
                    render.render(env, typoDrawing, visibleRect, TypoDrawingRender.RenderType.balloon, scale);
                } else {
                    render.render(env, typoDrawing, visibleRect, scale);
                }
				env.setDrawBalloon(false);
			}
			
			render.recycle();
			
			visibleRect.recycle();
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
	}
	
	/**
	 * 批注修订（Page版式）绘制
	 */
	public void renderBalloonLine(Canvas canvas, int index, Rect clip, float contentZoom, float balloonsZoom,
			int balloonOffset2MainView)
	{
		final TypoLayoutPageIterator pageIt = mTypoDocument.getPageList().tryReadLockLayoutPage(index);
		if (null == pageIt)
			return;
		final TypoLayoutPage layoutPage = pageIt.getLockedPage();
		if (!PageRender.isBalloonPageValid(layoutPage, index))
		{
			pageIt.recycle();
			return;
		}
		
		RectF ptRect = RectF.obtain();
		ZoomService.render2layout(clip, ptRect, balloonsZoom);
		
		float balloonOffset2MainView_point = ZoomService.render2layout_y(balloonOffset2MainView, balloonsZoom);
		balloonOffset2MainView_point += layoutPage.balloons.getTop();
		setting.balloonOffset2MainView = balloonOffset2MainView_point;
		
		if (null == mBalloonLineRender) mBalloonLineRender = new BalloonLineRender(setting);
		mBalloonLineRender.renderBalloonLine(canvas, layoutPage, ptRect, contentZoom, balloonsZoom);
		
		pageIt.recycle();
		ptRect.recycle();
	}
	
	/**
	 * 对象（完整）绘制
	 */
	public boolean renderTypoDrawing(Canvas canvas, float scale, TypoDrawing typoDrawing, Rect clip, boolean bFastDraw)
	{
		boolean result = true;
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_OBJECT, canvas, null, scale);
			
			RectF visibleRect = null;
			if (clip != null)
			{
				visibleRect = RectF.obtain();
				ZoomService.render2layout(clip, visibleRect, scale);				
			}
			
			PageRender render = PageRender.obtain(env);
			env.getGraphics().setDrawHigh(!bFastDraw);
			render.drawObjectInBegin(typoDrawing, visibleRect, scale);
			env.getGraphics().setDrawHigh(false);
			render.recycle();
			
			if (visibleRect != null)
				visibleRect.recycle();
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
		return result;
	}

	/**
	 * 对象（缩略图）绘制
	 */
	public void renderDrawing(Canvas canvas, int documentType, int shapeId)
	{
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_NORMAL, canvas, null, 1);
			final PageRender render = PageRender.obtain(env);
			ThumbRender.renderDrawing(control, render, mTypoDocument, documentType, shapeId, env);
			render.recycle();
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
	}
	
	public void renderFootEndNote(Canvas canvas, TypoLayoutPage layoutPage,
			TypoFootEndNote footEndNote, Rect clip, float scale, int outColor)
	{
		int saveCount = 0;
		try
		{
			saveCount = beginDraw(RenderType.TYPE_OBJECT, canvas, null, scale);
			
			env.setCurrentPage(layoutPage);
			
			RectF visibleRect = RectF.obtain();
			ZoomService.render2layout(clip, visibleRect, scale);
			
			PageRender render = PageRender.obtain(env);
			render.drawPage(footEndNote.getContent(), visibleRect, outColor, scale);
			render.recycle();
			
			visibleRect.recycle();
		}
		finally
		{
			endDraw(canvas, saveCount);
		}
	}
	
	/**
	 * 绘制在Canvas的开始处
	 */
	public void renderDocumentToBegin(Canvas canvas, float zoom, android.graphics.Rect clip, RenderType type, boolean lock)
	{
		canvas.save(Canvas.MATRIX_SAVE_FLAG);
		canvas.translate(- clip.left, - clip.top);
        renderDocument(canvas, null, clip, type, null, true, zoom, false, null);
		canvas.restore();
	}
	
	/**
	 * 画背景
	 * @param canvas
	 */
	public void drawBackground(Canvas canvas) {
		int layoutMode = env.getViewSettings().getLayoutMode();
		RenderColorMode colorMode = getColorMode();
		mColorModeRender.drawBackground(canvas, colorMode, mDrawWidth, mDrawHeight, layoutMode);
	}
	
	public RenderEnv getEnv()
	{
		return env;
	}
}
