/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2001/03/23
// RCS-ID:      $Id: helpfinder_svc.cpp,v 1.2 2001/04/11 15:42:06 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas (alex@soften.ktu.lt)
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "minimal.cpp"
    #pragma interface "minimal.cpp"
#endif

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

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

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

#include "helpfinder_svc.h"
#include "wx/xml/xmlres.h"

#include "wx/pmf/pm_flalg.h"
#include "wx/fl/controlbar.h"

#include "wx/html/htmlwin.h"

static wxCommandInfo _gHelpCommands[] = {

	wxCommandInfo( wxPMHelpFinderService::ID_CONFIGURE, "&Configure...", "", "" ),
	wxCommandInfo( wxPMHelpFinderService::ID_OPTIONS, "&Options...", "", "" ),
	wxCommandInfo( wxPMHelpFinderService::ID_TOGGLE_FINDER_PANE, "&Toggle Finder Window", "", "Alt+3" ),

	wxCommandInfo( -1, "SEPARATOR" ),

	wxCommandInfo( 0, "" ) // list-terminator
};

static wxCommandInfo _gHelpCommands1[] = {

	wxCommandInfo( wxPMHelpFinderService::ID_TOGGLE_FINDER_PANE, "&Toggle Finder Window", "", "Alt+3" ),

	wxCommandInfo( 0, "" ) // terminator
};

static wxPMMergableMenuChain _gHelpChains[] = {

	wxPMMergableMenuChain( "/&Help/", _gHelpCommands ),
	wxPMMergableMenuChain( "/&View/",  _gHelpCommands1 ),

	wxPMMergableMenuChain( "", NULL ) // list-terminator
};

IMPLEMENT_DYNAMIC_CLASS( wxPMHelpFinderService, wxPMSimpleService )

BEGIN_EVENT_TABLE( wxPMHelpFinderService, wxPMSimpleService )

	EVT_MENU( ID_CONFIGURE,			 wxPMHelpFinderService::OnConfigure )
	EVT_MENU( ID_OPTIONS,			 wxPMHelpFinderService::OnOptions )
	EVT_MENU( ID_FIND_HELP,			 wxPMHelpFinderService::OnFindHelp )
	EVT_MENU( ID_TOGGLE_FINDER_PANE, wxPMHelpFinderService::OnToggleFinderPane )

END_EVENT_TABLE()

wxPMHelpFinderService::wxPMHelpFinderService()

	: mpIndexSvc( NULL ),
	  mpPane( NULL )
{}

wxPMHelpFinderService::~wxPMHelpFinderService()
{}


wxPMMergableMenuChain* wxPMHelpFinderService::GetMergableMenuChain()
{
	return _gHelpChains;
}

bool wxPMHelpFinderService::Start()
{
	mpIndexSvc = (wxPMIndexingService*)wxPMBootSvc().
					FindUniqueServiceInstance( "wxPMIndexingService" );

	if ( !mpIndexSvc )
		return FALSE;

	mpIndexSvc->RegisterIndexHandler( (I_IndexHandler*)this );

	return TRUE; // started ok
}

bool wxPMHelpFinderService::Stop()
{
	return TRUE;
}

// command event handlers

void wxPMHelpFinderService::OnConfigure( wxCommandEvent& event )
{
}

void wxPMHelpFinderService::OnOptions( wxCommandEvent& event )
{
}

void wxPMHelpFinderService::OnFindHelp( wxCommandEvent& event )
{
}

static wxPMFrameLayoutPreference _gFinderLayPref( FL_ALIGN_BOTTOM, 400,1, 400, 180, FALSE );

void wxPMHelpFinderService::OnToggleFinderPane( wxCommandEvent& event )
{
	if ( !mpPane )
	{
		wxWindow* panel = wxTheXmlResource->
			LoadWindow( wxPMBootSvc().GetMainWindow(), "HelpFinder_Panel1" );

		HelpFinderPanel* fpanel = wxDynamicCast( panel, HelpFinderPanel );

		fpanel->SetFinder( this );

		bool hasFl = 
			wxPMBootSvc().FindUniqueServiceInstance( "I_PMPaneLayoutAlgorithm" ) != NULL;

		mpPane = new wxPMSimplePane( panel, hasFl ? &_gFinderLayPref : NULL );
		mpPane->SetPaneName( "HelpFinder Window" );

		wxPMBootSvc().AddService( mpPane );
		wxPMBootSvc().StartService( mpPane ); 
	}
	else
	{
		if ( mpPane->IsShown() )

			wxPMBootSvc().HidePane( mpPane );
		else
		{
			wxPMBootSvc().ShowPane( mpPane );
			((HelpFinderPanel*)mpPane->GetPaneWindow())->FocusName();
		}
	}
}

/*** implementation of I_IndexHandler interface ***/

const char* wxPMHelpFinderService::GetIndexHandlerName()
{
	return "wxWindows-Html-Help-Handler";
}

bool wxPMHelpFinderService::OnClearIndexItems( int indexId )
{
	mpIndexSvc->GetItemTable().DeleteItemsByType( WX_HELP_ENTRY_ITEM, indexId );

	return TRUE;
}

bool wxPMHelpFinderService::OnBeginBuild( int indexId )
{
	mTmpBufLen = 10000;
	mpTmpBuf = new char[mTmpBufLen+1];

	return TRUE; // nothing
}

bool wxPMHelpFinderService::OnIndexFile( const wxPMFileInfo& file, int fileId, int indexId )
{
	wxFile fl( file.GetPath() );
	if ( !fl.IsOpened() )
		return FALSE;

	int len = fl.Length();

	if ( len > mTmpBufLen )
	{
		delete [] mpTmpBuf;
		mTmpBufLen = len;
		mpTmpBuf = new char[ mTmpBufLen + 1 ];
	}

	char* buf = mpTmpBuf;

	// this must be fast, yeahh...!
	int n = fl.Read( buf, len );

	buf[n] = '\0'; 
	
	char* cur = buf;
	char* found = strstr( buf, "<A NAME" );

	ItemTable& itemTbl = mpIndexSvc->GetItemTable();

	// those are common for all items in a given file
	itemTbl.SetFileId( fileId );
	itemTbl.SetIndexId( indexId );

	while( found )
	{
		cur = found + 7;

		while( *cur && *cur != '"' )
			++cur;

		if ( !*cur )
			break;

		++cur; // skip leading '"'

		char* start = cur;

		while( *cur && *cur != '"' )
			++cur;

		if ( !*cur )
			break;

		*cur = '\0';
		wxString name = start;
		*cur = '"';

		wxString context;

		// now scan fromward to see if there's any heading ( <Hx> ... </Hx> ) ahead,
		// if so, take name from it's content, otherwise the name
		// is that found in <a NAME="..value.." >

		while( *cur && *cur != '/' )
			++cur;

		while( *cur && *cur != '<' )
			++cur;

		char* sectionStart = cur;

		if ( *cur && *(cur+1) == 'H' )
		{
			while( *cur && *cur != '>' ) 
				++cur;

			if ( !*cur )
				break;

			++cur; // skip '<'

			start = cur;

			while( *cur && *cur != '<' )
				++cur;

			*cur = '\0';

			wxString s= start;

			int pos = s.Find( "::" );

			*cur = '<'; // restore

			if ( pos != -1 )
			{
				context = s.Mid( 0, pos );
				name = s.Mid( pos + 2 );
			}
			else
				name = s;
		}
		else
		{
			context = name;
			name = "";
		}

		found = strstr( cur, "<A NAME" );

		int secitonSize = (int)(found - sectionStart);

		if ( found == NULL )

			secitonSize = (int)( (buf+n) - sectionStart );

		itemTbl.SetName( name.Lower() );
		itemTbl.SetContext( context.Lower() );
		itemTbl.SetLineNo( (int)( sectionStart - buf ) );
		itemTbl.SetLineCount( secitonSize );

		itemTbl.Add();
	}

	return TRUE;
}

bool wxPMHelpFinderService::OnEndBuild( int indexId )
{
	delete [] mpTmpBuf;
	mpTmpBuf = NULL;

	return TRUE; // nothing
}

wxPMIndexingService* wxPMHelpFinderService::GetIndexingService()
{
	return mpIndexSvc;
}

/***** Implementation for class HelpFinderPanel *****/

IMPLEMENT_DYNAMIC_CLASS( HelpFinderPanel, wxPanel )

BEGIN_EVENT_TABLE( HelpFinderPanel, wxPanel )

	EVT_BUTTON( XMLID( "search" ), HelpFinderPanel::OnSearch )
	EVT_BUTTON( XMLID( "top" ), HelpFinderPanel::OnTop )
	EVT_BUTTON( XMLID( "back" ), HelpFinderPanel::OnBack )
	EVT_BUTTON( XMLID( "forward" ), HelpFinderPanel::OnForward )

	EVT_INIT_DIALOG( HelpFinderPanel::OnInitDialog )

	EVT_TEXT_ENTER( XMLID( "name" ), HelpFinderPanel::OnEnter )
	EVT_TEXT_ENTER( XMLID( "context" ), HelpFinderPanel::OnEnter )

	EVT_SET_FOCUS( HelpFinderPanel::OnSetFocus )

END_EVENT_TABLE()

HelpFinderPanel::HelpFinderPanel()

	: mpFinder( NULL )
{}

void HelpFinderPanel::SetFinder( wxPMHelpFinderService* finderSvc )
{
	mpFinder = finderSvc;
}

void HelpFinderPanel::OnInitDialog( wxInitDialogEvent& event )
{
	wxTextCtrl* pName = (wxTextCtrl*)wxXmlFindWindow( "name", this );
	pName->SetValue("");
	wxTextCtrl* pCtx = (wxTextCtrl*)wxXmlFindWindow( "context", this );
	pCtx->SetValue("");

	FocusName();
}

void HelpFinderPanel::OnSetFocus( wxFocusEvent& event )
{
}

void HelpFinderPanel::OnEnter( wxCommandEvent& event )
{
	OnSearch( event );
}

void HelpFinderPanel::OnSearch( wxCommandEvent& event )
{
	wxTextCtrl* name = (wxTextCtrl*)wxXmlFindWindow( "name", this );
	wxTextCtrl* ctx = (wxTextCtrl*)wxXmlFindWindow( "context", this );

	ItemTable& itbl = mpFinder->GetIndexingService()->GetItemTable();

	bool found = FALSE;

	if ( itbl.FindByName( name->GetValue().Lower(), ctx->GetValue().Lower(), 
						  wxPMHelpFinderService::WX_HELP_ENTRY_ITEM,
						  TRUE ) )
	

		found = LoadItemContent();
	
	if ( !found )
	{
		wxString s = ctx->GetValue() + "::" + name->GetValue();

		SetPageContent( "<html><body>\"<b>" + s  + "</b>\" not found!</body></html>" );
	}
}

bool HelpFinderPanel::LoadItemContent()
{
	wxPMIndexingService& isvc = *mpFinder->GetIndexingService();
	ItemTable& itbl = isvc.GetItemTable();
	FileTable& ftbl = isvc.GetFileTable();

	if ( !ftbl.FindById( itbl.GetFileId() ) )
		return FALSE;

	wxFile fl( ftbl.GetName() );
	if ( !fl.IsOpened() )
		return FALSE;

	int len = itbl.GetLineCount();
	int pos = itbl.GetLineNo();
	char* buf = new char[ len + 1 ];

	if ( fl.Seek( pos ) != pos )
		return FALSE;

	if ( fl.Read( buf, len ) != len )
		return FALSE;

	buf[len] = '\0';

	SetPageContent( "<html><body>" + wxString(buf) + "</body></html>" );

	delete [] buf;

	return TRUE;
}

void HelpFinderPanel::SetPageContent( const wxString& html )
{
	wxHtmlWindow* wnd = (wxHtmlWindow*)wxXmlFindWindow( "htmlWindow", this );

	wnd->SetPage( html );
}
void HelpFinderPanel::OnTop( wxCommandEvent& event )
{
}

void HelpFinderPanel::OnBack( wxCommandEvent& event )
{
}

void HelpFinderPanel::OnForward( wxCommandEvent& event )
{
}

void HelpFinderPanel::FocusName()
{
	wxTextCtrl* name = (wxTextCtrl*)wxXmlFindWindow( "name", this );
	name->SetFocus();
	name->SetSelection(0,200);
}