// GUIConsView.cpp : implementation of the CGUIConsView class
//

#include "stdafx.h"
#include "GUICons.h"

#include "GUIConsDoc.h"
#include "CntrItem.h"
#define GUICONSVIEW_FILE
#include "GUIConsView.h"

#include "mainfrm.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#include "../Linedit/char_io.h"


/////////////////////////////////////////////////////////////////////////////
// CGUIConsView

IMPLEMENT_DYNCREATE(CGUIConsView, CRichEditView)

BEGIN_MESSAGE_MAP(CGUIConsView, CRichEditView)
	//{{AFX_MSG_MAP(CGUIConsView)
	ON_WM_DESTROY()
	ON_WM_CHAR()
	ON_WM_KEYDOWN()
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGUIConsView construction/destruction

CGUIConsView::CGUIConsView()
{
	m_nWordWrap = CRichEditView::WrapNone;
	m_curCaretPos = 0;
}

CGUIConsView::~CGUIConsView()
{
}

BOOL CGUIConsView::PreCreateWindow(CREATESTRUCT& cs)
{
    BOOL bRes = CRichEditView::PreCreateWindow(cs);
	cs.style |= ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL;
	return bRes;
}




void CGUIConsView::OnInitialUpdate()
{
	CRichEditView::OnInitialUpdate();


	// Set the printing margins (720 twips = 1/2 inch).
	SetMargins(CRect(720, 720, 720, 720));

	theView = this;

	CRichEditCtrl& ce = GetRichEditCtrl();

	DWORD oldMask = ce.GetEventMask();
	ce.SetEventMask(oldMask | EN_SELCHANGE | EN_MSGFILTER );

}

void CGUIConsView::OnDestroy()
{
	// Deactivate the item on destruction; this is important
	// when a splitter view is being used.
   CRichEditView::OnDestroy();
   COleClientItem* pActiveItem = GetDocument()->GetInPlaceActiveItem(this);
   if (pActiveItem != NULL && pActiveItem->GetActiveView() == this)
   {
      pActiveItem->Deactivate();
      ASSERT(GetDocument()->GetInPlaceActiveItem(this) == NULL);
   }
}


/////////////////////////////////////////////////////////////////////////////
// CGUIConsView diagnostics

#ifdef _DEBUG
void CGUIConsView::AssertValid() const
{
	CRichEditView::AssertValid();
}

void CGUIConsView::Dump(CDumpContext& dc) const
{
	CRichEditView::Dump(dc);
}

CGUIConsDoc* CGUIConsView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CGUIConsDoc)));
	return (CGUIConsDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CGUIConsView message handlers

void CGUIConsView::Backd(int n)
{
	if (n==0) return;

	long SelStart, SelEnd; 

 	GetRichEditCtrl().GetSel(SelStart,SelEnd); 
	SelStart=((SelStart<n)?0:SelStart-n); 
	GetRichEditCtrl().SetSel(SelStart,SelStart); 
	UpdateCaretPos();
}

void CGUIConsView::Forwd(int n)
{
	if (n==0) return;
	
	long SelStart, SelEnd; 

	CRichEditCtrl& ce = GetRichEditCtrl();
	int lidx = ce.LineIndex();
	int lg = ce.LineLength();
	
	ce.GetSel(SelStart,SelEnd); 
	SelStart = min(SelStart+n,lidx+lg); 
	GetRichEditCtrl().SetSel(SelStart,SelStart); 
	UpdateCaretPos();
} 

void CGUIConsView::Displ(int n, char *pos)
{
	Put_NChars(n,pos);
}

#define EscDown			( (::GetKeyState(VK_ESCAPE) & 0xA0) != 0 )
#define CtrlDown		( (::GetKeyState(VK_CONTROL) & 0xA0) != 0 )

void CGUIConsView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// Les messages caractères ne sont pas produits pour les caractères non
	// affichables et les MAJ, CTRL, FXX, deplacement, INSER et SUPPR.
	// On voit par contre les TAB, BACKSPACE et RETURN, mais pas DELETE


	CheckCaretPos();
    EnterCriticalSection(&cs);

	if (CtrlDown && nChar==VK_SPACE)
		nChar = KEY_CTRL(' ');

	for(int i=0;i < (int)nRepCnt;i++)
		ToKbdBuff(nChar);
	
	LeaveCriticalSection(&cs);
	SetEvent(kbd_event);
}


void CGUIConsView::Put_Char(int c) 
{
	CRichEditCtrl& ce = GetRichEditCtrl();
	int lidx = ce.LineIndex();
	int lg = ce.LineLength();
	long selStart, selEnd; 
	
	ce.GetSel(selStart,selEnd);

	switch (c) {
	
	case '\n':
		ce.SetSel(lidx+lg,lidx+lg);
		break;

	default:
		ce.SetSel(selStart,selStart+1);
	
	}
	char buf[2] = { c, '\0' };
	ce.ReplaceSel(buf);
	UpdateCaretPos();
}

void CGUIConsView::Put_NChars(int n, char *c)
{
	CRichEditCtrl& ce = GetRichEditCtrl();
	int lidx = ce.LineIndex();
	int lg = ce.LineLength();
	long selStart, selEnd; 
	ce.GetSel(selStart,selEnd);
	
	selEnd = ((lidx+lg < selStart+n) ? lidx+lg : selStart+n);
	ce.SetSel(selStart,selEnd);
	
	char old=c[n];
	c[n]='\0';
	ce.ReplaceSel(c);
	c[n]=old;
	UpdateCaretPos();

}

void CGUIConsView::Display_String(char *str)
{
	CRichEditCtrl& ce = GetRichEditCtrl();
	ce.ReplaceSel(str);
	UpdateCaretPos();
}

void CGUIConsView::Erase(int n)
{
	if (n==0) return;

    CRichEditCtrl& ce = GetRichEditCtrl();
	long selStart, selEnd; 
	
	ce.GetSel(selStart,selEnd);
	ce.SetSel(selStart,selStart+n);
	ce.Clear();

	UpdateCaretPos();
}


void CGUIConsView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
    int c=nChar;

    if (!(c>=0x21 && c<=0x2F || c>=0x5B && c<=0x5D || c>=0x70 && c<=0x87 ||
          c>=0x90 && c<=0x91))
        return;

    c = (CtrlDown) ? (2<<8) | c : (1<<8) | c;

    CheckCaretPos();
	EnterCriticalSection(&cs);

	for(int i=0;i < (int) nRepCnt;i++)
		ToKbdBuff(c);

	LeaveCriticalSection(&cs);
	SetEvent(kbd_event);
}

/////////////////////////////////////////////////////////////////////////////

int CGUIConsView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{

	TEXTMETRIC tm;

	if (CRichEditView::OnCreate(lpCreateStruct) == -1)
		return -1;

	CDC *pDC = GetDC();

	if (m_font.CreateFont(0,0,0,0,500,0,0,0,DEFAULT_CHARSET,0,0,0,FIXED_PITCH,NULL))
	{
		pDC->SelectObject (&m_font);
		SetFont(&m_font,true);
	}

	pDC->GetTextMetrics(&tm);
    char_size_x=tm.tmAveCharWidth;
    char_size_y=tm.tmHeight+tm.tmExternalLeading;

	return 0;
}


void CGUIConsView::OnSize(UINT nType, int cx, int cy) 
{
	CRichEditView::OnSize(nType, cx, cy);

	if (char_size_x != 0 && char_size_y != 0) {
		win_size_col=max(1,cx / char_size_x);
		win_size_row=max(1,cy / char_size_y);
	}

}


void CGUIConsView::OnEditPaste() 
{
	if ( !OpenClipboard() )
		return;

	HANDLE  h = ::GetClipboardData( CF_TEXT );
    char   *p=(char *) h;

    CheckCaretPos();
  	EnterCriticalSection(&cs);

	while(*p)
		ToKbdBuff(*p++);
	
	LeaveCriticalSection(&cs);
	SetEvent(kbd_event);

    CloseClipboard();
}


void CGUIConsView::ToggleInsert() 
{
	CheckCaretPos();
    EnterCriticalSection(&cs);

    ToKbdBuff(KEY_CTRL('V'));

    LeaveCriticalSection(&cs);
	SetEvent(kbd_event);	
}


void CGUIConsView::UpdateCaretPos()
{
	long selStart, selEnd;
	GetRichEditCtrl().GetSel(selStart,selEnd);
	m_curCaretPos = selEnd;
}

void CGUIConsView::CheckCaretPos()
{
    CRichEditCtrl& ce = GetRichEditCtrl();
	long selStart, selEnd; 
	int nblin = ce.GetLineCount();
	int curli = ce.LineFromChar(-1); // 0-based number of the line that contains the caret
	int lgTexte = GetTextLength();
	int depl;

	ce.GetSel(selStart,selEnd);

    if (selStart == m_curCaretPos)
		return;

	if (curli != nblin-1) {
		ce.SetSel(m_curCaretPos,m_curCaretPos);
		return;
	}


    EnterCriticalSection(&cs);

	ToKbdBuff(KEY_CTRL('E'));
	m_curCaretPos = lgTexte;
	ce.SetSel(lgTexte,lgTexte);
	

	// We must send Ctrl-B of Ctrl-F chars into KbdBuff
	depl = lgTexte - selEnd;
	for (int i = 0; i < depl; i++)
		ToKbdBuff(KEY_CTRL('B'));

	LeaveCriticalSection(&cs);
	SetEvent(kbd_event);
}

