#include "client.h"
#include <wx/fontdlg.h>
#include "wx/notebook.h"
/*
autologout (+) 
The first word is the number of minutes of inactivity before automatic logout. The optional second word is the number of minutes of inactivity before automatic locking. When the shell automatically logs out, it prints `auto-logout', sets the variable logout to `automatic' and exits. When the shell automatically locks, the user is required to enter his password to continue working. Five incorrect attempts result in automatic logout. Set to `60' (automatic logout after 60 minutes, and no locking) by default in login and superuser shells, but not if the shell thinks it is running under a window system (i.e., the DISPLAY environment variable is set), the tty is a pseudo-tty (pty) or the shell was not so compiled (see the version shell variable). See also the afsuser and logout shell variables. 

version (+) 
The version ID stamp. It contains the shell's version number (see tcsh), origin, release date, vendor, operating system and machine (see VENDOR, OSTYPE and MACHTYPE) and a comma-separated list of options which were set at compile time. Options which are set by default in the distribution are noted. 

8b
The shell is eight bit clean; default 
7b
The shell is not eight bit clean 
nls
The system's NLS is used; default for systems with NLS 
lf
Login shells execute /etc/csh.login before instead of after /etc/csh.cshrc and ~/.login before instead of after ~/.tcshrc and ~/.history. 
dl
`.' is put last in path for security; default 
nd
`.' is omitted from path for security 
vi
vi-style editing is the default rather than emacs 
dtr
Login shells drop DTR when exiting 
bye
bye is a synonym for logout and log is an alternate name for watchlog 
al
autologout is enabled; default 
kan
Kanji is used if appropriate according to locale settings, unless the nokanji shell variable is set 
sm
The system's malloc(3) is used 
hb
The `#!<program> <args>' convention is emulated when executing shell scripts 
ng
The newgrp builtin is available 
rh
The shell attempts to set the REMOTEHOST environment variable 
afs
The shell verifies your password with the kerberos server if local authentication fails. The afsuser shell variable or the AFSUSER environment variable override your local username if set. 
An administrator may enter additional strings to indicate differences in the local version. 


 * */
//#include "bbsrc/common.h"
#ifdef __WXGTK__
wxWindow *g_focustelnet=NULL;
#endif

extern wxColour TerminalColors[2][8];

BEGIN_EVENT_TABLE(enjTelnetPanel, wxWindow)
	//EVT_SCROLL(enjTelnetPanel::OnScroll)
	EVT_RIGHT_UP(enjTelnetPanel::OnMouseRightUp)
	EVT_LEFT_DOWN(enjTelnetPanel::OnMouseLeftDown)
	EVT_MOTION(enjTelnetPanel::OnMouseMotion)
	EVT_LEFT_UP(enjTelnetPanel::OnMouseLeftUp)
	EVT_MOUSEWHEEL(enjTelnetPanel::OnMouseWheel)
	//EVT_MIDDLE_DOWN(enjTelnetPanel::OnMouseMiddleDown)
	EVT_LEFT_DCLICK(enjTelnetPanel::OnMouseLeftDoubleClick)

	EVT_KEY_DOWN(enjTelnetPanel::OnKeyDown)
	EVT_KEY_UP(enjTelnetPanel::OnKeyUp)
	EVT_CHAR(enjTelnetPanel::OnChar)
	EVT_PAINT(enjTelnetPanel::OnPaint)
	EVT_SIZE(enjTelnetPanel::OnResize)
	EVT_SOCKET(wxID_ANY,     enjTelnetPanel::OnSocketEvent)
	EVT_KILL_FOCUS(enjTelnetPanel::OnKillFocus)
	EVT_SET_FOCUS(enjTelnetPanel::OnSetFocus)
	//EVT_ERASE_BACKGROUND(enjTelnetPanel::OnEraseBackground)
	EVT_TIMER(wxID_ANY,enjTelnetPanel::OnTimer)
	EVT_CLOSE(enjTelnetPanel::OnClose)
    EVT_END_PROCESS(wxID_ANY, enjTelnetPanel::OnProcessTerm)
END_EVENT_TABLE()

enjTelnetPanel::~enjTelnetPanel()
{
		//wxLogMessage("destroy");
//		telnet->DestroySocket();
			delete telnet;
			telnet=NULL;
};

void enjTelnetPanel::OnClose(wxCloseEvent &event)
{
	wxLogMessage("close");
}
void enjTelnetPanel::OnTimer(wxTimerEvent &event)
{
	//wxLogMessage("timer event %d",event.GetId());	
	if ( connect_state == 1 ) {
		wxFont fnt = GetCurrentFont();
		if ( fnt != pre_fnt ) {
				wxLogMessage("font changed");
				telnet->OnResize();
				pre_fnt = fnt;
		}
		if ( TerminalColors[0][0] != pre_bg ){
			SetBackgroundColour(TerminalColors[0][0]);
			pre_bg = TerminalColors[0][0];
			telnet->OnResize();
		}
		telnet->OnSocketEvent_Input();

		//if ( ticks > TELNET_PING_INTERVAL ) {
		/*
		if ( telnet->ticks > 10000 ) {
			wxLogMessage("active telnet at %d",telnet->ticks);
			telnet->ticks = 0;
			unsigned char tmp[2];
			tmp[0] = 255;//IAC;
			tmp[1] = 244;//AYT;
			//tmp[0] = 27;
			telnet->UserSend((char*)tmp,2);
		}else{
			telnet->ticks+=TELNET_TIMER;
		}
		*/
	}
}

void enjTelnetPanel::OnEraseBackground(wxEraseEvent & event)
{
	//wxLogMessage("erase background");
}

void enjTelnetPanel::OnSetFocus(wxFocusEvent & event)
{
	if ( telnet && telnet->lost_focus ) {
	telnet->OnSetFocus(event);
#ifdef __WXDEBUG__
	//wxLogMessage("set focus");
#endif
#ifdef __WXGTK__
	g_focustelnet=this;
#endif
	}
}

void enjTelnetPanel::OnKillFocus(wxFocusEvent & event)
{
	if ( telnet && !telnet->lost_focus ) {
		telnet->OnKillFocus(event);
#ifdef __WXDEBUG__
		//wxLogMessage("lost focus");
#endif
	}
}

void enjTelnetPanel::OnScroll(wxScrollEvent & event)
{
	//wxLogMessage("OnScroll enjTelnetPanel");
	telnet->Scrolled(event);
}

void enjTelnetPanel::OnMouseLeftUp(wxMouseEvent& event)
{
	//if (!event.ButtonDClick()) return;
	//if (!event.Dragging()) return;
	if(telnet)
	{
		telnet->OnMouseLeftUp(event);
		//telnet->CopySelectionToClipboard(false);
		//GetParent()->AddPendingEvent(event);
		//wxLogMessage("mouse left up");
	}
	//lost_focus=0;
}

void enjTelnetPanel::OnMouseLeftDown(wxMouseEvent& event)
{
	SetFocus();
	if(telnet)
	{
		telnet->OnMouseLeftDown(event);
		//wxLogMessage("mouse left down");
	}
}

void enjTelnetPanel::OnMouseRightUp(wxMouseEvent& event)
{
	if(telnet)
	{
		telnet->CancelSelection();
		SetFocus();
	}
	if ( event.ControlDown() ) {
		extern wxMenu *right_menu;
		PopupMenu(right_menu,event.GetPosition());
	}else{
		if (telnet){
			telnet->PasteFromClipboard(false);
		}
	}
		//GetParent()->AddPendingEvent(event);
}

void enjTelnetPanel::OnMouseWheel(wxMouseEvent& event)
{
	if(telnet)
	{
		int rotation =  event.GetWheelRotation();
		int delta = event.GetWheelDelta();
		//wxLogMessage("Mouse wheel rotation %d delta %d",rotation,delta);
		telnet->ScrollLines(rotation>0?1:0,abs(rotation/delta));
		//telnet->OnMouseMotion(event);
	}
}

void enjTelnetPanel::OnMouseMotion(wxMouseEvent& event)
{
	if(telnet)
	{
		telnet->OnMouseMotion(event);
	}
}

void enjTelnetPanel::OnMouseLeftDoubleClick(wxMouseEvent& event)
{
	if(telnet)
	{
		//telnet->CancelSelection();
		telnet->OnMouseLeftDoubleClick(event);
		telnet->CopySelectionToClipboard(false);
	}
}

enjTelnetPanel::enjTelnetPanel(wxWindow *parent,  wxWindow *tab,wxWindowID id, const wxPoint &pos, const wxSize &size)
		 : wxWindow( parent, id, pos, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
		 //: wxScrolledWindow( parent, id, pos, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS )
{
	control_down=0;
	is_show=0;
	//ping_interval=0;
	ticks=0;
	SetBackgroundColour(TerminalColors[0][0]);
	//SetBackgroundColour(*wxBLACK);
	//tabwin=NULL;
	tabwin=tab;
	telnet = NULL;
	//sockid=TELNET_SOCKET_ID;
	//sockid=wxNewId();
	sockid=wxID_ANY;


	//建立游標
	//caret.Create(this, 8,2);
	caret = new wxCaret(this, 8, 2);
	//caret->SetBlinkTime(10000);
	this->SetCaret( caret );
	connect_state = 0;
	isAltDown = false;
	m_timer.SetOwner(this);
	//Connect();
}

bool enjTelnetPanel::NewConnection(SiteInfo *site)
{
	bool suc=false;
	init_font();
	if (telnet == NULL ) {
		telnet = new SCD_Telnet(this,sockid,sbar);
	}
	EnableNaws(true);
	//si.port=port;
	//telnet->setScrolledWindow(this);
	connect_state = 0;
	suc=telnet->connect(*site);
	telnet->Show();
	m_timer.Start(TELNET_TIMER);
	is_show=1;
	return suc;
}

bool enjTelnetPanel::NewConnection(wxString hostname,int port)
{
	bool suc=false;
	init_font();
	//init_Icons();
	//UserSetFont(this);
	/*
	wxFont fnt = wxGetFontFromUser( this , global_default_fnt );
	global_default_fnt = fnt;
	global_default_fnt.SetNoAntiAliasing( !blAA );
	wxLogMessage("Set font %s",	fnt.GetNativeFontInfoDesc());
	*/

	SiteInfo si;
	si.Init();
	int pro = hostname.Find("://");
	wxString pro_name;
	wxString tmp_hostname;
	wxString real_hostname;
	if ( pro == -1 ) {
		si.protocol = SOCK_TELNET;
		tmp_hostname = hostname;
	}else{
		wxString pro_name(hostname.SubString(0,pro-1));
		tmp_hostname = hostname.Mid(pro+3);
		if ( pro_name == "ssh" ) {
			si.protocol = SOCK_SSH;
		}else if ( pro_name == "telnet" ) {
			si.protocol = SOCK_TELNET;
		}else if ( pro_name == "shell" ) {
			si.protocol = SOCK_EXECMD ;
		}else {
  			wxMessageBox(wxString::Format("Unknow protocol %s",pro_name),
               _("Login"),
               wxOK | wxICON_INFORMATION, this);
			return false;
		}
	}
	if ( si.protocol == SOCK_EXECMD ) {
		real_hostname = tmp_hostname;
	}else{
		pro = tmp_hostname.Find(':');
		if ( pro == -1 ) {
			if ( si.protocol == SOCK_SSH ) {
				si.port = 22;
			}else{
				si.port = 23;
			}
			real_hostname = tmp_hostname;
		}else{
			{
				wxString port_num(tmp_hostname.Mid(pro+1));
				real_hostname = tmp_hostname.Mid(0,pro);
				long portint =0;
				if (si.protocol != SOCK_EXECMD && 
							!port_num.ToLong(&portint) ) {
	  				wxMessageBox(wxString::Format("Invalid portnum %s",port_num), _("Login"),
	               		wxOK | wxICON_INFORMATION, this);
					return false;
				}
				si.port = portint;
			}
		}
	}

	if (telnet == NULL ) {
		telnet = new SCD_Telnet(this,sockid,sbar);
	}
	EnableNaws(true);
	si.ip=real_hostname;
	//si.port=port;
	//telnet->setScrolledWindow(this);
	connect_state = 0;
	suc = telnet->connect(si);
	telnet->Show();
	m_timer.Start(TELNET_TIMER);
	is_show=1;
	return suc;
/*
	if( telnet )
	{	telnet->Hide();	}

	wxClientDC dc(this);
	dc.BeginDrawing();
	if( telnet ) {
		wxSize old_ws, new_ws;
		old_ws = telnet->getWindowSize();
		new_ws = t->getWindowSize();

		int l = new_ws.GetWidth();
		int r = old_ws.GetWidth();
		int t = new_ws.GetHeight();
		int b = old_ws.GetHeight();
		dc.SetBrush(*wxBLACK_BRUSH);
		if(l<r)	dc.DrawRectangle(l, 0, r-l, (t>b)?t:b);
		if(t<b)	dc.DrawRectangle(0, t, (l>r)?l:r, b-t);
	}

	dc.EndDrawing();
	*/
//#endif

	//now_telnet = t;

	//if( telnet )
	//{
//		now_telnet->EnableDrawing(false);
//		now_telnet->EnableDrawing(true);
/*
//		wxSize new_ws = now_telnet->getWindowSize();
//		now_telnet->repaint( &dc, 0, 0, new_ws.GetWidth(), new_ws.GetHeight() );
		wxSize new_ws = GetClientSize();

		now_telnet->BeginDrawing(&dc);
		now_telnet->repaint( &dc, 0, 0, 1000, 1000 );
		now_telnet->EndDrawing();
*/
	//}
}

void enjTelnetPanel::AssignScrollBar(wxScrollBar *sb)
{
	sbar=sb;
	//telnet->AssignScrollBar(sb);
}
void enjTelnetPanel::OnSocketEvent(wxSocketEvent &event)
{
		if( event.GetSocketEvent() == wxSOCKET_CONNECTION) {
				/*
			if ( tabwin && tabwin->IsKindOf(CLASSINFO(wxNotebook))){
				wxNotebook *nb = (wxNotebook *) tabwin;		
   		//		int nPages =  nb->GetPageCount();
    			int nSel = nb->GetSelection();
				nb->SetPageImage(nSel,BBMAN_ICON_CONNECTED);
			}
			*/
			//tabwin->	
			connect_state = 1;
			telnet->OnSocketEvent(event);
		}else if ( event.GetSocketEvent() == wxSOCKET_LOST ) {
				/*
			if ( tabwin && tabwin->IsKindOf(CLASSINFO(wxNotebook))){
				wxNotebook *nb = (wxNotebook *) tabwin;		
    			int nSel = nb->GetSelection();
				nb->SetPageImage(nSel,BBMAN_ICON_CLOSED);
			}
			*/
			if ( connect_state == 0 ) {
				telnet->parse( wxStringToCharPtr( wxString( _T("\x1b[1;1H\x1b[1;5;33;43m ") ) + gettext("Connection fail ( maybe server out-of-service, or wrong address )") + wxString(_T(" \x1b[m")) ) );
			}else if ( connect_state == 1 ) {
				telnet->parse( wxStringToCharPtr( wxString( _T("\x1b[1;1H\x1b[1;5;33;43m ") ) + gettext("Disconnected") + wxString(_T(" \x1b[m")) ) );
				connect_state = 2;
			}
		telnet->OnSocketEvent(event);
	}else if( event.GetSocketEvent() == wxSOCKET_INPUT ){
		//telnet->OnSocketEvent(event);
	}
}

void enjTelnetPanel::OnPaint(wxPaintEvent& WXUNUSED(event))
{
	wxPaintDC dc(this);
	if(telnet == NULL)	return;
	
	telnet->OnPaint(&dc);
}

void enjTelnetPanel::OnKeyDown(wxKeyEvent& event)
{
#ifdef __WXGTK__	// wxGTK 下的 event.AltDown() 沒有作用，必須透過這種方式模擬
	if( event.GetKeyCode() == 307 )	isAltDown = true;
	event.m_altDown = isAltDown;
#endif

	//這必須放在前面，不然可能會被 now_telnet->OnKeyDown(event); 呼叫 event.Skip();
//	GetParent()->ProcessEvent(event);
	telnet->ticks=0;
	if(telnet)	{
		int key = event.GetKeyCode();
		if (event.ShiftDown()) {
				switch (key)
				{
					case WXK_LEFT:
					case WXK_RIGHT:
					{
						//wxLogMessage("telnet key down shift+arrow");
						if ( tabwin ) {
								tabwin->ProcessEvent(event);
								return;
						}
						//((enjScrollTelnetPanel *)GetParent())->OnKeyDown(event);
						//GetParent()->ProcessEvent(event);

							/*
						if ( tabwin && tabwin->IsKindOf(CLASSINFO(wxNotebook))){
							wxNotebook *nb = (wxNotebook *) tabwin;		
   							int nPages =  nb->GetPageCount();
    						int nSel = nb->GetSelection();
							if ( key == WXK_RIGHT ) {
								nSel = nPages-1 > nSel? nSel+1:0;
								//nb->SetSelection(nSel);
								wxLogMessage("WXK_Right + Shift pages %d selection %d",
												nPages,nSel);
							}else{
								nSel = nSel > 0? nSel-1:nPages-1;
								wxLogMessage("WXK_LEFT + Shift pages %d selection %d",
												nPages,nSel);
							}
							nb->SetSelection(nSel);
							nb->GetCurrentPage()->SetFocus();

							return;
						}
							*/
					}
					break;
					case WXK_PAGEUP:
					case WXK_PRIOR:
					case WXK_NUMPAD_PRIOR:
					case WXK_NUMPAD_PAGEUP:
						//telnet->SetCMDScrollBar();
						telnet->ScrollHalfPage(1);
					   	return;
					case WXK_PAGEDOWN:
					case WXK_NEXT:
					case WXK_NUMPAD_NEXT:
					case WXK_NUMPAD_PAGEDOWN:
						//telnet->SetCMDScrollBar();
						telnet->ScrollHalfPage(0);
					   	return;
					default:
						break;
				}
		}else if ( event.ControlDown()) {
				//control_down = 1;
					switch (key)
				{
					case WXK_LEFT:
					case WXK_RIGHT:
					case WXK_UP:
					case WXK_DOWN:
					case WXK_F1:
					case WXK_F2:
					case WXK_F3:
					case WXK_F4:
					case WXK_F5:
					case WXK_F6:
					case WXK_F7:
					case WXK_F8:
					case WXK_F9:
					case WXK_F10:
					case WXK_F11:
					case WXK_F12:
					case WXK_TAB:
					{
						if (tabwin) {
							tabwin->ProcessEvent(event);
							return;
						}
					}
					default:
						break;
				}
		}else if ( event.AltDown()) {
				switch(key)
				{
					case WXK_RETURN:
					//case WXK_TAB:
					//wxLogMessage("%d",key);
					{
						if (tabwin) {
							tabwin->ProcessEvent(event);
							return;
						}
					}
					default:
						break;
				}
				
			//wxLogMessage("Alt key down");
		}
#ifdef __WXDEBUG__
		//wxLogMessage("%d",key);
#endif
		telnet->OnKeyDown(event);
	}
}

// ----------------------------------------------------------------------------
void enjTelnetPanel::OnKeyUp(wxKeyEvent& event)
{
	wxUint32  key = event.GetRawKeyCode();
	if ( telnet ) {
		if ( key == VK_CONTROL || key == VK_LCONTROL || key == VK_RCONTROL ){
			wxLogMessage("control up %d",key);
			//control_down = 0;
		}
	}
#ifdef __WXGTK__	// wxGTK 下的 event.AltDown() 沒有作用，必須透過這種方式模擬
	if( event.GetKeyCode() == 307 )	isAltDown = false;
#endif
}
// ----------------------------------------------------------------------------
//extern bool blEnableNaws;
void enjTelnetPanel::OnChar(wxKeyEvent& event)
{
#ifdef __WXGTK__	// wxGTK 下的 event.AltDown() 沒有作用，必須透過這種方式模擬
	event.m_altDown = isAltDown;
#endif

	//EnableNaws( ! isEnableNaws() );
	//blEnableNaws = true;
	//GetParent()->AddPendingEvent(event);
	if(telnet)	telnet->OnChar(event);
}

void enjTelnetPanel::OnResize(wxSizeEvent& event)
{
	if ( telnet == NULL ) return;
	telnet->OnResize();
	//telnet->repaint(true);
}

void enjTelnetPanel::OnProcessTerm(wxProcessEvent &event)
{
	telnet->close();
}
