/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/08
// RCS-ID:      $Id: srceditordoc.cpp,v 1.8 2001/04/22 19:58:14 aleksandras Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "srceditordoc.cpp"
    #pragma interface "srceditordoc.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 "wx/pmf/srceditordoc.h"
#include "wx/pmf/lseditor.h"


/***** Implementation for class wxSourceCodeDocument *****/

IMPLEMENT_DYNAMIC_CLASS( wxSourceCodeDocument, wxPMDocument )

wxSourceCodeDocument::wxSourceCodeDocument()
{
	mpModel = new wxTextEditorModel();

	mpModel->SetCheckpoint();
}

wxSourceCodeDocument::~wxSourceCodeDocument()
{
	if ( mpModel )
        delete mpModel;
}

bool wxSourceCodeDocument::SavePMDocument( wxOutputStream& s )
{
	char* buf = NULL; size_t len = 0;

	mpModel->GetAllText( &buf, len );

	s.Write( buf, len );

	mpModel->FreeCharacters( buf );

	mpModel->SetCheckpoint();

	return TRUE;
}

bool wxSourceCodeDocument::LoadPMDocument( wxInputStream& s )
{
	wxString text;
	bool ok = wxPMReadStreamToString( s, text );

	wxASSERT( ok ); // DBG:: FOR NOW::

	mpModel->InsertText( TPosition( 0,0 ), (const char*)text, text.Length() );

	mpModel->ClearUndoBuffer();

	mpModel->SetCheckpoint();

	((wxSourceCodeView*)GetFirstView())->GetEditorView()->SyncScrollbars();

	return TRUE;
}

wxString wxSourceCodeDocument::GetAllText()
{
	return mpModel->GetAllText();
}

void wxSourceCodeDocument::ReplaceAllText( const wxString& withText )
{
	mpModel->DeleteRange( TPosition( 0,0 ), 
					      TPosition( mpModel->GetTotalRowCount(), 0 ) );

	mpModel->InsertText( TPosition( 0,0 ), withText );

	mpModel->NotifyAllViews();
}

void wxSourceCodeDocument::GotoLine( int line, int column )
{
	mpModel->OnGotoLine( line, column );

	mpModel->NotifyAllViews();
}

bool wxSourceCodeDocument::IsModified() const
{
	return mpModel->CheckpointModified();
}

void wxSourceCodeDocument::Modify(bool modify)
{
	if ( modify == FALSE )
	{
		mpModel->SetCheckpoint();
	}
}

void* wxSourceCodeDocument::GetInterface( const char* infName, const char* version )
{
	if ( strcmp( infName, "I_ContainingText" ) == 0 )

		return (void*)(I_ContainingText*)this;
	else
	if ( strcmp( infName, "I_MarkableText" ) == 0 )

		return (void*)(I_MarkableText*)this;
	else
		return NULL;
}

/* implementation of I_ContainingText interface */

bool wxSourceCodeDocument::GetAllText( wxString* toStr )
{
	*toStr = mpModel->GetAllText();

	return TRUE;
}

bool wxSourceCodeDocument::GetTextRange( wxString* toStr, int line1, int column1,
										 int line2, int column2 )
{
	char* text = NULL; 
    size_t len = 0;  //glt - unreferenced variable???  Is it supposed to be used?
//glt - Looks like this function was never finished, as it is not used
	mpModel->GetTextFromRange( TPosition( line1, column1 ),
							   TPosition( line2, column2 ), 
							   *toStr );

	return TRUE;
}

void wxSourceCodeDocument::GetEndPosition( int* line, int* column )
{
	*line = mpModel->GetTotalRowCount() - 1;
	*column = 10000;
}

void wxSourceCodeDocument::GetCursorPosition( int* line, int* column )
{
	TPosition pos = mpModel->GetCursor();

	*line = pos.mRow;
	*column = pos.mCol;
}

/* implementation of I_MarkableText interface */

long wxSourceCodeDocument::AddMark( int type, int line )
{
	TPinBase* pPin = NULL;

	if ( type == I_MarkableText::BOOKMARK )

		pPin = new TBookmarkPin( line );
	else
	if ( type == I_MarkableText::BREAKPOINT )

		pPin = new TBreakpointPin( line );
	else
		return -1; // not supported pin type

	long id = mpModel->AddPin( pPin );

	mpModel->MergeChange( line, 1 );

	mpModel->NotifyAllViews();

	return id;
}

bool wxSourceCodeDocument::IsMarked( int type, int line )
{
	TPinBase* pFound = mpModel->GetPinAt( line, ToModelPinType( type ) );

	return pFound != NULL;
}

void wxSourceCodeDocument::RemoveAllMarks( int type )
{
	// TBD::
}

bool wxSourceCodeDocument::RemoveMarkAt( int type, int line )
{
	return mpModel->RemovePinAt( line, ToModelPinType( type ) );
}

bool wxSourceCodeDocument::GetMarkInfo( long markId, int* type, int* line )
{
	TPinBase* pPin = mpModel->FindPinById( markId );

	if ( !pPin ) return FALSE;

	*type = ( pPin->GetTypeCode() == TBookmarkPin::GetPinTypeCode() )
			? I_MarkableText::BOOKMARK : I_MarkableText::BREAKPOINT;

	*line = pPin->GetRow();

	return TRUE;
}

bool wxSourceCodeDocument::RemoveMark( long markId )
{
	TPinBase* pPin = mpModel->FindPinById( markId );

	if ( !pPin ) return FALSE;

	mpModel->MergeChange( pPin->GetRow(), 1 );
	mpModel->RemovePinAt( pPin->GetRow(), pPin->GetTypeCode() );

	mpModel->NotifyAllViews();

	return TRUE;
}

bool wxSourceCodeDocument::JumpToMark( long markId )
{
	TPinBase* pPin = mpModel->FindPinById( markId );

	if ( pPin )
	{
		mpModel->OnGotoLine( pPin->GetRow(), 0 );
		return TRUE;
	}
	else
		return FALSE;
}

/* implementation of wxPMInf_MarkableText interface */

void wxSourceCodeDocument::StartTextUpdateBatch()
{
}

void wxSourceCodeDocument::FinishTextUpdateBatch()
{
}

void wxSourceCodeDocument::InsertText( wxString& text, int line, int column )
{
}

void wxSourceCodeDocument::GetSelection( int* line1, int* column1, int* line2, int* column2 )
{
}

void wxSourceCodeDocument::SetSelection( int line1, int column1, int line2, int column2 )
{
}

void wxSourceCodeDocument::TextPosToScreenPos( int line, int column, int* x, int* y )
{
}

void wxSourceCodeDocument::SetCursorPosition( int line, int column )
{
}

void wxSourceCodeDocument::GetPagePosition( int* line, int* column )
{
}

bool wxSourceCodeDocument::DeleteRenage( int line1, int column1, int line2, int column2 )
{
	return TRUE;
}

wxWindow* wxSourceCodeDocument::GetTextWidgetWindow()
{
	return NULL;
}

wxSize wxSourceCodeDocument::GetCharacterSize()
{
	return wxSize();
}

void wxSourceCodeDocument::HoldCursor( bool hold )
{
}

/*** protected methods ***/

int wxSourceCodeDocument::ToModelPinType( int infPinType )
{
	switch( infPinType )
	{
		case I_MarkableText::BOOKMARK : return TBookmarkPin::GetPinTypeCode();
		case I_MarkableText::BREAKPOINT : return TBreakpointPin::GetPinTypeCode();
		default : return -1;
	}

//	return -1;  // can never be reached
}

/***** Implementation for class wxSourceCodeView *****/

BEGIN_EVENT_TABLE( wxSourceCodeView, wxPMView )

	EVT_MENU( ID_UNDO,				wxSourceCodeView::OnCmdUndo )
	EVT_MENU( ID_REDO,				wxSourceCodeView::OnCmdRedo )
	EVT_MENU( ID_FIND,				wxSourceCodeView::OnCmdFind )
	EVT_MENU( ID_FIND_NEXT,			wxSourceCodeView::OnCmdFindNext )
	EVT_MENU( ID_FIND_PREV,			wxSourceCodeView::OnCmdFindPrev )
	EVT_MENU( ID_TOGGLE_BOOKMARK,	wxSourceCodeView::OnCmdToggleBookmark )
	EVT_MENU( ID_NEXT_BOOKMARK,		wxSourceCodeView::OnCmdNextBookmark )
	EVT_MENU( ID_PREV_BOOKMARK,		wxSourceCodeView::OnCmdPrevBookmark )
	EVT_MENU( ID_TOGGLE_BREAKPOINT, wxSourceCodeView::OnCmdToggleBreakpoint )
	EVT_MENU( ID_SELECT_ALL,		wxSourceCodeView::OnCmdSelectAll )
	EVT_MENU( ID_COPY,				wxSourceCodeView::OnCmdCopy )
	EVT_MENU( ID_PASTE,				wxSourceCodeView::OnCmdPaste )
	EVT_MENU( ID_CUT,				wxSourceCodeView::OnCmdCut )
	EVT_MENU( ID_REMOVE_LINE,		wxSourceCodeView::OnCmdRemoveLine )
	EVT_MENU( ID_INC_INDENT,		wxSourceCodeView::OnCmdIncIndent )
	EVT_MENU( ID_DEC_INDENT,		wxSourceCodeView::OnCmdDecIndent )

END_EVENT_TABLE()

// TBD:: should be made statics of wxSourceCodeView class

static wxCommandInfo _gSourceCodeViewCommands[] = {

	wxCommandInfo( wxSourceCodeView::ID_UNDO, "&Undo", "", "Ctrl+Z|Alt+BACK" ), 
	wxCommandInfo( wxSourceCodeView::ID_REDO, "&Redo", "", "Ctrl+A|Ctrl+BACK" ), 
	wxCommandInfo( -1, "SEPARATOR" ),

	wxCommandInfo( wxSourceCodeView::ID_COPY,		"&Copy", "",  "Ctrl+INSERT" ), 
	wxCommandInfo( wxSourceCodeView::ID_PASTE,		"&Paste", "", "Shift+INSERT" ), 
	wxCommandInfo( wxSourceCodeView::ID_CUT,		"C&ut", "",   "Ctrl+X" ), 
	wxCommandInfo( -1, "SEPARATOR" ),

	wxCommandInfo( wxSourceCodeView::ID_SELECT_ALL, "Select a&ll", "", "" ), 
	wxCommandInfo( wxSourceCodeView::ID_FIND,	   "&Find...", "",   "Ctrl+F" ), 
	wxCommandInfo( wxSourceCodeView::ID_FIND_NEXT, "Find n&ext", "", "F3" ),
	wxCommandInfo( wxSourceCodeView::ID_FIND_PREV, "Find previous", "", "Shift+F3" ),
	wxCommandInfo( -1, "SEPARATOR" ),

	wxCommandInfo( wxSourceCodeView::ID_TOGGLE_BOOKMARK,	"&Toggle bookmark", "",    "Alt+HOME" ), 
	wxCommandInfo( wxSourceCodeView::ID_NEXT_BOOKMARK,		"&Next bookmark", "",      "Alt+NEXT" ), 
	wxCommandInfo( wxSourceCodeView::ID_PREV_BOOKMARK,		"&Previous Bookmark", "", "Alt+PRIOR" ), 
	wxCommandInfo( wxSourceCodeView::ID_TOGGLE_BREAKPOINT,	"Toggle &breakpoint", "",  "F5" ), 
	wxCommandInfo( -1, "SEPARATOR" ),

	wxCommandInfo( wxSourceCodeView::ID_REMOVE_LINE, "Remo&ve line", "", "Ctrl+Y" ), 
	wxCommandInfo( wxSourceCodeView::ID_INC_INDENT,	 "&Increase block indent", "", "TAB" ), 
	wxCommandInfo( wxSourceCodeView::ID_DEC_INDENT,  "&Decrease block indent", "", "Shift+TAB" ), 

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

static wxPMMergableMenuChain _gSourceCodeViewChains[] = {

	wxPMMergableMenuChain( "/&Edit/", _gSourceCodeViewCommands ),

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

IMPLEMENT_DYNAMIC_CLASS( wxSourceCodeView, wxPMView )

wxSourceCodeView::wxSourceCodeView()

	: mpView( NULL )
{}

wxSourceCodeView::~wxSourceCodeView()
{
	if ( mpView )

		mpView->SetModel( NULL );
}

bool wxSourceCodeView::OnCreate( wxDocument* doc, long flags )
{
	if ( !wxPMView::OnCreate( doc, flags ) ) return FALSE;

	wxASSERT( doc->IsKindOf( CLASSINFO(wxSourceCodeDocument) ) ); // DBG::

	wxSourceCodeDocument* pSCDoc = (wxSourceCodeDocument*)doc;

	mpView = new wxTextEditorView( GetViewFrame(), -1, pSCDoc->GetModel(),
								   wxSUNKEN_BORDER, FALSE );

	mpView->SetNextCharReceiver( GetViewFrame() );

	mpModel = pSCDoc->GetModel();

	mpView->Activate();

	mpView->AddPinPainter( new TBreakpointPainter() );

	mpView->SyncScrollbars();

	// FIXME::
	// "X seems to require a forced resize" --Julian

	int x = 0, y = 0;
	GetViewFrame()->GetClientSize(&x, &y);
	GetViewFrame()->SetSize(-1,-1, x+1, y);
	GetViewFrame()->SetSize(-1,-1, x, y);

	mpView->SetFocus();

	return TRUE;
}

wxPMMergableMenuChain* wxSourceCodeView::GetMergableMenuChain()
{
	return _gSourceCodeViewChains;
}

void wxSourceCodeView::OnCmdUndo( wxCommandEvent& event )
{
	mpModel->OnUndo();
}

void wxSourceCodeView::OnCmdRedo( wxCommandEvent& event )
{
	mpModel->OnRedo();
}

void wxSourceCodeView::OnCmdFind( wxCommandEvent& event )
{
	mpModel->OnFind();
}

void wxSourceCodeView::OnCmdFindNext( wxCommandEvent& event )
{
	mpModel->OnFindNext( TRUE );
}

void wxSourceCodeView::OnCmdFindPrev( wxCommandEvent& event )
{
	mpModel->OnFindPrevious( TRUE );
}

void wxSourceCodeView::OnCmdToggleBookmark( wxCommandEvent& event )
{
	mpModel->OnToggleBookmark();
}

void wxSourceCodeView::OnCmdNextBookmark( wxCommandEvent& event )
{
	mpModel->OnNextBookmark();
}

void wxSourceCodeView::OnCmdPrevBookmark( wxCommandEvent& event )
{
	mpModel->OnPreviousBookmark();
}

void wxSourceCodeView::OnCmdToggleBreakpoint( wxCommandEvent& event )
{
	size_t curRow = mpModel->GetCursor().mRow;

	if ( mpModel->GetPinAt( curRow, TBreakpointPin::GetPinTypeCode() ) != NULL )

		mpModel->RemovePinAt( curRow, TBreakpointPin::GetPinTypeCode() );
	else
		mpModel->AddPin( new TBreakpointPin( curRow ) );

	mpModel->MergeChange( curRow, 1 );

	mpModel->NotifyAllViews();
}

void wxSourceCodeView::OnCmdSelectAll( wxCommandEvent& event )
{
	mpModel->OnSelectAll();
}

void wxSourceCodeView::OnCmdCopy( wxCommandEvent& event )
{
	mpModel->OnCopy();
}

void wxSourceCodeView::OnCmdPaste( wxCommandEvent& event )
{
	mpModel->OnPaste();
}

void wxSourceCodeView::OnCmdCut( wxCommandEvent& event )
{
	mpModel->OnCut();
}

void wxSourceCodeView::OnCmdRemoveLine( wxCommandEvent& event )
{
	mpModel->OnDeleteLine();
}

void wxSourceCodeView::OnCmdGotoLine( wxCommandEvent& event )
{
	mpModel->OnGotoLine();
}

void wxSourceCodeView::OnCmdIncIndent( wxCommandEvent& event )
{
	mpModel->OnShiftSelectionIndent( FALSE );
}

void wxSourceCodeView::OnCmdDecIndent( wxCommandEvent& event )
{
	mpModel->OnShiftSelectionIndent( FALSE );
}
