// CustomRichTextBox.cpp : main project file.

#include "stdafx.h"
#include "CustomRichTextBox.h"
#include <stdio.h>
#include <string>

namespace ObjDataEdit
{
	namespace CustomRichTextBox
	{


		/// <summary>
		///
		/// </summary>		
		std::string StringToChar( String * Str )
		{
			if( Str == NULL || Str->Length == 0 )
				return "";
			char utf8 __gc[] = Encoding::Default->GetBytes( Str );
			char __pin *charStr = &utf8[0];      
			return charStr;      
		}

		/// <summary>
		///
		/// </summary>	
		char*	GetDBSource( )
		{
			static char DBSourceInfo[1024];

			char    Buf[256];
			char	Path[256];
			GetCurrentDirectory(sizeof(Buf),Buf);
			sprintf( Path , "%s\\ObjectDataEdit.ini", Buf );	

			GetPrivateProfileString("BOOT", "DBSource" , NULL , Buf , sizeof(Buf) , Path );

			sprintf(DBSourceInfo, "%s%s", "workstation id=HSIANG;packet size=4096;user id=hsiangren;persist security info=True;initial catalog=ObjectData;password=2ddilxxl;data source=", Buf);

			return DBSourceInfo;

		}

#pragma region class CustomRichTextBox
		CustomRichTextBox::CustomRichTextBox(void)
		{
			mMirror = NULL;
			mParsing = false;
			mImeEndStart = false;
			mImeUpdated = false;

			this->mMirror = new CMirrorRichTextBox();
			// 
			// MirrorTextBox
			// 
			this->mMirror->Location = System::Drawing::Point(0, 0);
			this->mMirror->Name = "Mirror";
			this->mMirror->Size = System::Drawing::Size(Size.Width, Size.Height);
			this->mMirror->TabIndex = 1;
			this->mMirror->Visible = false;
			this->mMirror->Parent = this;

			this->sqlCommand_Base = (new System::Data::SqlClient::SqlCommand());
			this->sqlConnection_Base = (new System::Data::SqlClient::SqlConnection());
			this->sqlCommand_Base->Connection = this->sqlConnection_Base;			
			this->sqlConnection_Base->FireInfoMessageEventOnUserErrors = false;	
		}
#pragma region Member function
		void CustomRichTextBox::MirrorWndProc(Message* m)
		{
			Message mirror = *m;
			mirror.HWnd = mMirror->Handle;

			DWORD lang = (DWORD)GetKeyboardLayout(GetCurrentThreadId());

			switch (mirror.Msg)
			{
			case WM_KEYDOWN:
				{
					switch ((Keys)(int)m->WParam)
					{						
					case Keys::Enter:
					case Keys::Back:
					case Keys::Left:
					case Keys::Right:
					case Keys::Up:
					case Keys::Down:
					case Keys::Delete:
						{
							mMirror->AdjustCaretPos(SelectionStart, SelectionLength);
							mMirror->WndProcCaller(&mirror);
							break;
						}
					case Keys::Home:
					case Keys::End:
						{
							mMirror->WndProcCaller(&mirror);
							break;
						}
					default:
						if (!mStartComposition)
							mMirror->AdjustCaretPos(SelectionStart, SelectionLength);
						mMirror->WndProcCaller(&mirror);
						break;
					}
					break;
				}
			case WM_CHAR:
				{
					mMirror->WndProcCaller(&mirror);
					break;
				}
			case WM_COPY:
			case WM_CUT:
			case WM_PASTE:
			case WM_CLEAR:
			case WM_UNDO:
				{
					mMirror->WndProcCaller(&mirror);
					break;
				}

			case WM_IME_STARTCOMPOSITION:
				{
					mStartComposition = true;
					mMirror->WndProcCaller(&mirror);
					break;
				}
			case WM_IME_COMPOSITION:
				{
					mMirror->WndProcCaller(&mirror);
					break;
				}

			case WM_IME_ENDCOMPOSITION:
				{
					int tmp  = mMirror->SelectionStart;
					Sleep(tmp - tmp );
					mMirror->WndProcCaller(&mirror);
					tmp  = mMirror->SelectionStart;
					Sleep(tmp - tmp );
					mStartComposition = false;
					
					DWORD lang = (DWORD)GetKeyboardLayout(GetCurrentThreadId());
										
					if (lang == 0xE0010404) //ㄅ半注音
					{
						mMirror->TransletText();
						mImeEndStart = true;
						mImeUpdated = false;
						Rtf = mMirror->TranslatedText;
						mImeEndStart = false;
					}
					break;
				}			
			case EM_UNDO:
			case EM_SETMODIFY:
			case EM_SETSEL:			
				{
					mMirror->WndProcCaller(&mirror);
					break;
				}
			case EM_GETSEL:
			case EM_GETRECT:
			case EM_SETRECT:
			case EM_SETRECTNP:
			case EM_GETMODIFY:
			case EM_GETLINECOUNT:
			case EM_EMPTYUNDOBUFFER:
			case EM_LINEINDEX:
			case EM_GETTHUMB:
			case EM_LINELENGTH:
			case EM_REPLACESEL:
			case EM_GETLINE:
			case EM_LIMITTEXT:
			case EM_CANUNDO:
			case EM_FMTLINES:
			case EM_LINEFROMCHAR:
			case EM_SETTABSTOPS:
			case EM_SETPASSWORDCHAR:
			case EM_GETFIRSTVISIBLELINE:
			case EM_SETWORDBREAKPROC:
			case EM_GETWORDBREAKPROC:
			case EM_SETMARGINS:
			case EM_GETMARGINS:
			case EM_GETLIMITTEXT:
			case EM_POSFROMCHAR:
			case EM_CHARFROMPOS:
			case EM_SETIMESTATUS:
			case EM_GETIMESTATUS:
				{
					mMirror->WndProcCaller(&mirror);
					break;
				}
			}
		}

		/// <summary>
		///
		/// </summary>
		void CustomRichTextBox::TextChange(EventArgs* e)
		{
			if (mParsing) return;
			mParsing = true;
			LockWindowUpdate((HWND)Handle.ToPointer());
			System::Windows::Forms::RichTextBox::OnTextChanged(e);

			POINT* scrollPos = GetScrollPos();

			this->Rtf = mMirror->TranslatedText;
			this->SelectionStart = mMirror->GetCorrectSelectionStart();

			mParsing = false;
			SetScrollPos(scrollPos);

			LockWindowUpdate((HWND)0);
			Invalidate();	
		}

		/// <summary>
		///
		/// </summary>		
		void CustomRichTextBox::KeyWord( const char* pszKeyWord, char* pszSourceText, int& iType )
		{
			System::Data::SqlClient::SqlDataReader* myReader;

			if (sqlConnection_Base->State == System::Data::ConnectionState::Closed)
			{
				this->sqlConnection_Base->ConnectionString = GetDBSource();
				sqlConnection_Base->Open();
			}

			iType = 0;

			// you must to kill [111111]
			// you must to kill [111111]

			// 檢查是不是六位數 GUID
			int iGUID = atoi( pszKeyWord );
			if( iGUID > 100000 )
			{
				char szCommand[1024];
				sprintf( szCommand, "Select content from StringDB Where KeyStr = 'Sys%d_name'", iGUID );

				sqlCommand_Base->CommandText = szCommand;
				myReader = sqlCommand_Base->ExecuteReader();

				/*
				if( iGUID >= 100000 && iGUID < 200000 )
				{
				iType = 1;
				}
				else
				if( iGUID >= 200000 && iGUID < 300000 )
				{
				iType 
				}
				*/
			}
			else
				//if( strcmp( pszKeyWord, "ZONE_" ) == 0 )
				{
					char szCommand[1024];
					std::string pWord = pszKeyWord;
					size_t begin; 
					while ( (begin = pWord.find("'")) != std::string::npos ) 
					{
						pWord.replace(begin, 1, "''");
						break;
					}

					sprintf( szCommand, "Select content from StringDB Where KeyStr = '%s'", pWord.c_str() );
					sqlCommand_Base->CommandText = szCommand;
					myReader = sqlCommand_Base->ExecuteReader();
				}

				if( myReader->Read() == false )
				{
					// 找不到字串
					if( pszSourceText )
					{
						sprintf( pszSourceText, pszKeyWord );
					}			
				}
				else
				{
					String* Str   =  String::Format("{0} ", myReader->GetString( 0 ));


					if (myReader != NULL)
					{			 
						myReader->Close();
					}
					if (Str->Contains("[") && Str->Contains("]"))
					{
						String* orgKey = new String(("[" + std::string(pszKeyWord) + "]").c_str());
						while (Str->Contains("[") && Str->Contains("]"))
						{
							int indexLeft = Str->IndexOf("[");
							int indexRight = Str->IndexOf("]");

							String* CutStr = Str->Substring(0, indexLeft);

							mMirror->AddPragraphBlock(CTextBlock::PB_TRANSLATED, iType, "", CutStr);

							std::string tempStr = StringToChar(Str->Substring(indexLeft + 1, indexRight - indexLeft - 1));
							const char* subKeyWord = tempStr.c_str();
							char TransText [512];

							KeyWord(subKeyWord, TransText, iType);
							tempStr = "["+ tempStr + "]";
							String* OrgStr = new String(tempStr.c_str()) ;
							String* NewStr = new String(TransText);
							Str = Str->Substring(indexRight + 1);
							mMirror->AddPragraphBlock(CTextBlock::PB_TRANSLATED, 2, "", NewStr);
						}
						mMirror->AddPragraphBlock(CTextBlock::PB_TRANSLATED, iType, orgKey, Str);
						Str = " ";
					}

					if( pszSourceText )
					{
						sprintf( pszSourceText, StringToChar( Str ).c_str() );
					}
				}


				if (myReader != NULL)
				{			 
					myReader->Close();
				}
		}
#pragma endregion 

#pragma region Overriden methods
		/// <summary>
		/// override WinProc
		/// </summary>
		void CustomRichTextBox::WndProc(Message* m)
		{		
			MirrorWndProc(m);
			switch (m->Msg)
			{
			case WM_PAINT:
				{
					//Don't draw the control while parsing to avoid flicker.
					if (mParsing)
					{
						return;
					}
					break;
				}
			}
			System::Windows::Forms::RichTextBox::WndProc(m);

			switch (m->Msg)
			{
			case WM_LBUTTONDOWN:
				{
					mMirror->AdjustCaretPos(SelectionStart, SelectionLength);
					break;
				}

			case WM_KEYDOWN:
				{
					switch ((Keys)(int)m->WParam)
					{						
					case Keys::Enter:
					case Keys::Back:
					case Keys::Left:
					case Keys::Right:
					case Keys::Up:
					case Keys::Down:
					case Keys::Delete:
					case Keys::Home:
					case Keys::End:
						{
							mMirror->AdjustCaretPos(SelectionStart, SelectionLength);
							break;
						}
					}

				}
			}
		}

		/// <summary>
		/// 
		/// </summary>
		void CustomRichTextBox::OnVScroll(EventArgs* e)
		{
			if (mParsing) return;
			System::Windows::Forms::RichTextBox::OnVScroll(e);
		}

		/// <summary>
		/// Text origin backup for custom textbox
		/// </summary>
		void CustomRichTextBox::OnTextChanged(EventArgs* e)
		{
			if (mImeEndStart)
			{
				if (!mImeUpdated)
				{
					TextChange(e);
					mImeUpdated = true;
				}
			}
			else
			{
				TextChange(e);	
			}			
		}
	
#pragma endregion

#pragma region Scrollbar positions functions
		/// <summary>
		/// Sends a win32 message to get the scrollbars' position.
		/// </summary>
		/// <returns>a POINT structore containing horizontal and vertical scrollbar position.</returns>
		POINT* CustomRichTextBox::GetScrollPos()
		{
			POINT* res = new POINT();
			IntPtr* ptr = __nogc new IntPtr(res);

			//copy form winuser.h for call correct sencmessage funtion
#ifdef UNICODE
			SendMessageW((HWND)Handle.ToPointer(), EM_GETSCROLLPOS, 0, (LPARAM)ptr->ToPointer());
#else
			SendMessageA((HWND)Handle.ToPointer(), EM_GETSCROLLPOS, 0, (LPARAM)ptr->ToPointer());
#endif // !UNICODE

			delete ptr;
			return res;

		}

				 /// <summary>
				 /// Sends a win32 message to set scrollbars position.
				 /// </summary>
				 /// <param name="point">a POINT conatining H/Vscrollbar scrollpos.</param>
		void CustomRichTextBox::SetScrollPos(POINT* point)
		{
			IntPtr* ptr = __nogc new IntPtr(point);

			//copy form winuser.h for call correct sencmessage funtion
#ifdef UNICODE
			SendMessageW((HWND)Handle.ToPointer(), EM_SETSCROLLPOS, 0, (LPARAM)ptr->ToPointer());
#else
			SendMessageA((HWND)Handle.ToPointer(), EM_SETSCROLLPOS, 0, (LPARAM)ptr->ToPointer());
#endif // !UNICODE
			delete ptr;
		}
#pragma endregion
#pragma endregion 

#pragma region class CustomRichTextBox
		CMirrorRichTextBox::CMirrorRichTextBox()
		{
			mParent = NULL;
			mCaseSesitive = false;
			mParsing = false;
			mTranslatedText = "";
			mStartToken = "[";
			mCloseToken = "]";
			mBlockList = new List<CTextBlock*>();
			mColors = new List<Color>();
			mColors->Add(Color::Red);
			mColors->Add(Color::Violet);
			mColors->Add(Color::Blue);
			mColors->Add(Color::Magenta);
		}

#pragma region Members function

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::WndProcCaller(Message* m)
		{
			WndProc(m);
		}

		int CMirrorRichTextBox::GetCorrectSelectionStart()
		{
			int SSResult = 0;
			int SSRemain = SelectionStart;

			CTextBlock* pItem = NULL;

			//Deal with SelectionStart
			for (int i = 0; i < mBlockList->Count; i++)
			{
				if (SSRemain <= 0)
					break;

				pItem = mBlockList->Item[i];

				switch (pItem->Kind)
				{
				case CTextBlock::PB_NORMAL:
					{
						//SelectionStart exceed the block
						if (SSRemain >= pItem->OriginalText->Length)
						{
							//add SSResult the block length
							SSResult += pItem->OriginalText->Length;
							SSRemain -= pItem->OriginalText->Length;
						}
						else //last block
						{
							SSResult += SSRemain;
							SSRemain = 0;
						}
						break;
					}
				case CTextBlock::PB_TRANSLATED:
					{
						if (SSRemain >= pItem->OriginalText->Length) 
						{
							SSResult += pItem->TranslatedText->Length;
							SSRemain -= pItem->OriginalText->Length;									
						}
						else
						{
							SSResult += SSRemain;
							SSRemain = 0;
						}
						break;
					}
				case CTextBlock::PB_NEWLINE:
					{
						if (SSRemain >= RETURN_SYMBOL_LEN)
						{
							SSResult += RETURN_SYMBOL_LEN;
							SSRemain -= RETURN_SYMBOL_LEN;								
						}
						break;
					}
				}
			}

			return SSResult;
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::AdjustCaretPos(int ParentSelectionStart, int ParentSelectionLength)
		{			                
			int SSResult    = 0;
			int SLResult    = 0;
			int SSRemain    = ParentSelectionStart;
			int SLRemain    = ParentSelectionLength;
			int LastBlock   = 0;
			int LastBlockSS = 0;	

			//no content Set as parent value
			if (mBlockList->Count == 0)
			{
				SSResult = ParentSelectionStart;
				SLResult = ParentSelectionLength;
			}

			CTextBlock* pItem = NULL;
			//Deal with SelectionStart
			//for each block
			for (int i = 0; i < mBlockList->Count; i++)
			{
				if (SSRemain <= 0)
					break;

				pItem = mBlockList->Item[i];

				switch (pItem->Kind)
				{
					//normal block
				case CTextBlock::PB_NORMAL:
					{
						//SelectionStart exceed the block
						if (SSRemain >= pItem->OriginalText->Length)
						{
							//add SSResult the block length
							SSResult += pItem->OriginalText->Length;
							SSRemain -= pItem->OriginalText->Length;									
						}
						else //last block
						{
							SSResult += SSRemain;
							LastBlock = i;
							LastBlockSS = SSRemain;
							SSRemain = 0;
						}  
						break;
					}
				case CTextBlock::PB_TRANSLATED:
					{
						//SelectionStart exceed the block
						if (SSRemain >= pItem->TranslatedText->Length)
						{
							//add SSResult the block length
							SSResult += pItem->OriginalText->Length;
							SSRemain -= pItem->TranslatedText->Length;								
						}
						else //last block
						{
							SSResult += SSRemain;
							LastBlock = i;
							LastBlockSS = SSRemain;
							SSRemain = 0;

						}  
						break;
					}
				case CTextBlock::PB_NEWLINE:
					{
						if (SSRemain >= RETURN_SYMBOL_LEN)
						{
							SSResult += RETURN_SYMBOL_LEN;
							SSRemain -= RETURN_SYMBOL_LEN;							
						}
						break;
					}
				}
			}

			//Deal with SelectionLength
			for (int i = LastBlock; i < mBlockList->Count; i++)
			{
				if (SLRemain <= 0)
					break;

				pItem = mBlockList->Item[i];

				if (i == LastBlock)
				{
					int LBRemainLen = pItem->OriginalText->Length - LastBlockSS;

					if (SLRemain <= LBRemainLen)
					{
						SLResult = SLRemain;
						break;
					}
					else
					{
						SLResult += LBRemainLen;
						SLRemain -= LBRemainLen;
						continue;
					}
				}

				switch (pItem->Kind)
				{
				case CTextBlock::PB_NORMAL:
					{
						if (SLRemain > pItem->OriginalText->Length)
						{
							SLResult += pItem->OriginalText->Length;
							SLRemain -= pItem->OriginalText->Length;										
						}
						else //last block
						{
							SLResult += SLRemain;
							SLRemain = 0;
						}

						break;
					}
				case CTextBlock::PB_TRANSLATED:
					{
						if (SLRemain > pItem->TranslatedText->Length)
						{
							SLResult += pItem->OriginalText->Length;
							SLRemain -= pItem->TranslatedText->Length;										
						}
						else //last block
						{
							SLResult += SLRemain;
							SLRemain = 0;
						}
						break;
					}
				case CTextBlock::PB_NEWLINE:
					{
						if (SLRemain >= RETURN_SYMBOL_LEN)
						{
							SLResult += RETURN_SYMBOL_LEN;
							SLRemain -= RETURN_SYMBOL_LEN;									
						}
						break;
					}
				}
			}

			SelectionStart  = SSResult;
			SelectionLength = SLResult;
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		CTextBlock* CMirrorRichTextBox::AddPragraphBlock(int Kind, int PBTKind, String* Original, String* Translated)
		{
			CTextBlock* NewBlock = NULL;
			NewBlock = new CTextBlock();
			NewBlock->Kind = Kind;
			NewBlock->PBTKind = PBTKind;
			NewBlock->OriginalText = Original;
			NewBlock->TranslatedText = Translated;
			mBlockList->Add(NewBlock);
			return NewBlock;
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::TransletText()
		{
			mBlockList->Clear();

			wchar_t nNewLine __gc [] = {'\n'};

			String* lines[] = Text->Replace("\\","\\\\")->Replace("{", "\\{")->Replace("}", "\\}")->Replace("\r", "")->Split(nNewLine);

			for (int lineCounter = 0; lineCounter < lines->Length; lineCounter++)
			{
				if (lineCounter != 0)
				{
					AddPragraphBlock(CTextBlock::PB_NEWLINE, 0, "", "");
				}

				String* line = lines[lineCounter];

				String* tmpStartToken = mCaseSesitive ? mStartToken : mStartToken->ToUpper();
				String* tmpCloseToken = mCaseSesitive ? mCloseToken : mCloseToken->ToUpper();

				//process until string is empty
				while (line != "")
				{
					int ind1 = -1;
					int ind2 = -1;

					ind2 = line->IndexOf(tmpCloseToken);
					String* sub;
					String* sub1;
					String* sub2;

					//find first EndToken
					if (ind2 >= 0)
					{
						sub = line->Substring(0, ind2 + 1);

						ind1 = sub->LastIndexOf(tmpStartToken);

						//the the last matched StrartToken 
						if (ind1 >= 0)
						{
							sub1 = sub->Substring(0, ind1);
							sub2 = sub->Substring(ind1, ind2 - ind1 + 1);

							std::string tempStr = StringToChar(sub2->Trim(tmpStartToken->ToCharArray())->Trim(tmpCloseToken->ToCharArray()));
							const char* pszKeyWord = tempStr.c_str();

							char TransText [512];

							int iType = CTextBlock::PBT_KIND_NOT_FOUND;

							sprintf(TransText, "");

							int iGUID = atoi( pszKeyWord );

							// 20120813 Edit by ukilue (需求：小宏)
							// 替代字串可以找出其他的Key String Content

							//if( (iGUID <= 100000) && (strcmp( pszKeyWord, "ZONE_" ) != 0))
							//{
							//	sprintf(TransText, "<%s_查無資料> ", pszKeyWord);
							//}
							//else
							//{
							AddPragraphBlock(CTextBlock::PB_NORMAL, 0, sub1, sub1);
							static_cast<CustomRichTextBox*>(Parent)->KeyWord(pszKeyWord, TransText, iType);

							//查無資料
							if (strcmp(pszKeyWord, TransText) == 0)
							{
								sprintf(TransText, "<%s_查無資料> ", pszKeyWord);
							}	
							//}
							if (strcmp(" ", TransText) != 0)
							{
								AddPragraphBlock(CTextBlock::PB_TRANSLATED, iType, sub2, TransText);
							}

						}
						//no matched StrartToken
						else
						{
							AddPragraphBlock(0, 0, sub, sub);
						}

						if (ind2 + 1 < line->Length)
							line = line->Substring(ind2 + 1, line->Length - (ind2 + 1));
						else
							line = "";

					}
					//no block need to process
					else
					{
						AddPragraphBlock(CTextBlock::PB_NORMAL, 0, line, line);

						line = "";
					}
				}
			}
			AddPragraphBlock(CTextBlock::PB_NEWLINE, 0, "", "");


			StringBuilder* sb = new
				StringBuilder((int)(Text->Length * 1.5 + 150));

			//Start of Rtf
			sb->Append("{"); 

			//Rtf header
			sb->Append("\\rtf1\\fbidis\\ansi\\ansicpg950\\deff0\\deflang1033\\deflangfe1028");

			//Start of Font Table
			sb->Append("{");
			sb->Append("\\fonttbl");

			//Font table creation
			int fontCounter = 0;
			Hashtable* fonts = new Hashtable();

			AddFontToTable(sb, Font, fontCounter, fonts);

			//end of font table
			sb->Append("}\n"); 

			//Start of ColorTable
			sb->Append("{");
			sb->Append("\\colortbl ;");

			Hashtable* colors = new Hashtable();
			int colorCounter = 1;

			AddColorToTable(sb, ForeColor, colorCounter, colors);
			AddColorToTable(sb, BackColor, colorCounter, colors);

			for (int i = 0; i < mColors->Count; i++)
			{
				AddColorToTable(sb, mColors->Item[i], colorCounter, colors);
			}				

			//end of color table
			sb->Append("}\n");  

			//Parsing text
			sb->Append("\\viewkind4\\uc1\\pard\\ltrpar");

			SetSettings(sb, Font, ForeColor, colors, fonts);

			CTextBlock* pItem = NULL;
			for (int i = 0; i < mBlockList->Count; i++)
			{
				pItem = mBlockList->Item[i];
				switch (pItem->Kind)
				{
				case CTextBlock::PB_NORMAL:
					{							
						sb->Append(StrToRtf(pItem->TranslatedText));
						break;
					}
				case CTextBlock::PB_TRANSLATED:
					{
						SetSettings(sb, Font, mColors->Item[pItem->PBTKind], colors, fonts);
						sb->Append(pItem->TranslatedText);
						SetSettings(sb, Font, ForeColor, colors, fonts);
						break;
					}
				case CTextBlock::PB_NEWLINE:
					{
						AddNewLine(sb);
						break;
					}
				}
			}

			//End of Rft;
			sb->Append("}\n");

			mTranslatedText = sb->ToString();
		}

#pragma endregion

#pragma region Overriden methods

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::OnTextChanged(EventArgs* e)
		{
			if (mParsing)
				return;

			mParsing = true;

			LockWindowUpdate((HWND)Handle.ToPointer());

			System::Windows::Forms::RichTextBox::OnTextChanged(e);

			TransletText();

			mParsing = false;

			LockWindowUpdate((HWND)0);
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::WndProc(Message* m)
		{
			switch (m->Msg)
			{
			case WM_PAINT:
				{
					//Don't draw the control while parsing to avoid flicker.
					if (mParsing)
					{
						return;
					}
					break;
				}
			}
			System::Windows::Forms::RichTextBox::WndProc(m);
		}
#pragma endregion

#pragma region Rtf building helper functions

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::SetSettings(StringBuilder* sb, System::Drawing::Font* font, Color color, Hashtable* colors, Hashtable* fonts)
		{
			SetColor(sb, color, colors);
			SetFont(sb, font, fonts);
			SetFontSize(sb, (int)font->Size);
			EndTags(sb);
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::SetColor(StringBuilder* sb, Color color, Hashtable* colors)
		{
			sb->Append("\\cf")->Append(colors->Item[__box(color)]);
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::SetBackColor(StringBuilder* sb, Color color, Hashtable* colors)
		{
			sb->Append("\\cb")->Append(colors->Item[__box(color)]);
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::SetFont(StringBuilder* sb, System::Drawing::Font* font, Hashtable* fonts)
		{
			if (font == NULL) return;
			sb->Append("\\f")->Append(fonts->Item[font->Name]);
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::SetFontSize(StringBuilder* sb, int size)
		{
			sb->Append("\\fs")->Append(size * 2);
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::AddNewLine(StringBuilder* sb)
		{
			sb->Append("\\par\n");
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::EndTags(StringBuilder* sb)
		{				
			sb->Append(" ");
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::AddFontToTable(StringBuilder* sb, System::Drawing::Font* font, int& counter, Hashtable* fonts)
		{

			sb->Append("{\\f")->Append(counter)->Append("\\fnil\\fcharset136")->Append(StrToRtf(font->Name))->Append(";}");
			fonts->Add(font->Name, __box(counter++));
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		void CMirrorRichTextBox::AddColorToTable(StringBuilder* sb, Color color, int& counter, Hashtable* colors)
		{

			sb->Append("\\red")->Append(color.R)->Append("\\green")->Append(color.G)->Append("\\blue")
				->Append(color.B)->Append(";");
			colors->Add(__box(color), __box(counter++));
		}

		//-----------------------------------------------------------------------------------
		//
		//-----------------------------------------------------------------------------------
		String* CMirrorRichTextBox::StrToRtf(String* str)
		{
			int length = str->Length;
			int z = (int)'z';
			StringBuilder* ret = new StringBuilder(length);			

			for(int i = 0; i < length; i++) 
			{
				wchar_t ch = str->Chars[i];

				if(((int)ch) > z) 
				{
					Encoding* targetEncoding;

					// Gets the encoding for the specified code page.
					targetEncoding = Encoding::Default;

					// Gets the byte representation of the specified string.
					Byte encodedChars __gc [] = targetEncoding->GetBytes(__box(str->Chars[i])->ToString());
					for(int j=0; j<encodedChars->Length;j++)
					{							
						String* st = __box(encodedChars[j])->ToString();
						ret->Append("\\'")->Append(__box(INT32::Parse(st))->ToString("X")->ToLower());
					}
				}
				else 
				{
					ret->Append(ch);
				}
			}
			return ret->ToString();
		}


#pragma endregion

#pragma endregion 
	}
}