// out.cpp
#include "stdafx.h"
#include "out.h"
#include "stdlib.h"


COut::COut()
{
	displayArea = CRect(0,0,800,600);
	x=0;
	y=0;
	xstart=0;
	ystart=0;
	rowHeight=21;
	charWidth=8; //!!!
	space=charWidth; //一个字符的宽度
	precious=7; //小数精度7位
	clipFlag = 0; //0 clip,1 no clip,2 no clip but return
	scrollRows = 0;
	scrollCols = 0;
	setFont(120,"宋体");
	textColor = RGB(0,0,0);
	textBkColor = RGB(255,255,255);
	textBkMode = OPAQUE;

	rowNum = displayArea.Height() / rowHeight + 10;
	isDrawBmp = false;
	beginStr = "￥[";endStr = "]";
	beginStr1 = "￥[";endStr1 = "]";
	beginStr2 = "％[";endStr2 = "]";
	isScrolling = false;

	bmpBkColor = RGB(74,65,74);//与背景色相同
	bmpForColor = RGB(230,255,255);
}
COut::~COut()
{
	if(!font)
		delete font;
}

void COut::setDC(CDC *pDC)
{
	COut::pDC=pDC;
}
void COut::setDisplayArea(CRect rect)
{
	displayArea = rect;
	xstart = rect.left;
	ystart = rect.top;
	x = rect.left;
	y = rect.top;
	rowNum = displayArea.Height() / rowHeight + 10;
}
void COut::setStart(int x,int y)
{
	xstart = displayArea.left + x + scrollCols*charWidth;
	ystart = displayArea.top + y + scrollRows*rowHeight;
	COut::x = xstart;
	COut::y = ystart;
}
void COut::endl()
{
	x=xstart;
	y+=rowHeight;
}

void COut::setSpaceWidth(int width)
{
	space=width*charWidth;
}
void COut::clip(int flag)
{
	clipFlag = flag;
}
///////////////////////////////////////
void COut::setFont(int size,CString type)
{
	if(!font)
		delete font;
	font = new CFont;
	font->CreatePointFont(size,type,NULL);
}
void COut::setTextColor(COLORREF textColor)
{
	COut::textColor = textColor;
}
void COut::setTextBkColor(COLORREF bkColor)
{
	textBkColor = bkColor;
}
void COut::setTextBkMode(int mode)
{
	textBkMode = mode;
}
void COut::clearBackground(COLORREF color)
{
	CPen pen(PS_SOLID,1,color),*oldPen;
	CBrush brush(color),*oldBrush;
	oldPen = pDC->SelectObject(&pen);
	oldBrush = pDC->SelectObject(&brush);
	pDC->Rectangle(displayArea);
	pDC->SelectObject(oldPen);
	pDC->SelectObject(oldBrush);
}
///////////////////////////////////////
void COut::clearScrollPos()
{
	scrollRows = 0;
	scrollCols = 0;
}
void COut::scrollUp(int rows)
{
	scrollRows -= rows;
}
void COut::scrollDown(int rows)
{
	scrollRows += rows;
}
void COut::scrollLeft(int colomn)
{
	scrollCols -=colomn;
}
void COut::scrollRight(int colomn)
{
	scrollCols +=colomn;
}
void COut::scrollPixel(int pixels, int direction)
{
	if(direction == 1)
		y += pixels;
	if(direction == -1)
		y -= pixels;
}
void COut::scrollRow(int rows,int direction)
{
	if(direction == 1) //向下
		y += rows*rowHeight;
	if(direction == -1) //向上
		y -= rows*rowHeight;
}
///////////////////////////////////////////
COut &COut::operator << (int num)
{
	char s[33];
	CString str;
	str = itoa(num,s,10);//十进制 int
	(*this)<<str;
	return *this;
}
COut &COut::operator << (unsigned int num)
{
	char s[33];
	CString str;
	str = itoa(num,s,10);//十进制 int
	(*this)<<str;
	return *this;
}
COut &COut::operator << (long num)
{
	char s[33];
	CString str;
	str = ltoa(num,s,10);//十进制 long
	(*this)<<str;
	return *this;
}
COut &COut::operator << (float num)
{
	char s[33];
	CString str;
	str = gcvt(num,precious,s); //gcvt
	(*this)<<str;
	return *this;
}
COut &COut::operator << (double num)
{
	char s[33];
	CString str;
	str = gcvt(num,precious,s); //gcvt
	(*this)<<str;
	return *this;
}
COut &COut::operator << (char chr)
{
	CString str;
	str = &chr;
	(*this)<<str;
	return *this;
}
COut &COut::operator << (char *pStr)
{
	CString str = pStr;
	(*this)<<str;
	return *this;
}
COut &COut::operator << (CString str)
{
	CString temp;
	long beginPos,endPos,num;
	CString subStr = "\15\12"; //支持回车
	beginPos = 0;
	while(1)
	{
		endPos = str.Find(subStr,beginPos);
		if(endPos != -1)
		{
			num = endPos - beginPos;
			temp = str.Mid(beginPos,num);
			beginPos = endPos + subStr.GetLength();
			if(isDrawBmp)
				drawLineInRectIncludeBmp(temp);
			else
				drawLineInRect(temp);
			endl();
//			rowNum = (y - displayArea.top)/rowHeight;
//			if(rowNum < displayArea.Height()/rowHeight)
//				rowNum = displayArea.Height()/rowHeight;

		}
		else
		{
			num = str.GetLength() - beginPos;
			temp = str.Mid(beginPos,num);
			if(isDrawBmp)
				drawLineInRectIncludeBmp(temp);
			else
				drawLineInRect(temp);
			break;
		}
	}
	return *this;
}
//////////////////////////////////////////////////
void COut::SupportBmp(bool b,int flag)
{
	if(flag == 1)
	{
		beginStr = beginStr1;
		endStr = endStr1;
	}
	if(flag == 2)
	{
		beginStr = beginStr2;
		endStr = endStr2;
	}
	isDrawBmp = b;
}

void COut::drawLineInRectIncludeBmp(CString &s)
{
	int ifSuccess;
	buffer = s;
	bufferPos = 0;
	int beginPos,endPos;
	CString temp;
	while(1)
	{
		beginPos = bufferPos;
		temp = getInnerStrIter(beginStr,endStr,ifSuccess);
		if(ifSuccess)
		{
			CString t = beginStr+temp+endStr;
			endPos = bufferPos - t.GetLength();
			s = buffer.Mid(beginPos,endPos-beginPos);
			drawLineInRect(s);
			LoadBmp(temp);
			DrawBmp();
		}
		else
		{
			s = buffer.Right(buffer.GetLength()-beginPos);
			drawLineInRect(s);
			break;
		}
	}
}

void COut::LoadBmp(CString s)
{
	bmp.LoadDIB(s);
	bmp.ChangeColor(RGB(255,255,255),bmpBkColor);
	bmp.ChangeColor(RGB(20,20,20),bmpForColor,20);
}

void COut::DrawBmp()
{
	int destX,destY,srcX,srcY,srcCx,srcCy;
	if(x < displayArea.left)
	{
		destX = displayArea.left;
		srcX = displayArea.left - x;
		srcCx = displayArea.Width();
	}
	else if(x > displayArea.right)
		return;
	else
	{
		destX = x;
		srcX = 0;
		srcCx = displayArea.right - x;
	}
	if(y < displayArea.top)
	{
		destY = displayArea.top;
		srcY = displayArea.top - y;
		srcCy = displayArea.Height();

	}
	else if(y > displayArea.bottom)
		return;
	else
	{
		destY = y;
		srcY = 0;
		srcCy = displayArea.bottom - y;
	}
//	bkBmp.FastCopyScreen(pDC,destX,destY,srcCx,srcCy);
	bkBmp.FastCopyScreen(pDC);
	bkBmp.BltBmpToBuf(destX,destY,&bmp,bmpBkColor);
	bkBmp.DrawBitmap(pDC,0,0);
	//裁剪有问题
//	bmp.DrawBitmap(pDC,destX,destY,srcX,srcY,srcCx,srcCy);
	x += bmp.width;
	y += bmp.height - rowHeight;
}

/////////////////////////////////////////////////
void COut::drawLineInRect(CString str)
{
	removeInnerStr(str,beginStr1,endStr1);
	removeInnerStr(str,beginStr2,endStr2);
	oldTextColor = pDC->SetTextColor(textColor);
	oldTextBkColor = pDC->SetBkColor(textBkColor);
	oldTextBkMode = pDC->SetBkMode(textBkMode);
  	oldFont = pDC->SelectObject(font); 
	CString temp;
	int n,n2,tempx;
	switch(clipFlag)
	{
	case 0://0 clip
		n = (displayArea.left - x)/charWidth;
		if(n > 0) //超出左边界
		{
			getCutPisition(temp,n,str); //str中
			temp = str;
			n2 = displayArea.Width() / charWidth;
			if(str.GetLength() > n2)
			{
				getCutPisition(temp,n2,str); //temp中
			}
			tempx = x;
			x = displayArea.left;
			if((y > displayArea.top) && (y < (displayArea.bottom-rowHeight)))
				pDC->TextOut(x,y,temp);
			x = tempx;
			x += temp.GetLength()*charWidth+space;
			goto rt;
		}
		else
		{
			n = (displayArea.right - x)/charWidth;
			if(n > 0) //字符串尾部可能超出右边界
			{
				getCutPisition(temp,n,str); //temp中
			}
		}
		if((y > displayArea.top) && (y < (displayArea.bottom-rowHeight)))
			pDC->TextOut(x,y,temp);
		x += temp.GetLength()*charWidth+space;
		break;
	case 1://1 no clip
		pDC->TextOut(x,y,str);
		x += temp.GetLength()*charWidth+space;
		break;
	case 2://2 no clip but return
		while(1) //消除乱码
		{
			if(displayArea.left > x)//超出左边界
				x = displayArea.left;
			n = (displayArea.right - x)/charWidth;//当前行可显示的最多字符数目
			if(n <= 0)//超出右边界
			{
				n = displayArea.Width()/charWidth;
				endl();
			}
			getCutPisition(temp,n,str);//temp中是str的前n个字符(汉字占两个)
			if((y > displayArea.top) && (y < (displayArea.bottom-rowHeight)))
				pDC->TextOut(x,y,temp);
			if(!str.IsEmpty())
				endl();
			else
			{
				x += temp.GetLength()*charWidth+space;
				break;
			}
		}
	}
rt:	 pDC->SetTextColor(oldTextColor);
	 pDC->SetBkColor(oldTextBkColor);
	 pDC->SetBkMode(oldTextBkMode);
  	 pDC->SelectObject(oldFont); 
}

//将sourceStr分为两部分,前n个在subStr中,剩下的在sourceStr中
void COut::getCutPisition(CString &subStr, int &n, CString &sourceStr)
{
	int i,flag,length;
	unsigned char c;
	subStr = sourceStr.Left(n);
	flag = 0;
	length = subStr.GetLength();
	for(i=0;i<length;i++)
	{
		c = subStr.GetAt(i);
		if(c <= 127)
		flag++;
	}
	if( (((n%2)==1) && ((flag%2)==0))  ||  (((n%2)==0) && ((flag%2)==1)))
		subStr = sourceStr.Left(--n); //!!!
	sourceStr = sourceStr.Right(sourceStr.GetLength()-n);
}
////////////////////////////////////////////////////////
void COut::removeSubStr(CString &sourceStr,CString subStr)
{
	long beginPos,endPos,num;
	CString temp;
	beginPos = 0;
	while(true)
	{
		endPos = sourceStr.Find(subStr,beginPos);
		if(endPos != -1)
		{
			num = endPos - beginPos;
			temp += sourceStr.Mid(beginPos,num);
			beginPos = endPos + subStr.GetLength();
		}
		else
		{
			num = sourceStr.GetLength() - beginPos;
			temp += sourceStr.Mid(beginPos,num);
			break;
		}
	}
	sourceStr = temp;
}
void COut::replaceSubStr(CString &sourceStr, CString subStrOut,CString subStrIn)
{
	long beginPos,endPos,num;
	CString temp;
	beginPos = 0;
	while(true)
	{
		endPos = sourceStr.Find(subStrOut,beginPos);
		if(endPos != -1)
		{
			num = endPos - beginPos;
			temp += sourceStr.Mid(beginPos,num);
			temp +=subStrIn;
			beginPos = endPos + subStrOut.GetLength();
		}
		else
		{
			num = sourceStr.GetLength() - beginPos;
			temp +=subStrIn;
			temp += sourceStr.Mid(beginPos,num);
			break;
		}
	}
	sourceStr = temp;
}

CString COut::getInnerStrIter(CString beginStr, CString endStr, int &ifSuccess)
{
	long beginPos,endPos,count;
	beginPos = buffer.Find(beginStr,bufferPos);
	if(beginPos != -1)
	{
		beginPos += beginStr.GetLength();
		endPos = buffer.Find(endStr,beginPos);
		if(endPos != -1)
		{
			count = endPos - beginPos;
			bufferPos = endPos + endStr.GetLength();
			ifSuccess = 1;
			return buffer.Mid(beginPos,count);
		}
	}
	ifSuccess = 0;
	return "";

}

void COut::removeInnerStr(CString &s,CString begin,CString end)
{
	int pos1,pos2,endLen;
	pos1 = s.Find(begin);
	endLen = end.GetLength();
	while(1)
	{
		if(pos1 != -1)
		{
			pos2 = s.Find(end,pos1);
			if(pos2 != -1)
			{
				s.Delete(pos1,pos2+endLen-pos1);
				pos1 = s.Find(begin,pos1);
			}
			else
				break;
		}
		else
			break;
	}
}

void COut::SetBmpColor(COLORREF b, COLORREF f)
{
	bmpBkColor = b;
	bmpForColor = f;
}
