/////////////////////////////////////////////////////////////////////////////
//
// Mud32vw.cpp : implementation of the CMudView class
//
// CMudView
//

#include "stdafx.h"
#include "gmud32.h"

#include "gmud32doc.h"
#include "gmud32vw.h"
#include "world.h"
#include "connectd.h"

#include "outwnd.h"
#include "inwnd.h"
#include "csmartsocket.h"
#include "lowlev.h"
#include "statuswn.h"
#include "wrapopti.h"
#include "trigger.h"
#include "mainfrm.h"
#include "textfrmt.h"
#include "io.h"
#include "replaced.h"
#include "AliasArray.h"

#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNCREATE(CMudView, CView)
BEGIN_MESSAGE_MAP(CMudView, CView)
	//{{AFX_MSG_MAP(CMudView)
	ON_WM_CREATE()
	ON_WM_SIZE()
	ON_COMMAND(ID_SERVER_CONNECT, OnServerConnect)
	ON_UPDATE_COMMAND_UI(ID_SERVER_CONNECT, OnUpdateServerConnect)
	ON_COMMAND(ID_SERVER_DISCONNECT, OnServerDisconnect)
	ON_UPDATE_COMMAND_UI(ID_SERVER_DISCONNECT, OnUpdateServerDisconnect)
	ON_MESSAGE(WM_SOCKET_DISCONNECTED,OnSocketDisconnected)
	ON_MESSAGE(WM_SOCKET_CONNECTED,OnSocketConnected)
	ON_MESSAGE(WM_SOCKET_STRING_RECIEVED,OnStringReceived)
	ON_MESSAGE(WM_ASYNCH_GETHOST_COMPLETE,OnAsynchGetHostCompleted)
	ON_MESSAGE(WM_ENTER_PRESSED,OnUserInput)
	ON_MESSAGE(WM_FONTCHANGED,OnFontChanged)
	ON_MESSAGE(WM_COLORCHANGED,OnColorChanged)
	ON_WM_SETFOCUS()
	ON_WM_CTLCOLOR()
	ON_COMMAND(ID_FILE_EDITTRIGGERLIST, OnFileEdittriggerlist)
	ON_UPDATE_COMMAND_UI(ID_FILE_EDITTRIGGERLIST, OnUpdateFileEdittriggerlist)
	ON_COMMAND(ID_WINDOW_PAUSE, OnWindowPause)
	ON_UPDATE_COMMAND_UI(ID_WINDOW_PAUSE, OnUpdateWindowPause)
	ON_COMMAND(ID_FILE_TOGGLELOGGING, OnFileTogglelogging)
	ON_UPDATE_COMMAND_UI(ID_FILE_TOGGLELOGGING, OnUpdateFileTogglelogging)
	ON_COMMAND(ID_PASTE_FILE, OnPasteFile)
	ON_WM_VSCROLL()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

#define new DEBUG_NEW

CString GetFileExceptionString( int cause);
/////////////////////////////////////////////////////////////////////////////
// CMudView construction/destruction
CMudView::CMudView()
{
	m_pInWnd=0;
	m_pOutWnd=0;
	m_pStatusWnd=0;
	m_pSocket=0;

	m_pHostBuf= new char[MAXGETHOSTSTRUCT];
	m_pWorld=0;
	m_pBGBrush=0;
	m_bUnSeen=-1;
	m_bActive=FALSE;
	m_bIsLogging=FALSE;
	m_fLogFile=NULL;
	m_bConnectionPending=FALSE;
}

CMudView::~CMudView()
{
	if(m_pInWnd)
		delete m_pInWnd;
	if(m_pOutWnd)
		delete m_pOutWnd;
	if(m_pStatusWnd)
		delete m_pStatusWnd;
	if(m_pSocket)
		delete m_pSocket;

	delete m_pHostBuf;
	if(m_pBGBrush)
		delete m_pBGBrush;
	CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
	pFrame->PostMessage(WM_UPDATE_WORLDS);

	if(m_bIsLogging)
	{
		m_fLogFile->Flush();
		m_fLogFile->Close();
		delete m_fLogFile;
		m_fLogFile=0;
		m_bIsLogging=FALSE;
	}

}

/////////////////////////////////////////////////////////////////////////////
// CMudView drawing
void CMudView::OnDraw(CDC* /* pDC */)
{
	CMudDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
}

/////////////////////////////////////////////////////////////////////////////
// CMudView diagnostics
#ifdef _DEBUG
void CMudView::AssertValid() const
{
	CView::AssertValid();
}
void CMudView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}
CMudDoc* CMudView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMudDoc)));
	return (CMudDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMudView message handlers

int CMudView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	CMudApp *pApp = (CMudApp *)AfxGetApp();
	m_pBGBrush= new CBrush(pApp->m_colorBackGround);
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;
	m_pOutWnd = new COutWnd();
	if(!m_pOutWnd->Create(0,0,WS_CHILD|WS_VISIBLE,CRect(0,0,0,0),this,2113))
	{
		AfxMessageBox("Error creating Output window");
		return -1;
	}
	m_pStatusWnd = new CStatusWnd();
	if(!m_pStatusWnd->Create(0,0,WS_CHILD|WS_VISIBLE,CRect(0,0,0,0),this,2114))
	{
		AfxMessageBox("Error creating status line window");
		return -1;
	}
	m_pSocket = new CSmartSocket();
	m_pSocket->SetParentWnd(this);
	m_pInWnd = new CInWnd();
	if(!m_pInWnd->Create(WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL|ES_WANTRETURN,CRect(0,0,0,0),this,2112))
	{
		AfxMessageBox("Error creating input window");
		return -1;
	}
	LOGFONT *pLogFont = &((CMudApp *)AfxGetApp())->m_LogFont;
	m_pOutWnd->NewFont(pLogFont);
	m_pStatusWnd->NewFont(pLogFont);
	CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
	return 0;
}

void CMudView::OnSize(UINT nType, int cx, int cy)
{
	if(nType)
		CView::OnSize(nType, cx, cy);
	
	int linesize=m_pOutWnd->GetLineHeight()+5;
	m_pOutWnd->MoveWindow(0,0,cx,cy-linesize*2);
	m_pStatusWnd->MoveWindow(0,cy-linesize*2,cx,linesize);
	m_pInWnd->MoveWindow(0,cy-linesize,cx,linesize);
}

// user requests to connect to a server.
void CMudView::OnServerConnect()
{
	CConnectDialog dlg(this);
	dlg.m_paWorlds = &((CMudDoc *)GetDocument())->m_aWorlds;
	dlg.m_pTriggers = &((CMudDoc *)GetDocument())->m_aTriggers;
	dlg.m_pMacros = &((CMudDoc *)GetDocument())->m_aMacros;
	dlg.m_pAliases = &((CMudDoc *)GetDocument())->m_aAliases;
	GetDocument()->SetModifiedFlag();
	if(dlg.DoModal()==IDOK)
	{
		Connect(dlg.m_pWorld);
	}
}

CMudView::Connect(CWorld *pWorld)
{
	m_pSocket->HardClose();
	m_pWorld = pWorld;
	m_pSocket->Create();
	m_sAddress=m_pWorld->m_sHostName;
	m_wPort=m_pWorld->m_wPort;
	m_sName=m_pWorld->m_sName;
	if(atoi(m_pWorld->m_sHostName))
	{
		Printf("%%%%%% Connecting to %s on port %d.\n",(LPCSTR)m_pWorld->m_sHostName,(int)m_pWorld->m_wPort);
		m_pSocket->Connect((LPCSTR)m_pWorld->m_sHostName,m_pWorld->m_wPort);
	}
	else
	{
		WSAAsyncGetHostByName(m_hWnd,WM_ASYNCH_GETHOST_COMPLETE,m_pWorld->m_sHostName,m_pHostBuf,MAXGETHOSTSTRUCT);
		Printf("%%%%%% Performing Asynch DNS lookup on %s\n",(LPCSTR)m_pWorld->m_sHostName);
	}
	m_bConnectionPending=TRUE;	
	return TRUE;
}

// dns lookup has finished
afx_msg LONG CMudView::OnAsynchGetHostCompleted(UINT,LONG lParam)
{
	ASSERT(m_pWorld);
	WORD nError = WSAGETASYNCERROR(lParam);
	if(nError)
	{
		Printf("%%%%%% Error %d - %s -in DNS lookup of %s.\n",(int)nError,m_pSocket->SockerrToString(nError),m_pWorld->m_sHostName);
		WORD nBufSize = WSAGETASYNCBUFLEN(lParam);
		m_pSocket->HardClose();
		return FALSE;
	}
	hostent * pHostEnt = (hostent *)m_pHostBuf;
	char temps[30];
	LPSTR pHost=pHostEnt->h_addr;
	wsprintf(temps,"%d.%d.%d.%d",(int)(unsigned char)pHost[0],(int)(unsigned char)pHost[1],(int)(unsigned char)pHost[2],(int)(unsigned char)pHost[3]);
	m_sAddress = temps;
	Printf("%%%%%% Connecting to %s on port %d\n",temps,(int)m_pWorld->m_wPort);
	m_pSocket->Connect(temps,m_pWorld->m_wPort);
	SetUnSeen();
	m_bConnectionPending=TRUE;	
	return TRUE;
}

afx_msg LONG CMudView::OnSocketConnected(UINT  nErrCode ,LONG )
{
	ASSERT(m_pWorld);
	CFrameWnd *pWnd = (CFrameWnd *)GetParent();
	pWnd->OnUpdateFrameTitle(GetFocus()==m_pInWnd);
	SetUnSeen();
	if(nErrCode)
	{
		m_pSocket->HardClose();
		m_pSocket->Create();
		Printf("%%%%%% Error Connecting: %s\n",m_pSocket->SockerrToString(nErrCode));
		Printf("%%%%%% Retrying connection to %s on port %d.\n",(LPCSTR)m_sAddress,(int)m_wPort);
  	m_bConnectionPending=TRUE;	
		CObArray *pA=&((CMudDoc *)GetDocument())->m_aWorlds;
		for(int loop=0;loop<pA->GetSize();loop++)
		{
			CWorld *pW = (CWorld *)(pA->GetAt(loop));
			if(pW->m_sName == m_sName)
				m_pWorld=pW;
		}
		ASSERT_VALID(m_pWorld);
		m_pSocket->Connect((LPCSTR)m_pWorld->m_sHostName,m_pWorld->m_wPort);
		return TRUE;
	}
	CMudApp *pApp = (CMudApp *)AfxGetApp();
	if(pApp->m_bConnectBeep)
		MessageBeep(0);
	Printf("%%%%%% Connected to %s on port %d.\n",(LPCSTR)m_pWorld->m_sHostName,(int)m_pWorld->m_wPort);
	
	if(m_pWorld->m_sConnectString.GetLength())
	{
		m_pSocket->Printf("%s\n",m_pWorld->m_sConnectString);
		if(GetApp()->m_bEcho)
			Printf("%s\n",m_pWorld->m_sConnectString);
	}
	m_bConnectionPending=FALSE;
	return TRUE;
}

afx_msg LONG CMudView::OnSocketDisconnected(UINT  nErrCode ,LONG)
{
	m_bConnectionPending=FALSE;
	switch(nErrCode)
	{
		case 0:
			break;
		default:
			TRACE("\nError code in onsocketdisconnected: %d",nErrCode);
			break;
	}
	if(!GetApp()->m_bEcho)
		m_pOutWnd->OnEnterPressed();
	Printf("%%%%%% Disconnected from server.\n");
	CFrameWnd *pWnd = (CFrameWnd *)GetParent();
	pWnd->OnUpdateFrameTitle(GetFocus()==m_pInWnd);
	m_pWorld=0;
	SetUnSeen();
	((CMainFrame *)(AfxGetMainWnd()))->UpdateWorlds();
	return TRUE;
}

void CMudView::OnServerDisconnect()
{
	m_bConnectionPending=FALSE;
	m_pSocket->HardClose();
	CFrameWnd *pWnd = (CFrameWnd *)GetParent();
	pWnd->OnUpdateFrameTitle(GetFocus()==m_pInWnd);
	SetUnSeen();
}

void CMudView::OnUpdateServerConnect(CCmdUI* pCmdUI)
{
	pCmdUI->Enable(!m_pSocket->IsConnected() && !m_bConnectionPending);
}

void CMudView::OnUpdateServerDisconnect(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_pSocket->IsConnected() || m_bConnectionPending);
}

afx_msg LONG CMudView::OnStringReceived(UINT ,LONG lparam)
{
	LPSTR pStr = (LPSTR)lparam;
	LPSTR pStripped = new char[BUFFSIZE];
	CMudDoc *pDoc = (CMudDoc *)GetDocument();
	Ansimemcpy(pStripped,pStr,0,BUFFSIZE);
	CSelArray *paTriggers= (CSelArray *)pDoc->m_aTriggers.Get(m_pWorld->m_sTriggerList);
	m_pOutWnd->PutString(pStr);
	if(m_bIsLogging)
	{
		try
		{
			m_fLogFile->WriteString(pStripped);
		}
		catch( CFileException* e )
		{
		    // Handle the file exceptions here.
			AfxMessageBox("Error writing to log file:\n"+GetFileExceptionString(e->m_cause));
			delete e;
		}
	}
	for(int loop=0;loop<paTriggers->GetSize();loop++)
	{
		((CTrigger *)(paTriggers->Get(loop)))->CheckActivation(pStripped,this);
	}
	SetUnSeen();
	CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
	pFrame->UpdateWorlds();
	delete pStripped;
	return TRUE;
}

void CMudView::SetUnSeen( BOOL bUnSeen /* = TRUE */ )
{
	if(	!m_bUnSeen && !m_bActive)
	{
		m_bUnSeen=bUnSeen;
		CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
		pFrame->UpdateWorlds();
	}
}

afx_msg LONG CMudView::OnUserInput(UINT,LONG lParam)
{
	LPCSTR pStr = (LPSTR)lParam;
	if(!GetApp()->m_bEcho)
		m_pOutWnd->OnEnterPressed();

  CString sStr=pStr;

  // check aliases
  if(m_pWorld)
  {
	  CAliasArray *pAliases= (CAliasArray *)GetDocument()->m_aAliases.Get(m_pWorld->m_sAliasList);
	  sStr = pAliases->CheckAliases(sStr);
  }

  // command stacking
  for(int loop=0;loop<sStr.GetLength();loop++)
    if(sStr[loop]=='|')
      sStr.SetAt(loop,'\n');

  for(loop=0;loop<sStr.GetLength();loop++)
  {
    if(sStr[loop]=='\n')
    {
      CString sLine=sStr.Left(loop);
      sStr=sStr.Mid(loop+1);
      loop=0;
      ProcessOneLine(sLine);
    }
  }
  ProcessOneLine(sStr);
  return TRUE;
}

long CMudView::ProcessOneLine(CString sStr)
{

  // check user variables
  if(!sStr.IsEmpty() && GetUserVariables())
  {
    CMapStringToString *pUserVariables = GetUserVariables();

    int iPos=-1;
    for(int start=0;start<sStr.GetLength();start++)
    {
      if(sStr[start]=='%')
      {
        for(int end=start+1;end<sStr.GetLength();end++)
        {
          if(sStr[end]=='%')
          {
            CString sSuspect = sStr.Mid(start+1,end-start-1);
            CString sValue;
            if(pUserVariables->Lookup(sSuspect,sValue))
            {
              sStr=sStr.Left(start)+sValue+sStr.Mid(end+1);
            }
          }
        }
      }
    }
  }

  // echo to user
  if(GetApp()->m_bEcho)
		Printf("%s\n\r",(LPCSTR)sStr);

  // check for '/' command
  if(!sStr.IsEmpty() && sStr[0]=='/')
  {
    if(ProcessUserCommandLine(sStr))
      return TRUE; // else it's not a command
  }

  //put string
	m_pSocket->Printf("%s\n",(LPCSTR)sStr);
	return TRUE;
}

afx_msg LONG CMudView::OnFontChanged(UINT,LONG)
{
	LOGFONT *pLogFont = &((CMudApp *)AfxGetApp())->m_LogFont;
	m_pOutWnd->NewFont(pLogFont);
	m_pStatusWnd->NewFont(pLogFont);
	return TRUE;
}


void CMudView::OnSetFocus(CWnd* pOldWnd) 
{
	CView::OnSetFocus(pOldWnd);
	SetUnSeen(FALSE);
	if(m_pInWnd)
		m_pInWnd->SetFocus();	
}

CString CMudView::GetTitle()
{
	if(m_pSocket->IsConnected())
	{
		return m_pWorld->m_sName;
	}
	else
	{
		return CString("Not Connected");
	}
}

HBRUSH CMudView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	ASSERT_VALID(m_pBGBrush);
	HBRUSH hbr = CView::OnCtlColor(pDC, pWnd, nCtlColor);
	CMudApp *pApp = (CMudApp *)AfxGetApp();

	if ( nCtlColor== CTLCOLOR_EDIT ) 
	{
		// Set the text background color.
		pDC->SetBkColor(pApp->m_colorBackGround);
		// Set the text foreground color.
		pDC->SetTextColor(pApp->m_colorForeGround);
		// Return the control background brush.
	}
	return 	(HBRUSH)m_pBGBrush->m_hObject;
}

afx_msg LONG CMudView::OnColorChanged(UINT,LONG)
{
	delete m_pBGBrush;
	CMudApp *pApp = (CMudApp *)AfxGetApp();
	m_pBGBrush= new CBrush(pApp->m_colorBackGround);
	m_pInWnd->Invalidate();
	m_pOutWnd->Invalidate();
	m_pStatusWnd->Invalidate();
	return TRUE;
}

void CMudView::OnActivateView(BOOL bActivate, CView* pActivateView, CView* pDeactiveView) 
{	
	CView::OnActivateView(bActivate, pActivateView, pDeactiveView);
	m_bActive=bActivate;

	m_bUnSeen=FALSE;
	CMainFrame *pFrame = (CMainFrame *)AfxGetMainWnd();
	pFrame->UpdateWorlds();
}

void CMudView::OnFileEdittriggerlist() 
{
	GetDocument()->EditTriggerList(m_pWorld);
}

void CMudView::OnUpdateFileEdittriggerlist(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_pWorld?1:0);
}

void CMudView::OnWindowPause() 
{
	if(m_pSocket)
		m_pSocket->Pause(!m_pSocket->m_bPaused);
}

void CMudView::OnUpdateWindowPause(CCmdUI* pCmdUI) 
{
	if(m_pSocket)
		pCmdUI->SetCheck(m_pSocket->m_bPaused);
	else
		pCmdUI->SetCheck(FALSE);
}

BOOL CMudView::Pause(BOOL bPause)
{
	BOOL bWasPaused = m_pSocket->m_bPaused;
	if(m_pSocket)
		m_pSocket->Pause(bPause);
	return bWasPaused;
}


void CMudView::OnFileTogglelogging() 
{
	if(m_bIsLogging)
	{
		m_fLogFile->Flush();
		m_fLogFile->Close();
		delete m_fLogFile;
		m_fLogFile=0;
		m_bIsLogging=FALSE;
		AfxMessageBox("Log file closed.");
	}
	else
	{
		ASSERT(m_fLogFile==0);
		CFileDialog dlg(FALSE,"LOG","*.log",OFN_HIDEREADONLY,"Log Files (*.log) | *.log | All Files (*.*) | *.* ||",this);
		if(dlg.DoModal()==IDOK)
		{
			try
			{
        int iMode=CFile::modeCreate|CFile::modeWrite;
				if(_access("log.txt",0)==0)
				{
					CReplaceDialog rdlg(this);
					rdlg.m_sFileName = dlg.GetPathName();
					switch(rdlg.DoModal())
					{
						case IDOK:
							break;
						case IDOVERWRITE:
							iMode=CFile::modeWrite;
							break;
						default:
						case IDCANCEL:
							AfxMessageBox("File logging operation Canceled.");
							return;
					}
				}
				m_fLogFile= new CStdioFile(dlg.GetPathName(),iMode);
				if(iMode == CFile::modeWrite)
					m_fLogFile->SeekToEnd();
					
			}
			catch( CFileException* e )
			{
			    // Handle the file exceptions here.
				AfxMessageBox("Error opening Log file for writing:\n"+GetFileExceptionString(e->m_cause));
				e->Delete();
				return;
			}
			m_bIsLogging=TRUE;
		}
	}
}

void CMudView::OnUpdateFileTogglelogging(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(m_bIsLogging);
}

CString GetFileExceptionString( int cause)
{
	switch(cause)
	{
		case CFileException::endOfFile:
			return "The end of file was reached.";
		case CFileException::diskFull:
			return "The disk is full.";
		case CFileException::lockViolation:
			return "There was an attempt to lock a region that was already locked";
		case CFileException::sharingViolation:
			return "SHARE.EXE was not loaded, or a shared section was locked.";
		case CFileException::hardIO:
			return "There was a hardware error.";
		case CFileException::badSeek:
			return "There was a DISK ERROR trying to set the file pointer.";
		case CFileException::directoryFull:
			return "The current directory is full: there are no more directory entries.";
		case CFileException::removeCurrentDir:
			return "The current working directory cannot be removed.";
		case CFileException::invalidFile:
			return "There was an attempt to use an invalid file handle.";
		case CFileException::accessDenied:
			return "The File could not be accessed.";
		case CFileException::tooManyOpenFiles:
			return "The permitted number of open files was exceeded.";
		case CFileException::badPath:
			return "all or part of the path is invalid";
		case CFileException::fileNotFound:
			return "File not found.";
		case CFileException::generic:
		default:
		case CFileException::none:
			return "unknown error";
	}
	return "Error showing error!";
}

BOOL __cdecl CMudView::Printf(LPSTR format, ...)
{
	LPSTR buffer = new char[BUFFSIZE];
	
	va_list marker;
	va_start(marker,format);
	vsprintf(buffer,format,marker);
	va_end(marker);

	// actually print it
	if(m_bIsLogging)
	{
		try
		{
			m_fLogFile->WriteString(buffer);
		}
		catch( CFileException* e )
		{
		    // Handle the file exceptions here.
			AfxMessageBox("Error writing to log file:\n"+GetFileExceptionString(e->m_cause));
			delete e;
		}
	}

	m_pOutWnd->PutString(buffer);

	return TRUE;
}

void CMudView::OnPasteFile() 
{
	CFileDialog dlg(TRUE,"LOG","*.*",0,"All Files (*.*) | *.* ||",this);
	if(dlg.DoModal()==IDOK)
	{
		try
		{
			CStdioFile fFile(dlg.GetPathName(),CFile::modeRead);
			CString str;
			LPSTR pStr = str.GetBufferSetLength(2049);
			while((pStr=fFile.ReadString(pStr,2048))!=0)
			{
				m_pSocket->Printf("%s",pStr);
				Printf("%s",pStr);
			}
			Printf("\n");
			str.ReleaseBuffer();
		}
		catch( CFileException* e )
		{
		    // Handle the file exceptions here.
			AfxMessageBox("Error opening file for Pasting:\n"+GetFileExceptionString(e->m_cause));
			e->Delete();
			return;
		}
	}
}

void CMudView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	CView::OnVScroll(nSBCode, nPos, pScrollBar);
	m_pOutWnd->PostMessage(WM_VSCROLL,nSBCode,(long)pScrollBar);
}

CMapStringToString * CMudView::GetUserVariables()
{
  if(!m_pWorld)
    return NULL;
  return m_pWorld->GetUserVariables();
}

bool CMudView::ProcessUserCommandLine(CString sInput)
{
  //ASSERT(sInput[0]=='/');

  CMapStringToString * pVariables = GetUserVariables();
  if(!pVariables)
    return FALSE;

  // split off argument
  CString sCommand,sArguments;
  for(int loop=0;loop<sInput.GetLength();loop++)
  {
    if(sInput[loop]==' ')
    {
      sCommand = sInput.Left(loop);
      sArguments = sInput.Mid(loop);
      break;
    }
  }
  if(sCommand == "")
    sCommand = sInput;
  sCommand.TrimRight();
  sArguments.TrimLeft();

  if(strcmpi(sCommand,"/set")==0)
  {
    if(sArguments == "") // dump variables to console;
    {
      printf("\n");
      for(POSITION pos=pVariables->GetStartPosition();pos!=NULL;)
      {
        CString sKey,sValue;
        pVariables->GetNextAssoc(pos,sKey,sValue);
        Printf("%%%s%% = %s\n",(LPCSTR)sKey,(LPCSTR)sValue);
      }
    }
    else
    {
      // split off key and value
      CString sKey,sValue;
      for(int loop=0;loop<sArguments.GetLength();loop++)
      {
        char ch=sArguments[loop];
        if(ch =='=' || ch == ' ')
        {
          int begin=loop;
          while(loop<sArguments.GetLength() && (sArguments[loop] == '=' || sArguments[loop]==' '))
            loop++;

          sKey = sArguments.Left(begin);
          sValue = sArguments.Mid(loop);
          break;
        }
      }
      if(!sKey.GetLength())
        sKey=sArguments;
      sKey.TrimRight();
      sValue.TrimLeft();
      if(sValue == "")
      {
        if(pVariables->RemoveKey(sKey))
          Printf("\nKey %s removed\n",(LPCSTR)sKey);
        else
          Printf("\nError, could not remove Key:%s\n",(LPCSTR)sKey);
      }
      else
      {
        pVariables->SetAt(sKey,sValue);
        Printf("\n%%%s%% = %s\n",(LPCSTR)sKey,(LPCSTR)sValue);
      }
    }
  }
  else if(strcmpi(sCommand,"/reconnect")==0)
  {
		m_pSocket->HardClose();
		m_pSocket->Create();
		Printf("%%%%%% Reconnecting to %s on port %d.\n",(LPCSTR)m_sAddress,(int)m_wPort);
  	m_bConnectionPending=TRUE;	
		CObArray *pA=&((CMudDoc *)GetDocument())->m_aWorlds;
		for(int loop=0;loop<pA->GetSize();loop++)
		{
			CWorld *pW = (CWorld *)(pA->GetAt(loop));
			if(pW->m_sName == m_sName)
				m_pWorld=pW;
		}
		ASSERT_VALID(m_pWorld);
		m_pSocket->Connect((LPCSTR)m_pWorld->m_sHostName,m_pWorld->m_wPort);
		return TRUE;

  }
  else
    return FALSE; // wasnt command

  return TRUE; // was command
}

BOOL CMudView::OnEraseBkgnd(CDC* /* pDC*/ ) 
{
	return TRUE;
}