/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/08
// RCS-ID:      
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
    #pragma implementation "ui_lookeditor.cpp"
    #pragma interface "ui_lookeditor.h"
#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 "ui_lookeditor.h"
#include "ui_lookrenderer.h"

#include "wx/image.h"
#include "wx/panel.h"
#include "wx/filedlg.h"
#include "wx/clipbrd.h"

#include "wx/pmf/lseditor.h" // fancy editor for editing script

// X-Framework stuff
#include "XObject.h"
#include "XCellBackground.h"
#include "XSelectionEditor.h"
#include "XPrimitives.h"
#include "XRectEditor.h"

#include "txtrecset.h"
#include "myutils.h"

// sorry, 3 .cpp's and .h's of AWT-layouts contrib. needed to compile this .cpp!

#include "wx/awtlay/awt_emul.h"
#include "wx/awtlay/gridbaglayout.h"
#include "wx/awtlay/flowlayout.h"

/***** Implementation for class wxUILookDocument *****/

IMPLEMENT_DYNAMIC_CLASS( wxUILookDocument, wxPMDocument )

wxUILookDocument::wxUILookDocument()
{}

wxUILookDocument::~wxUILookDocument()
{}

wxTextEditorModel* wxUILookDocument::GetModel()
{
	return mpModel;
}

void wxUILookDocument::SetModel( wxTextEditorModel* pModel )
{
	mpModel = pModel;
}

bool wxUILookDocument::CanHaveFile()
{
	return TRUE;
}

bool wxUILookDocument::SavePMDocument( wxOutputStream& s )
{
	wxUILookView* pView = (wxUILookView*)GetFirstView();

	char* txt = NULL; size_t len = 0;

	mpModel->GetAllText( &txt, len );

	s.Write( (const char*)txt, len );

	mpModel->FreeCharacters( txt );

	mpModel->SetCheckpoint();

	return TRUE;
}

bool wxUILookDocument::LoadPMDocument( wxInputStream& s )
{
	wxString script;
	bool ok = wxPMReadStreamToString( s, script );

	mpModel->InsertText( TPosition(0,0), script.c_str(), script.Length() );

	mpModel->NotifyAllViews();

	mpModel->SetCheckpoint();

	wxASSERT( ok ); // DBG::

	UpdateAllViews( NULL );

	return ok;
}

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

void wxUILookDocument::Modify(bool modify)
{
	if ( modify == FALSE )

		mpModel->SetCheckpoint();
}

/***** Implementation for class wxUILookView *****/

static wxCommandInfo _gLookCommands[] = {

	wxCommandInfo( wxUILookView::ID_UPDATE, "&Update", "", "Ctrl+U" ), 
	wxCommandInfo( wxUILookView::ID_SAVE_AND_UPDATE, "&Save and Update", "", "Ctrl+M" ), 
	wxCommandInfo( wxUILookView::ID_INSERT_IMAGE, "&Insert Image...", "", "Ctrl+I" ), 
	wxCommandInfo( wxUILookView::ID_INSERT_NEW_ITEM, "&New item", "", "" ), 
	wxCommandInfo( wxUILookView::ID_VALIDATE, "&Validate", "", "Ctrl+V" ), 

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

static wxPMMergableMenuChain _gLookEditorMenuChains[] = {

	wxPMMergableMenuChain( "/&Edit/&Look-Editor/", _gLookCommands ),

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

IMPLEMENT_DYNAMIC_CLASS( wxUILookView, wxPMView )

BEGIN_EVENT_TABLE( wxUILookView, wxPMView )

	EVT_MENU( ID_UPDATE, wxUILookView::OnUpdate )
	EVT_MENU( ID_SAVE_AND_UPDATE, wxUILookView::OnSaveAndUpdate )
	EVT_MENU( ID_INSERT_IMAGE, wxUILookView::OnInsertImage )
	EVT_MENU( ID_INSERT_NEW_ITEM, wxUILookView::OnInsertNewItem )
	EVT_MENU( ID_VALIDATE, wxUILookView::OnValidate )

	EVT_TEXT( ID_SCRIPT_TEXT, wxUILookView::OnText )

END_EVENT_TABLE()

wxUILookView::wxUILookView()

	: mpScene( NULL ),
	  mpModel( NULL ),
	  mpScriptView( NULL ),
	  mpRenderer( NULL )
{
}

wxUILookView::~wxUILookView()
{
	if ( mpScene ) 
	{
		delete mpScene;
		GetViewFrame()->PopEventHandler();
	}

	if ( mpRenderer ) delete mpRenderer;
}
/* glt - I see no need for this version of the function.  The other ::OnUpdate
         function does everything this function does....?
void wxUILookView::OnUpdate( wxView* sender, wxObject* hint )
{
	wxUILookDocument* pDoc = (wxUILookDocument*)GetDocument();

	if ( DoValidate() )

		DoUpdate();
}
*/
bool wxUILookView::OnCreate( wxDocument* doc, long flags )
{
	if ( !wxPMView::OnCreate( doc, flags ) ) return FALSE;


#if defined(__WINDOWS__) 
	wxFont font;
    font.SetFaceName("MS Sans Serif");
    font.SetPointSize( 8 );
    font.RealizeResource();

	GetViewFrame()->SetFont( font );
#endif

	// awt-layouts stuff

	Container& cont = *new Container( GetViewFrame() );
	cont.setLayout( new GridBagLayout() );

	mpModel = new wxTextEditorModel();

	((wxUILookDocument*)doc)->SetModel( mpModel );

	mpScriptView = new wxTextEditorView( GetViewFrame(), -1, mpModel );
	mpModel->SetActiveView( mpScriptView );

	wxWindow* pPreviewPanel = new wxPanel( GetViewFrame(), -1,
										   wxDefaultPosition, wxDefaultSize, 
										   wxSUNKEN_BORDER );

	pPreviewPanel->SetFont( font );

#if defined(__WXMSW__) || defined(__WINDOWS__) 
    font.SetFaceName("Courier");
    font.SetPointSize( 9 );
    font.RealizeResource();
#else
    //mFont.SetFamily( wxSWISS );
	mFont = wxSystemSettings::GetSystemFont(wxSYS_OEM_FIXED_FONT);

    font.SetStyle(wxNORMAL);
    font.SetWeight(wxNORMAL);
    font.SetPointSize( 9);
#endif

	mpScriptView->SetFont( font );
	
	GridBagConstraints c;
	int rmd = GridBagConstraints::REMAINDER;
	c.fill  = GridBagConstraints::BOTH;
	c.weightx = 1.0; c.weighty = 1.0; c.insets = Insets( 5,5,0,0 );
	c.gridwidth = 1; c.gridheight = 1;

	c.gridy = 0; c.gridx = 0;
	cont.add( mpScriptView, &c ); c.gridx = 1;
	cont.add( pPreviewPanel, &c );

	Container* btnPanel = new Container();
	btnPanel->setInsets( Insets(5,5,5,5) );
	btnPanel->setLayout( new FlowLayout() );

	c.gridx = 0; c.gridy = 1; c.weighty = 0.0; c.gridwidth = 2;
	cont.add( btnPanel, &c );

	btnPanel->add( new wxButton( GetViewFrame(), ID_UPDATE, "&Update", wxDefaultPosition ) );
	btnPanel->add( new wxButton( GetViewFrame(), ID_SAVE_AND_UPDATE, "&Save and Update", wxDefaultPosition ) );
	btnPanel->add( new wxButton( GetViewFrame(), ID_INSERT_IMAGE, "&Insert Image", wxDefaultPosition ) );
	btnPanel->add( new wxButton( GetViewFrame(), ID_INSERT_NEW_ITEM, "&New Item", wxDefaultPosition ) );
	btnPanel->add( new wxButton( GetViewFrame(), ID_VALIDATE, "&Validate", wxDefaultPosition ) );

	GetViewFrame()->SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE));

	// create preview panel

	wxASSERT( doc->IsKindOf( CLASSINFO(wxUILookDocument) ) );

	mpScene = new XCollection();

	XCellBackground* pBg = new XCellBackground( *wxWHITE );
	mpScene->Insert( pBg );

	XSelectionEditor* pEditor = new XSelectionEditor();
	mpScene->SetEditor( pEditor );

	mpScene->MarkBackgroundObj( *pBg );

	XwxWindowHook* pHook = new XwxWindowHook( pPreviewPanel, mpScene );

	mpRenderer = new wxUILookRenderer();

//glt	OnUpdate( NULL, NULL );
    wxCommandEvent event;
    OnUpdate(event);

	cont.doLayout();

	return TRUE;
}

wxPMMergableMenuChain* wxUILookView::GetMergableMenuChain()
{
	return _gLookEditorMenuChains;
}

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

/*** event handlers ***/

void wxUILookView::OnSaveAndUpdate( wxCommandEvent& event )
{
	if ( !DoValidate() )

		return;

	if ( !DoUpdate() )

		return;

	GetDocument()->Modify( TRUE );

	wxPMBootSvc().GetDocManager()->SaveDocument( (wxUILookDocument*)GetDocument() );

	GetDocument()->Modify( FALSE );
}

void wxUILookView::OnInsertImage( wxCommandEvent& event )
{
#if wxCHECK_VERSION(2,3,0)
    wxFileDialog dlg( wxPMBootSvc().GetMainWindow(), 
					  "Select Image file", "", "", 
					  "BMP files (*.bmp)|*.bmp|PNG files (*.png)|*.png|XPM files (*.xpm)|*.xpm|GIF files (*.gif)|*.gif|JPEG files (*.jpg)|*.jpg|", wxOPEN | wxCHANGE_DIR );
#else
    wxFileDialog dlg( wxPMBootSvc().GetMainWindow(), 
					  "Select Image file", "", "", 
					  "BMP files (*.bmp)|*.bmp|PNG files (*.png)|*.png|XPM files (*.xpm)|*.xpm|GIF files (*.gif)|*.gif|JPEG files (*.jpg)|*.jpg|", wxOPEN );
#endif
	if ( dlg.ShowModal() == wxID_OK )
	{
		long type = wxBITMAP_TYPE_ANY;
		wxString path = dlg.GetPath();

		if ( path.Find( ".bmp" ) )

			type = wxBITMAP_TYPE_BMP;
		else
		if ( path.Find( ".gif" ) )

			type = wxBITMAP_TYPE_GIF;
		else
		if ( path.Find( ".jpg" ) != -1 )

			type = wxBITMAP_TYPE_JPEG;
		else
		if ( path.Find( ".pcx" ) != -1 )

			type = wxBITMAP_TYPE_PCX;
		else
		if ( path.Find( ".png" ) != -1 )

			type = wxBITMAP_TYPE_PNG;
		else
		if ( path.Find( ".PNM" ) != -1 )

			type = wxBITMAP_TYPE_PNM;
		else
		{
			wxMessageBox( "The format of selected image file is not supported" );

			return;
		}

		::wxInitAllImageHandlers();
		wxImage img( path, type );

		if ( !img.Ok() )
		{
			wxMessageBox( "Error loading image from file " + path );

			return;
		}

		Record* pRec = mpRenderer->ImageToRecord( img );

		if ( !pRec )
		{
			wxMessageBox( "Error formatting image-data to text-record" );

			return;
		}
		wxString txt = pRec->GetTextContent();

		txt = ToPlatformText( txt );

		mpModel->WriteText( txt );
		mpScriptView->SetFocus();
	}
}

void wxUILookView::OnInsertNewItem( wxCommandEvent& event )
{
	wxUILookInfo info;
	Record rec;
	rec.SetName( "look_item" );

	mpRenderer->StoreToRecord( info, rec );

	wxString txt = rec.GetTextContent();
	mpModel->WriteText( txt );
}

void wxUILookView::OnValidate( wxCommandEvent& event )
{
	GetDocument()->Modify( TRUE );

	DoValidate();
}

void wxUILookView::OnUpdate( wxCommandEvent& event )
{
	GetDocument()->Modify( TRUE );

	if ( DoValidate() )

		DoUpdate();
}

void wxUILookView::OnText( wxCommandEvent& event )
{
	GetDocument()->Modify( TRUE );

	event.Skip();
}

/*** protected methods ***/

bool wxUILookView::DoValidate()
{
	return mpRenderer->ParseScript( mpModel->GetAllText() );
}

bool wxUILookView::DoUpdate()
{
	mpScene->SelectAll();
	mpScene->DeleteSelection();

	UILookInfoListT lst = mpRenderer->GetInfoItems();

	wxClientDC dc( GetViewFrame() );
	dc.SetFont( GetViewFrame()->GetFont() );

	int labelWidth = 70, curY = 10, curX = 10;

	for( size_t i = 0; i != lst.Count(); ++i )
	{
		wxUILookInfo& info = *lst[i];

		wxString text;
		int x = 0, y = 0, w = 0, h = 0;

		mpRenderer->CalcItemParams( info, wxSize( 0,0 ),
									dc, text, x, y, w, h,
									wxFont(), wxColour(), wxColour(),
									&mpRenderer->GetEqSolver() );


		XLabelObj* pLabel = new XLabelObj( info.mName );
		wxUILookPreviewItem* pPreview = new wxUILookPreviewItem();

		mpScene->Insert( pLabel, FALSE );
		mpScene->Insert( pPreview, FALSE );

		pPreview->SetEditor( new XRectEditor() );
		pLabel->SetEditor( new XRectEditor() );

		pLabel->SetBounds( XRect( curX,curY, labelWidth, h ) );

		pPreview->SetLookInfo( &info, mpRenderer );

		pPreview->SetBoundsNoRefresh( XRect( curX + labelWidth + 30, curY, 
											 w, h ) );

		pPreview->RegenerateBitmap( dc );

		mpScene->InvalidateRect( pLabel->GetInclusiveBounds() );
		mpScene->InvalidateRect( pPreview->GetInclusiveBounds() );

		curY += h + 30;
	}

	mpScene->RefreshNow();

	return TRUE;
}

/***** Implementation for class wxUILookPreviewItem *****/

wxUILookPreviewItem::wxUILookPreviewItem()

	: mpLookInfo( NULL ),
	  mpRenderer( NULL )
{}

wxUILookPreviewItem::~wxUILookPreviewItem()
{}

void wxUILookPreviewItem::Draw( wxDC& canvas )
{
	if ( !mCurBmp.Ok() ) 
		
		RegenerateBitmap( canvas );

	canvas.DrawBitmap( mCurBmp, mBounds.x, mBounds.y );
}

XRect wxUILookPreviewItem::GetBounds()
{
	return mBounds;
}

void wxUILookPreviewItem::SetBounds( const XRect& bounds )
{
	mBounds = bounds;
	RegenerateBitmap( this->GetCanvas() );

	InvalidateRect( GetInclusiveBounds() );

	RefreshNow();
}

void wxUILookPreviewItem::SetBoundsNoRefresh( const XRect& bounds )
{
	mBounds = bounds;

	mCurBmp = wxBitmap();
}

void wxUILookPreviewItem::SetLookInfo( wxUILookInfo* pLookInfo, wxUILookRenderer* pRenderer )
{
	mpLookInfo = pLookInfo;

	mpRenderer = pRenderer;
}

void wxUILookPreviewItem::RegenerateBitmap( wxDC& dc )
{
	if ( mpLookInfo == NULL ) return;

	if ( mBounds == XRect() )
	{
		// TBD:: ?
	}

	bool ok = mpRenderer->RenderItemLook( *mpLookInfo, 
										  wxSize( mBounds.width, mBounds.height ), 
										  wxPMBootSvc().GetMainWindow(),
										  mCurBmp, dc,
										  wxFont(), wxColour(), wxColour(), NULL );
}
