/////////////////////////////////////////////////////////////////////////////
// Name:        No names yet.
// Purpose:     Contrib. demo
// Author:      Aleksandras Gluchovas
// Modified by:
// Created:     2000/02/08
// RCS-ID:      $Id: pm_prjtempl.cpp,v 1.9 2001/04/20 10:17:11 georgetasker Exp $
// Copyright:   (c) Aleksandras Gluchovas
// Licence:   	GPL (version 2.0 or later)
/////////////////////////////////////////////////////////////////////////////

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

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

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

#include "wx/image.h"


/***** Implementation for class wxPMProjectCreatorDialog *****/

PMProjectTypeTemplateListT wxPMProjectCreatorDialog::m_Templates;

wxString wxPMProjectCreatorDialog::m_LRUCategory;

BEGIN_EVENT_TABLE( wxPMProjectCreatorDialog, wxDialog )

	EVT_BUTTON( wxPMProjectCreatorDialog::ID_NEW,    wxPMProjectCreatorDialog::OnNew )
	EVT_BUTTON( wxID_CANCEL,						 wxPMProjectCreatorDialog::OnCancel )
	EVT_BUTTON( wxPMProjectCreatorDialog::ID_HELP,   wxPMProjectCreatorDialog::OnHelp )
	EVT_BUTTON( wxPMProjectCreatorDialog::ID_BROWSE, wxPMProjectCreatorDialog::OnBrowse )

	EVT_TREE_SEL_CHANGED( wxPMProjectCreatorDialog::ID_CATEGORY_TREE,
						  wxPMProjectCreatorDialog::OnTreeItemSelected )

	EVT_SIZE( wxPMProjectCreatorDialog::OnSize ) // memorizes LRU size

	EVT_TEXT( wxPMProjectCreatorDialog::ID_NAME_TEXT, wxPMProjectCreatorDialog::OnText )

END_EVENT_TABLE()

wxSize wxPMProjectCreatorDialog::m_LRUDialogSize( 550,370 );

wxPMProjectCreatorDialog::
	wxPMProjectCreatorDialog( wxWindow* pParent, 
							  const wxString& defaultName, 
							  const wxString& defaultDir,
							  bool createMasksForIamges )

	: wxDialog( pParent, -1, "New Project", 
				wxDefaultPosition, m_LRUDialogSize, 
				wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER | wxTAB_TRAVERSAL ),
	  m_pSelectedType( NULL ),  
	  m_pLocation( NULL ),
	  m_pCurImageList( NULL ),
	  m_TreeImages( 16,16, TRUE, 2 )
{
	// creating controls

	m_pTree = new wxTreeCtrl( this, ID_CATEGORY_TREE );
	m_pList = new wxListCtrl( this, -1, wxDefaultPosition, wxDefaultSize, 
							 wxLC_ICON | wxLC_AUTOARRANGE | wxLC_SINGLE_SEL);

	// TBD:: description field
	//m_pDescText = new wxTextCtrl( this, -1, "", wxDefaultPosition, wxDefaultSize, 
	//							 wxTE_READONLY );
	//m_pDescText->Enable( FALSE );

	wxStaticText* pNameLabel = new wxStaticText( this,-1, "Project &name:" );
	m_pName = new wxTextCtrl( this, ID_NAME_TEXT, defaultName );

	wxStaticText* pDirLabel = new wxStaticText( this,-1, "&Directory:" );
	m_pLocation = new wxTextCtrl( this, -1, defaultDir );

	// awt-layouts stuff::

	GridBagConstraints c;
	c.fill = GridBagConstraints::BOTH;
	c.weightx = 1.0; c.weighty = 1.0;
	c.insets = Insets( 2,2, 2,2 );

	Container& cont = *new Container(this);
	cont.setLayout( new GridBagLayout() );
	cont.setInsets( Insets( 5,5, 5,5 ) );

	Container& panel0 = *new Container();
	panel0.setLayout( new GridBagLayout() );

	c.gridwidth = GridBagConstraints::REMAINDER;
	cont.add( &panel0, &c );

	c.gridwidth = 1;
	panel0.add( m_pTree, &c ); c.gridwidth = GridBagConstraints::REMAINDER;
	panel0.add( m_pList, &c ); c.weighty = 0.0;

	Container& panel = *new Container();
	panel.setLayout( new GridBagLayout() );
	c.insets = Insets( 2,5, 2,5 );

	cont.add( &panel, &c );

	c.weightx = 0.0; c.gridx = 0; c.gridy = 0; c.gridwidth = 1;
	
	c.anchor = GridBagConstraints::SOUTH; c.insets.top = 5;
	panel.add( pNameLabel, &c );

	c.gridwidth = 4; c.gridx = 1; c.insets.top = 2; c.insets.right = 0;
	panel.add( m_pName,     &c ); c.insets.right = 5;
	c.gridy++; c.gridx = 0;

	c.gridwidth = 1;  c.insets.top = 5;
	panel.add( pDirLabel, &c );

	c.gridwidth = 3; c.gridx = 1;  c.insets.top = 2;
	panel.add( m_pLocation, &c );

	c.gridwidth = 1; c.gridx = 4; c.insets.right = 0;
	panel.add( new wxButton( this, ID_BROWSE, "&Browse..." ), &c ); c.insets.right = 5;

	c.gridx = 0; c.gridy++;

	c.insets = Insets( 5,5, 0,5 );

	c.weightx = 1.0; c.gridx = 1;
/*//glt*/	panel.add( new wxStaticText( this,-1, ""), &c ); //(NOTE: This dialog is resizable)
    c.gridx++;     c.weightx = 0.0;

	wxButton* pCreateBtn = new wxButton( this, ID_NEW, "&Create" );
	pCreateBtn->SetDefault();
	
	panel.add( pCreateBtn, &c ); c.gridx++;
	panel.add( new wxButton( this, wxID_CANCEL, "C&ancel" ), &c ); c.gridx++;

	c.insets.right = 0;
	panel.add( new wxButton( this, ID_HELP, "&Help" ), &c ); c.gridx++;

    size_t i;
	for( i = 0; i != m_Templates.Count(); ++i )
	{
		wxPMProjectTypeTemplate& t = *m_Templates[i];

		wxPMPrjCreatorItemData* pData = GetTreeDataForCategory( t.GetCategory() );

		pData->m_Templates.Add( &t );
	}

	// make last-recently-used category visible by default (if any)

	if ( wxPMProjectCreatorDialog::m_LRUCategory != "" )
	{
		wxPMPrjCreatorItemData* pData = 
			
			GetTreeDataForCategory( wxPMProjectCreatorDialog::m_LRUCategory );

		if ( pData )
		{
			wxTreeItemId id = pData->GetId();

			while( id.IsOk() )
			{
				m_pTree->Expand( id );
				id = m_pTree->GetParent( id );
			}

			m_pTree->EnsureVisible( pData->GetId() );
			m_pTree->SelectItem( pData->GetId() );
		}
	}

	// do "cloning" of bitmap object using wx-image,
	// because "shared" bitmaps get dorked, after
	// reloading image list (because of masks probably...)

	// FIXME:: can be slow!
	wxImage img0( wxPMBmpMgr().FindBitmap( "misc/16x16_green_folder" ) );
	wxImage img1( wxPMBmpMgr().FindBitmap( "misc/16x16_green_folder_open" ) );

	m_TreeImages.Add( img0.ConvertToBitmap(), *wxWHITE );
	m_TreeImages.Add( img1.ConvertToBitmap(), *wxWHITE );

	m_pTree->SetImageList( &m_TreeImages);

    // glt - Needed with wxwindows 2.3+ for some reason to get the dialog to
    // not crush all widgets into the upper left corner of the wxDialog
    int w,h;
	GetClientSize(&w, &h);
	SetSize(w,h);

	wxCommandEvent evt; OnText( evt ); // generate value for m_pLocation

	Center( wxBOTH );

//    m_pLocation->SetInsertionPoint(0);
}						

/*** static methods ***/

wxSize wxPMProjectCreatorDialog::GetDialogLRUSize()
{
	return m_LRUDialogSize;
}

wxString wxPMProjectCreatorDialog::GetLRUCategory()
{
	return m_LRUCategory;
}

void wxPMProjectCreatorDialog::SetDefaultCategory( const wxString& cat )
{
	m_LRUCategory = cat;
}

void wxPMProjectCreatorDialog::AddTemplates( PMProjectTypeTemplateListT& templates )
{
    size_t i;
	for( i = 0; i != templates.Count(); ++i )

		m_Templates.Add( templates[i] );
}

void wxPMProjectCreatorDialog::RemoveAllTemplates()
{
    size_t i;
	for( i = 0; i != m_Templates.Count(); ++i )

		delete m_Templates[i];

	m_Templates.Clear();
}

PMProjectTypeTemplateListT& wxPMProjectCreatorDialog::GetTemplates()
{
	return m_Templates;
}

/*** protected methods ***/

wxString wxPMProjectCreatorDialog::GetSubcategory( const wxString& category, size_t depth )
{
	size_t pos = 0, len = category.Length();
	for(;;)
	{
		if ( category[pos] == '/' )
            ++pos;

		size_t start = pos;

		while( pos < len && category[pos] != '/' )
            ++pos;

		if ( depth == 0 )
            return wxString( category, start, pos - start );

		if ( pos >= len )
            return "";

		--depth;
	}

//	return "";  // can never be reached
}

wxPMPrjCreatorItemData* 
	wxPMProjectCreatorDialog::GetTreeDataForCategory( const wxString& category )
{
	wxString curCategory = "/";
	wxTreeItemId item = m_pTree->GetRootItem();

	if ( !item.IsOk() )
		
		item = m_pTree->AddRoot( "Project Types", 0,1, 
								new wxPMPrjCreatorItemData(curCategory) );

	size_t depth = 0;

	for(;;)
	{
		wxString name = GetSubcategory( category, depth );

		if ( name == "" ) 
			
			return (wxPMPrjCreatorItemData*)m_pTree->GetItemData( item );

		long cookie = 0;
		wxTreeItemId child = m_pTree->GetFirstChild( item, cookie );

		while( child.IsOk() )
		{
			if ( m_pTree->GetItemText( child ) == name )

				break;

			child = m_pTree->GetNextChild( item, cookie );
		}

		if ( !child.IsOk() ) 
		{
			// matching item not found, then create the rest of
			// missing branch starting from this "depth"

			while( name != "" )
			{
				curCategory += name + "/";

				item = m_pTree->AppendItem( item, name, 0,1, 
										   new wxPMPrjCreatorItemData( curCategory ) );

				++depth;

				name = GetSubcategory( category, depth );
			}

			if ( !m_pTree->IsExpanded( m_pTree->GetRootItem() ) )

				m_pTree->Expand( m_pTree->GetRootItem() );

			return (wxPMPrjCreatorItemData*)m_pTree->GetItemData( item );
		}
		else
		{
			item = child;

			++depth;

			curCategory += name + "/";
		}
	}

//	return NULL; // never reached

}

wxPMProjectTypeTemplate* wxPMProjectCreatorDialog::GetSelectedType()
{
	return m_pSelectedType;
}

wxString wxPMProjectCreatorDialog::GetProjectName()
{
	return m_Name;
}

wxString wxPMProjectCreatorDialog::GetDirectory()
{
	return m_Directory;
}

void wxPMProjectCreatorDialog::OnNew( wxCommandEvent& event )
{
	if ( !m_pSelectedType && m_pList->GetSelectedItemCount() != 1 )
	{
		wxMessageBox( "You must first select the type of project you want\nto create (e.g. Classical wxApp)", "Application type needed",  wxOK | wxICON_INFORMATION);

		return;
	}

	m_pSelectedType = NULL; size_t cnt = (size_t)m_pList->GetItemCount();

    size_t i;
	for( i = 0; i != cnt; ++i )
	{
		int state = m_pList->GetItemState( i, wxLIST_MASK_STATE |
										   wxLIST_STATE_FOCUSED |
										   wxLIST_STATE_SELECTED  );

		printf( "i = %d state = %d sel_flag = %d \n",
				i, state, wxLIST_STATE_SELECTED );

		if ( ( state & wxLIST_STATE_SELECTED ) || 
             ( state & wxLIST_STATE_FOCUSED  ) )
		{
			printf ( "!!! Selection found !!!\n" );
			wxPMPrjCreatorItemData* pData = (wxPMPrjCreatorItemData*)
					m_pTree->GetItemData( m_pTree->GetSelection() );

			m_pSelectedType = pData->m_Templates[i];
		}
	}

	wxASSERT( m_pSelectedType != NULL ); // DBG::

	m_Directory = m_pLocation->GetValue();
	m_Name = m_pName->GetValue();

	EndModal( wxID_OK );
}

void wxPMProjectCreatorDialog::OnCancel( wxCommandEvent& event )
{
	EndModal( wxID_CANCEL );
}

void wxPMProjectCreatorDialog::OnHelp( wxCommandEvent& event )
{
	wxMessageBox( "TBD:: wxHtmlHelp" );
}

void wxPMProjectCreatorDialog::OnBrowse( wxCommandEvent& event )
{
	wxDirDialog dlg( this, "Choose Project Directory", ::wxGetCwd() );

	if ( dlg.ShowModal() == wxID_OK )
	{
		wxString dir = dlg.GetPath();

		if ( dir[ dir.Length() - 1 ] != wxFILE_SEP_PATH )

			dir += wxFILE_SEP_PATH;

		m_pLocation->SetValue( dir );

		OnText( event ); // regenerate value for m_pLocation
	}
}

void wxPMProjectCreatorDialog::OnTreeItemSelected( wxTreeEvent& event )
{
	wxPMPrjCreatorItemData* pData = (wxPMPrjCreatorItemData*)
		m_pTree->GetItemData( m_pTree->GetSelection() );

	m_LRUCategory = pData->m_Category;

	LoadIcons( pData->m_Templates );
}

void wxPMProjectCreatorDialog::LoadIcons( PMProjectTypeTemplateListT& templates )
{
	if ( m_pCurImageList )
        delete m_pCurImageList;

	// getting common size for all images:

	size_t i; int maxWidth = 0, maxHeight = 0;
	for( i = 0 ; i != templates.Count(); ++i )
	{
		wxBitmap& bmp = templates[i]->GetBitmap();

		maxWidth  = wxMax( bmp.GetWidth(),  maxWidth );
		maxHeight = wxMax( bmp.GetHeight(), maxHeight ); 
	}

	m_pCurImageList = new wxImageList( maxWidth, maxHeight, m_CreateMasks, 1 );

	for( i = 0; i != templates.Count(); ++i )
	{
		// do "cloning" of bitmap object using wx-image,
		// because "shared" bitmaps get dorked, after
		// reloading image list (because of masks probably...)

		// FIXME:: can be slow!
		wxImage img( templates[i]->GetBitmap() );

		if ( m_CreateMasks )
            m_pCurImageList->Add( img.ConvertToBitmap(), *wxWHITE );
        else 
            m_pCurImageList->Add( img.ConvertToBitmap() );
	}

    m_pList->DeleteAllItems();

	m_pList->SetImageList( m_pCurImageList, wxIMAGE_LIST_NORMAL);

	long firstItem = 0;

	for( i = 0; i != templates.Count(); ++i )
	{	
		long item = m_pList->InsertItem( i, templates[i]->GetType(), i );

		 if ( i == 0 )
             firstItem = item;
	}

	if ( templates.Count() )
    {
	  // auto-focus first type in the list
//	  m_pList->SetItemState( firstItem, wxLIST_STATE_FOCUSED, 
//							wxLIST_MASK_STATE  );
	  m_pList->SetItemState( firstItem, wxLIST_STATE_SELECTED, 
							wxLIST_STATE_SELECTED  );
    }
}  // wxPMProjectCreatorDialog::LoadIcons()


size_t wxPMProjectCreatorDialog::GetLastTokenLen( const wxString& text )
{
	if ( text.Length() == 0 )
        return 0;

	size_t i = text.Length();

	while( i != 0 && text[i-1] != wxFILE_SEP_PATH )
        --i;

	return text.Length() - i;
}

wxString wxPMProjectCreatorDialog::ReplaceLastToken( const wxString& text, 
													 const wxString& newToken )
{
	if ( text.Length() == 0 )
        return "";

	return wxString( text, 0, text.Length() - GetLastTokenLen(text) ) + 
		   newToken;
}

void wxPMProjectCreatorDialog::OnText( wxCommandEvent& event )
{
	if ( !m_pLocation )
        return;

	wxString dir = m_pLocation->GetValue();

	dir = ReplaceLastToken( dir, m_pName->GetValue() );

	m_pLocation->SetValue( dir );

	m_pLocation->SetInsertionPointEnd(/* dir.Length() */);
}

void wxPMProjectCreatorDialog::OnSize( wxSizeEvent& event )
{
	int w = 0, h = 0;
	GetSize( &w, &h );

	wxPMProjectCreatorDialog::m_LRUDialogSize.x = w; 
	wxPMProjectCreatorDialog::m_LRUDialogSize.y = h;

	event.Skip();
}

/***** Implementation for class wxPMProjectCreatorDialog *****/

wxPMProjectTypeTemplate::
	wxPMProjectTypeTemplate( const wxString& category, 
						     const wxString& type, 
							 const wxString& desc, 
							 const wxString& imageName, 
							 wxDocTemplate*  pDocTemplate )

	: m_Category( category ),
	  m_Type( type ),
	  m_Desc( desc ),
	  m_ImageName( imageName ),
	  m_pDocTemplate( pDocTemplate )
{}

wxString wxPMProjectTypeTemplate::GetCategory()
{
	return m_Category;
}

wxString wxPMProjectTypeTemplate::GetType()
{
	return m_Type;
}

wxString wxPMProjectTypeTemplate::GetDescription()
{
	return m_Desc;
}

wxString wxPMProjectTypeTemplate::GetImageName()
{
	return m_ImageName;
}

wxDocTemplate* wxPMProjectTypeTemplate::GetDocTemplate()
{
	return m_pDocTemplate;
}

wxBitmap& wxPMProjectTypeTemplate::GetBitmap()
{
	if ( !m_Bmp.Ok() ) 
		
		m_Bmp = wxPMBmpMgr().FindBitmap( m_ImageName );

	return m_Bmp;
}

/***** Implementation for class wxPMProjectCreatorTemplate *****/

wxPMProjectCreatorTemplate::
	wxPMProjectCreatorTemplate( wxDocManager* manager, 
								const wxString& descr, const wxString& filter, 
								const wxString& dir, const wxString& ext, 
								const wxString& docTypeName, const wxString& viewTypeName, 
								wxClassInfo* docClassInfo, wxClassInfo* viewClassInfo, 
								long flags )
	: wxDocTemplate( manager, descr, filter, dir, ext, docTypeName, viewTypeName,
					 docClassInfo, viewClassInfo, flags )
{}

wxPMProjectCreatorTemplate::~wxPMProjectCreatorTemplate()
{}

wxDocument* wxPMProjectCreatorTemplate::CreateDocument( const wxString& path, long flags )
{
	wxPMProjectCreatorDialog dlg( wxPMBootSvc().GetMainWindow(),
								  "Project1", // TBD::
								  ::wxGetWorkingDirectory() + 
								  wxString( wxFILE_SEP_PATH ) );

	if ( dlg.ShowModal() == wxID_OK )
	{
		if ( wxPMBootSvc().HasWorkplace() == FALSE )
		{
			// TBD::

		}

		wxDocTemplate* pTempl = dlg.GetSelectedType()->GetDocTemplate();

		wxString path = dlg.GetDirectory() + wxString(wxFILE_SEP_PATH) + 
						dlg.GetProjectName() + "." + pTempl->GetDefaultExtension();

		wxObject* pObj = pTempl->CreateDocument( path, wxDOC_NEW );

		wxASSERT( pObj->IsKindOf( CLASSINFO(wxPMProject) ) ); // DBG::

		wxPMProject* pPrj = (wxPMProject*)pObj;

		wxASSERT( pPrj ); // DBG::

		wxPMFileInfo* pInfo = new wxPMFileInfo( path );

		pPrj->SetDocumentTemplate( pTempl );
		pPrj->SetTitle( dlg.GetProjectName() );
		pPrj->SetFileInfo( pInfo );

		return pPrj;
	}

	return NULL;
}
