/////////////////////////////////////////////////////////////////////////////
// Name:        remhelp.cpp
// Purpose:     Remote help controller class
// Author:      Eric Dowty
// Modified by:	
// Created:     2002-11-18
// RCS-ID:      $Id: remhelp.cpp,v 1.1.2.1 2002/11/18 14:46:48 JS Exp $
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#if defined(__GNUG__) && !defined(__APPLE__)
#pragma implementation remhelp.h
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include <math.h>

#include "wx/process.h"
#include "wx/confbase.h"

// Settings common to both executables: determines whether
// we're using TCP/IP or real DDE.

//#include "ddesetup.h"
//#define wxUSE_DDE_FOR_IPC 0

#if defined(__WXGTK__) || defined(__WXMOTIF__)
#include "mondrian.xpm"
#endif

#include "remhelp.h"
#include "client.h"

#if !defined(USE_REMOTE)
#include <wx/html/helpctrl.h>
#endif

//////////////////
//////////////////
// helper classes

rhhcClient::rhhcClient( bool *isconn_a )
{
    isconn_2 = isconn_a;
}

wxConnectionBase *rhhcClient::OnMakeConnection()
{
	return new rhhcConnection( isconn_2 ); 
}

rhhcConnection::rhhcConnection( bool *isconn_a ) 
: wxConnection()
{
	isconn_3 = isconn_a;
	*isconn_3 = TRUE;
}

rhhcConnection::~rhhcConnection()
{
    *isconn_3 = FALSE;
}

bool rhhcConnection::OnAdvise(const wxString& topic, const wxString& item, char *data, int size, wxIPCFormat format)
{
    return TRUE;
}

bool rhhcConnection::OnDisconnect()
{
    *isconn_3 = FALSE;
	
    return wxConnection::OnDisconnect();
}

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

// wxRemoteHtmlHelpController class

IMPLEMENT_CLASS(wxRemoteHtmlHelpController, wxHelpControllerBase)

wxRemoteHtmlHelpController::wxRemoteHtmlHelpController(int style )
{
	m_style = style;  
	m_connection = NULL; 
	m_client  = NULL;
	m_pid = 0;
	isconn_1 = FALSE;
	m_process = NULL;
	
	// defaults
	//
	// server app is assumed to be local
	//
    // for MSW (DDE classes), a_service is 'service name', apparently an arbitrary string
    // for Unix, should be a valid file name (for a nonexistent file)
    // for nonMSW, nonUnix, must be port number, for example "4242" (TCP/IP based classes)
    // should be unique to the client app
	
	wxString thename = wxGetApp().GetAppName();
#if defined(__WXMSW__)
	m_appname = wxT("helpview.exe");
	m_service = thename + wxString(wxT("_helpservice"));
#elif defined(__UNIX__)
	m_appname = wxT("./helpview");
	m_service = wxT("/tmp/") + thename + wxString(wxT("_helpservice"));
#else
	m_appname = wxT("./helpview");   
	m_service = wxT("4242");
#endif
	
	m_book = thename + wxT(".hhp");  // or .htb or .zip
	m_windowname = thename + wxT(" Help: %s");
	//underscores for spaces
	m_windowname.Replace( wxT(" "), wxT("_") );
}

void wxRemoteHtmlHelpController::SetService(wxString& a_service)
{
	m_service = a_service;
}
void wxRemoteHtmlHelpController::SetServer(wxString& a_appname)
{
	m_appname = a_appname;
}

void wxRemoteHtmlHelpController::OnQuit()
{
	//kill the Server here?
	//this function is not called ?
}

wxRemoteHtmlHelpController::~wxRemoteHtmlHelpController()
{
    if ( isconn_1 )
    {
		//if (!m_connection->Poke( wxT("--YouAreDead"), wxT("") ) )
		//	wxLogError(wxT("wxRemoteHtmlHelpController - YouAreDead Failed"));
		
		// Kill the server.  This could be an option.
		Quit();
		
		m_connection->Disconnect();
        delete m_connection;
		
        delete m_process;
        m_process = NULL;
    }
    if( m_client ) 
		delete m_client; //should be automatic?
	
}

bool wxRemoteHtmlHelpController::DoConnection()
{
    wxString cmd, blank;
    int nsleep;
	
    blank = wxT("  ");
	
    // ignored under DDE, host name in TCP/IP based classes
    wxString hostName = wxT("localhost");
	
    // Create a new client
    if( !m_client ) m_client = new rhhcClient(&isconn_1);
	
    nsleep = 0;
	
	// suppress the log messages from MakeConnection()
    {
		wxLogNull nolog;
		
		//first try to connect assuming server is running
		if( !isconn_1 ) 
			m_connection = (rhhcConnection *)m_client->MakeConnection(hostName, m_service, wxT("HELP") );
		
		//if not, start server
		if( !isconn_1 ) {
			
			wxString stylestr;
			stylestr.Printf( wxT("--Style%d"), m_style );
			
			cmd = m_appname + blank + m_service + blank + m_windowname + blank + m_book + blank + stylestr;
			
			m_process = new wxProcess(NULL);
			m_pid = wxExecute( cmd, FALSE, m_process );
			// leaks - wxExecute itself (if not deleted) and in wxExecute at
			// wxExecuteData *data = new wxExecuteData;
			if( m_pid <= 0 ) {
				wxLogError( wxT("wxRemoteHtmlHelpController - Failed to start Help server") );
				return FALSE;
			}
        }
		
        while ( !isconn_1 )
        { 
			//try every second for a while, then leave it to user
			wxSleep(1);
			if( nsleep > 4 ) {
				if ( wxMessageBox( wxT("Failed to make connection to Help server.\nRetry?") ,
					wxT("wxRemoteHtmlHelpController Error"),
					wxICON_ERROR | wxYES_NO | wxCANCEL ) != wxYES )
				{           
					// no server
					return FALSE;
				}
			}
			nsleep++;
			
			m_connection = (rhhcConnection *)m_client->MakeConnection(hostName, m_service, wxT("HELP") );
        }
    }
	
    if (!m_connection->StartAdvise(wxT("Item"))) {
		wxLogError(wxT("wxRemoteHtmlHelpController - StartAdvise failed") );
		return FALSE;
    }
	
    return TRUE;
}

bool wxRemoteHtmlHelpController::LoadFile(const wxString& WXUNUSED(file))
{
    return TRUE;
}
bool wxRemoteHtmlHelpController::DisplaySection(int sectionNo)
{
    Display(sectionNo);
	return TRUE;
}
bool wxRemoteHtmlHelpController::DisplayBlock(long blockNo)
{
	return DisplaySection((int)blockNo);
}

bool wxRemoteHtmlHelpController::Quit()
{
	//this code from exec sample - branches left in for testing
	// sig = 3, 6, 9 or 12 all kill server with no apparent problem
	// but give error message on MSW - timout?
	int sig = 15;   //3 = quit; 6 = abort; 9 = kill;  15 = terminate
	
					/*
					switch ( sig )
					{
					default:
					wxFAIL_MSG( _T("unexpected return value") );
					// fall through
					
					  case -1:
					  // cancelled
					  return FALSE;
					  
						case wxSIGNONE:
						case wxSIGHUP:
						case wxSIGINT:
						case wxSIGQUIT:
						case wxSIGILL:
						case wxSIGTRAP:
						case wxSIGABRT:
						case wxSIGEMT:
						case wxSIGFPE:
						case wxSIGKILL:
						case wxSIGBUS:
						case wxSIGSEGV:
						case wxSIGSYS:
						case wxSIGPIPE:
						case wxSIGALRM:
						case wxSIGTERM:
						break;
						}
	*/
	
    if ( sig == 0 )
    {
        if ( wxProcess::Exists(m_pid) )
            wxLogStatus(_T("Process %ld is running."), m_pid);
        else
            wxLogStatus(_T("No process with pid = %ld."), m_pid);
    }
    else // not SIGNONE
    {
        wxKillError rc = wxProcess::Kill(m_pid, (wxSignal)sig);
        if ( rc == wxKILL_OK )
        {
            wxLogStatus(_T("Process %ld killed with signal %d."), m_pid, sig);
        }
        else
        {
            static const wxChar *errorText[] =
            {
                _T(""), // no error
					_T("signal not supported"),
					_T("permission denied"),
					_T("no such process"),
					_T("unspecified error"),
            };
			
			// sig = 3, 6, 9 or 12 all kill server with no apparent problem
			// but give error message on MSW - timout?
			//
            //wxLogError(_T("Failed to kill process %ld with signal %d: %s"),
            //            m_pid, sig, errorText[rc]);
        }
    }
	
	
    return TRUE;
}

void wxRemoteHtmlHelpController::Display(const wxString& helpfile)
{
    if( !isconn_1 ) {
        if( !DoConnection() ) return;
    }
    
    if (!m_connection->Execute( helpfile, -1 ) ) 
		wxLogError(wxT("wxRemoteHtmlHelpController - Display Failed"));
	
}

void wxRemoteHtmlHelpController::Display(const int id)
{
    if( !isconn_1 ) {
        if( !DoConnection() ) return;
    }
	
	wxString intstring;
	intstring.Printf( "--intstring%d", id );
    
    if (!m_connection->Execute( intstring, -1 ) ) 
		wxLogError(wxT("wxRemoteHtmlHelpController - Display Failed"));
	
}

bool wxRemoteHtmlHelpController::AddBook(const wxString& book, bool show_wait_msg)
{
	//ignore show_wait_msg - there shouldn't be a delay in this step
	//show_wait_msg = TRUE could be transmitted with ++AddBook
	m_book = book;
	
	if( isconn_1 ) {
		if (!m_connection->Poke( wxT("--AddBook"), (char*)book.c_str() ) )
			wxLogError(wxT("wxRemoteHtmlHelpController - AddBook Failed"));
		return FALSE;
	}
	
	return TRUE;
}

bool wxRemoteHtmlHelpController::DisplayContents()
{
	if( isconn_1 ) {
		if (!m_connection->Poke( wxT("--DisplayContents"), wxT("") ) ) {
			wxLogError(wxT("wxRemoteHtmlHelpController - DisplayContents Failed"));
			return FALSE;
		}
	}
	return TRUE;
}
void wxRemoteHtmlHelpController::DisplayIndex()
{
	if( isconn_1 ) {
		if (!m_connection->Poke( wxT("--DisplayIndex"), wxT("") ) )
			wxLogError(wxT("wxRemoteHtmlHelpController - DisplayIndex Failed"));
	}
}
bool wxRemoteHtmlHelpController::KeywordSearch(const wxString& keyword)
{
	if( isconn_1 ) {
		if (!m_connection->Poke( wxT("--KeywordSearch"), (char*)keyword.c_str() ) ) {
			wxLogError(wxT("wxRemoteHtmlHelpController - KeywordSearch Failed"));
			return FALSE;
		}
	}
	return TRUE;
}

void wxRemoteHtmlHelpController::SetTitleFormat(const wxString& format)
{
	m_windowname = format;
	m_windowname.Replace( wxT(" "), wxT("_") );
	
	if( isconn_1 ) {
		if (!m_connection->Poke( wxT("--SetTitleFormat"), (char*)format.c_str() ) )
			wxLogError(wxT("wxRemoteHtmlHelpController - SetTitleFormat Failed"));
	}
}

void wxRemoteHtmlHelpController::SetTempDir(const wxString& path)
{
	if( isconn_1 ) {
		if (!m_connection->Poke( wxT("--SetTempDir"), (char*)path.c_str() ) )
			wxLogError(wxT("wxRemoteHtmlHelpController - SetTempDir Failed"));
	}
}

