/***************************************************************************
 *   Copyright (C) 2005 by Thierry CHARLES   *
 *   thierry@les-charles.net   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "mainwindow.h"
#include "res_id.h"
#include "version.h"
#include "defs.h"

#include <sys/time.h>
#include <wx/wx.h>
#include <wx/icon.h>
#include <wx/filename.h>
#include <wx/msgdlg.h>
#include <wx/arrstr.h>
#include <wx/numdlg.h>
#include <wx/statusbr.h>
#include <wx/dir.h>
#include <wx/wfstream.h>
#include <wx/utils.h>
#include <wx/wfstream.h>

#include "xpe.h"
#include "components/calculator/calculator_pe.h"
#include "components/clock/clock_panelelement.h"
#include "components/stdgui/tframe.h"
#include "components/stdgui/tgenbutton.h"
#include "components/stdgui/tbitmap.h"
#include "components/framework/tapplicationpanel.h"
#include "components/framework/tconfigdlg.h"
#include "xpe_components/config/keywords_cfg.h"
#include "xpe_components/config/editor_cfg.h"
#include "xpe_components/config/mainwindow_cfg.h"
#include "xpe_components/config/renderer_cfg.h"
#include "xpe_components/config/misc_cfg.h"
#include "xpe_components/config/paths_cfg.h"
#include "xpe_components/dlg/xpe_exit_dlg.h"
#include "xpe_components/editor/pov_enlighter.h"
#include "xpe_components/editor/pov_panelelement.h"
#include "xpe_components/editor/ini_panelelement.h"
#include "xpe_components/filepelt/imageviewer/imageviewer_pelt.h"
#include "xpe_components/panelelt/documents_panelelt.h"
#include "xpe_components/panelelt/explorer_panelelt.h"
#include "xpe_components/panelelt/help_panelelt.h"
#include "xpe_components/panelelt/navig_panelelt.h"
#include "xpe_components/panelelt/notes_panelelt.h"
#include "xpe_components/panelelt/renderer_panelelt.h"
#include "xpe_components/panelelt/tools_panelelt.h"
#include "xpe_components/panelelt/std_toolbars.h"
#include "xpe_components/parser/povparserres.h"
#include "lib/lib_http.h"
#include "lib/lib_file.h"
#include "lib/lib_logging.h"

#include "bitmaps/xpe_16.xpm"

DEFINE_EVENT_TYPE(EVENT_CLOSE_TAB)

XPEMainWindow::XPEMainWindow(XPE * app)
    : TMainWindow(NULL, -1, app->getName()),
    filesHistory(NULL),
    application(app),
    bDefaultParametersLoaded(false),
    searchDlg(NULL),
    replaceDlg(NULL),
    menuInsert(NULL)
{
    this->SetIcon(wxIcon(xpe_16_xpm));
    this->filesHistory = new wxFileHistory(9,File_Recent1);

    // construction du menu de base

    // Menu File
    wxMenuBar *menuBar = new wxMenuBar();
    wxMenu * menuFile = new wxMenu();

    menuFile->Append( File_PovNew, wxTr( "&New povray scene\tCTRL+N" ), wxTr( "Create a new empty povray file" ));
    this->Connect( File_PovNew, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileNew), NULL, this );
    menuFile->Append( File_IniNew, wxTr( "&New povray ini" ), wxTr( "Create a new empty povray ini-file" ));
    this->Connect( File_IniNew, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileNew), NULL, this );
    menuFile->Append( File_Open, wxTr( "&Open ...\tCTRL+O" ), wxTr( "Open a dialog to choose the file to open" ));
    this->Connect( File_Open, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileOpen), NULL, this );
    wxMenu * menuFileRecent = new wxMenu( );
    menuFile->Append( File_Recent, wxTr("Recent files"), menuFileRecent );
    this->Connect( File_Recent1, File_Recent9, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileOpen), NULL, this );
    this->filesHistory->UseMenu(menuFileRecent);
    menuFile->AppendSeparator();
    menuFile->Append( File_Save, wxTr( "&Save\tCTRL+S" ), wxTr( "Save current file" ) );
    this->Connect( File_Save, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileSave), NULL, this );
    menuFile->Append( File_Save_As, wxTr( "S&ave as ..." ), wxTr( "Open a dialog to choose the file name to save under" ) );
    this->Connect( File_Save_As, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileSaveAs), NULL, this );
    menuFile->Append( File_Close, wxTr( "&Close\tCTRL+W" ), wxTr( "Close the active editor tab" ) );
    this->Connect( File_Close, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileClose), NULL, this );
    menuFile->AppendSeparator();
    menuFile->Append( File_Quit, wxTr( "E&xit\tCTRL+Q" ), wxTr( "Exit the application" ) );
    this->Connect( File_Quit, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnFileQuit), NULL, this );

    menuBar->Append( menuFile, wxTr( "&File" ) );

    // Menu Edit
    wxMenu * menuEdit = new wxMenu();

    menuEdit->Append( Edit_Undo, wxTr( "Undo\tCTRL+Z" ), wxTr( "Undo last operation in the active editor tab") );
    this->Connect( Edit_Undo, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditUndoRedo), NULL, this );
    menuEdit->Append( Edit_Redo, wxTr( "Redo\tCTRL+SHIFT+Z" ) , wxTr( "Replay last canceled operation"));
    this->Connect( Edit_Redo, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditUndoRedo), NULL, this );
    menuEdit->AppendSeparator();
    menuEdit->Append( Edit_Cut, wxTr( "Cut\tCTRL+X" ), wxTr("Copy selected text to clipoard and delete it") );
    this->Connect( Edit_Cut, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditCutCopyPaste), NULL, this );
    menuEdit->Append( Edit_Copy, wxTr( "Copy\tCTRL+C" ), wxTr("Copy selected text to clipoard") );
    this->Connect( Edit_Copy, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditCutCopyPaste), NULL, this );
    menuEdit->Append( Edit_Paste, wxTr( "Paste\tCTRL+V" ), wxTr("Paste clipboard content") );
    this->Connect( Edit_Paste, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditCutCopyPaste), NULL, this );
    menuEdit->AppendSeparator();
    menuEdit->Append( Edit_Gotoline, wxTr( "Go to line ...\tCTRL+G" ), wxTr("Goes to the selected line") );
    this->Connect( Edit_Gotoline, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditGoToLine), NULL, this );
    menuEdit->AppendSeparator();
    menuEdit->Append( Edit_SelectAll, wxTr( "Select all\tCTRL+A" ), wxTr("Selects all the active document") );
    this->Connect( Edit_SelectAll, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditSelectAll), NULL, this );
    menuEdit->Append( Edit_JoinLines, wxTr( "Join lines\tCTRL+J" ), wxTr("Join current and next lines") );
    this->Connect( Edit_JoinLines, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditJoinLines), NULL, this );
    menuEdit->Append( Edit_DeleteLine, wxTr( "Delete line\tCTRL+K" ), wxTr("Delete current line") );
    this->Connect( Edit_DeleteLine, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditDeleteLine), NULL, this );
    menuEdit->Append( Edit_CommentIn, wxTr( "Comment lines\tCTRL+D" ), wxTr("Comment selected lines") );
    this->Connect( Edit_CommentIn, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditComment), NULL, this );
    menuEdit->Append( Edit_CommentOut, wxTr( "Un-comment lines\tCTRL+SHIFT+D" ), wxTr("Un-comment selected lines") );
    this->Connect( Edit_CommentOut, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditComment), NULL, this );
    menuEdit->AppendSeparator();
    menuEdit->Append( Edit_Find, wxTr( "Find ...\tCTRL+F" ), wxTr("Search text in the active document") );
    this->Connect( Edit_Find, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditFind), NULL, this );
    menuEdit->Append( Edit_FindSel, wxTr( "Find selection\tCTRL+F3" ), wxTr("Search next occurence of currently selected text") );
    this->Connect( Edit_FindSel, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditFindSel), NULL, this );
    menuEdit->Append( Edit_FindNext, wxTr( "Find next\tF3" ), wxTr("Search next occurence of searched text") );
    this->Connect( Edit_FindNext, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditFindNext), NULL, this );
    menuEdit->Append( Edit_Replace, wxTr( "Replace ...\tCTRL+R" ), wxTr("Replace text in the document") );
    this->Connect( Edit_Replace, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditReplace), NULL, this );
    menuEdit->AppendSeparator();
    menuEdit->Append( Edit_Preferences, wxTr( "Preferences ..." ), wxTr("Open the configuration manager") );
    this->Connect( Edit_Preferences, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnEditPreferences), NULL, this );

    menuBar->Append( menuEdit, wxTr( "&Edit" ) );



    // Menu Insert
    this->menuInsert = new wxMenu();

    this->menuInsert->Append( Insert_Reload, wxTr( "Reload ..." ), wxTr( "Reloads the insert menu") );
    this->Connect( Insert_Reload, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnInsertReload ), NULL, this );

    menuBar->Append( menuInsert, wxTr( "&Insert" ) );


    // Menu XPE
    wxMenu * menuXPE = new wxMenu();

    menuXPE->Append( Nextpe_CheckUpdates, wxTr( "Check for new version ..." ), wxTr( "Check if a new version has been released on http://nextpe.sf.net/") );
    this->Connect( Nextpe_CheckUpdates, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnNextpeCheckUpdates), NULL, this );
    menuXPE->Append( Nextpe_About, wxTr( "A&bout...\tF1" ), wxTr( "Display informations about the application" ) );
    this->Connect( Nextpe_About, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnNextpeAbout), NULL, this );

    menuBar->Append( menuXPE, wxTr( "-X-P-E-" ) );


    this->SetMenuBar( menuBar );

    wxStatusBar * statusBar = this->CreateStatusBar();
    int fieldsWidths[4];
    fieldsWidths[0] = -1;
    fieldsWidths[1] = 150;
    fieldsWidths[2] = 40;
    fieldsWidths[3] = 25;
    statusBar->SetFieldsCount(4,fieldsWidths);
    int fieldsStyles[4];
    fieldsStyles[0] = wxSB_FLAT;
    fieldsStyles[1] = wxSB_NORMAL;
    fieldsStyles[2] = wxSB_NORMAL;
    fieldsStyles[3] = wxSB_FLAT;
    statusBar->SetStatusStyles(4,fieldsStyles);
    this->updateCursorStatusInfos();
    this->SetStatusText( wxTr("Welcome in neXtgen Povray Editor") );




    TApplicationPanel * panel = new TApplicationPanel(this,CENTER_PANEL_ID,TApplicationPanel::Center);
    panel->setDisplayMode(TApplicationPanel::Exclusive);
    panel->setMightHaveNoVisibleElement(false);
    this->setCenterPanel(panel);

    panel = new TApplicationPanel(this,TOP_PANEL_ID,TApplicationPanel::Top );
    panel->setDisplayMode(TApplicationPanel::Shared);
    this->setTopPanel(panel);

    panel = new TApplicationPanel(this,LEFT_PANEL_ID,TApplicationPanel::Left);
    panel->setDisplayMode(TApplicationPanel::Shared);
    this->setLeftPanel(panel);

    panel = new TApplicationPanel(this,RIGHT_PANEL_ID,TApplicationPanel::Right);
    panel->setDisplayMode(TApplicationPanel::Shared);
    this->setRightPanel(panel);

    panel = new TApplicationPanel(this,BOTTOM_PANEL_ID,TApplicationPanel::Bottom);
    panel->setDisplayMode(TApplicationPanel::Shared);
    this->setBottomPanel(panel);

    this->Connect(EVENT_CLOSE_TAB, wxCommandEventHandler( XPEMainWindow::OnCloseTab ), NULL, this );
}

XPEMainWindow::~XPEMainWindow()
{
}

void XPEMainWindow::OnNextpeAbout( wxCommandEvent& WXUNUSED( event ) )
{
    wxMessageBox( wxTr( "Visit us at http://nextpe.sf.net/ to get the latest version, or to get documentation.\nneXtgen Povray Editor is maintained by Thierry CHARLES http://www.les-charles.net\n" ),
                  wxString::Format(wxTr( "neXtgen Povray Editor %s (%s)" ),
                                   wxT(XPE_OFFICIAL_VERSION),
                                    wxString::Format(wxT("%d"),XPE_VERSION).c_str()),
                  wxOK | wxICON_INFORMATION, this );
}

void XPEMainWindow::OnNextpeCheckUpdates( wxCommandEvent& WXUNUSED(event) )
{
    this->checkForUpdate(false);
}

void XPEMainWindow::OnFileQuit( wxCommandEvent& WXUNUSED( event ) )
{
    this->Close(false);
}

void XPEMainWindow::OnFileNew( wxCommandEvent& event )
{
    static wxLongLong iLastEvent = 0;
    wxLongLong iCurrentEvent = ::wxGetLocalTimeMillis();
    if(iCurrentEvent - iLastEvent < 250)
        return;
    iLastEvent = iCurrentEvent;

    this->createNewEditorTab((event.GetId() == File_PovNew) ? Povfile : Inifile);
}

void XPEMainWindow::OnFileOpen( wxCommandEvent& event )
{
    if(event.GetId() == File_Open)
    {
        wxFileDialog * dlg = new wxFileDialog(this, wxTr("Choose a file"), wxT(""), wxT(""),
                wxSTr("Povray scripts") + wxT(" (*.pov)|*.pov|")
                + wxSTr("Povray includes") + wxT(" (*.inc)|*.inc|")
                + wxSTr("Povray ini") + wxT(" (*.ini)|*.ini|")
                + wxSTr("Image files") + wxT(" (*.png;*.jpg;*.jpeg;*.tiff;*.gif)|*.png;*.jpg;*.jpeg;*.tiff;*.gif|"),
                wxOPEN|wxFILE_MUST_EXIST);
        int iRes = dlg->ShowModal();
        if(iRes == wxID_OK)
        {
            this->loadFile(dlg->GetPath());
        }

        delete dlg;
    }
    else
    {
        this->loadFile(this->filesHistory->GetHistoryFile(event.GetId() - File_Recent1));
    }
}

void XPEMainWindow::OnFileSave( wxCommandEvent& WXUNUSED( event ) )
{
    this->writeFile();
}

void XPEMainWindow::OnFileSaveAs( wxCommandEvent& WXUNUSED( event ) )
{
    this->writeFileAs();
}

void XPEMainWindow::OnFileClose( wxCommandEvent& WXUNUSED( event ) )
{
    static wxLongLong iLastEvent = 0;
    wxLongLong iCurrentEvent = ::wxGetLocalTimeMillis();
    if(iCurrentEvent - iLastEvent < 250)
        return;
    iLastEvent = iCurrentEvent;

    this->closeTab();
}

void XPEMainWindow::OnCloseTab( wxCommandEvent& event )
{
    FileViewerPanelElement * tab = dynamic_cast<FileViewerPanelElement *>(event.GetEventObject());
    if(!tab)
        return;

    this->closeTab(tab);
}

/**
 * cree un nouveau panneau d'edition du type passe en parametre sans lui affecter aucun nom ni le rendre visible
 * @param type type d'editeur a creer
 * @return editeur cree
 */
FileViewerPanelElement * XPEMainWindow::_createNewFileTab(FileTabType type)
{
    FileViewerPanelElement * panelElt = NULL;
    const char * szType = NULL;
    switch(type)
    {
        case Povfile :
            szType = PELT_TYPE_POVEDITOR;
            break;
        case Inifile :
            szType = PELT_TYPE_INIEDITOR;
            break;
        case ImageFile :
            szType = PELT_TYPE_IMAGEVIEWER;
            break;
    }
    if(!szType)
        return NULL;

    panelElt = dynamic_cast<FileViewerPanelElement *>(CurrentApplication()->builElement(
                                            szType, this->getCenterPanel(),-1));

    if(type == Povfile || type == Inifile)
    {
        EditorPanelElement * editorElt = dynamic_cast<EditorPanelElement *>(panelElt);
        if(editorElt)
        {
            editorElt->getEditor()->addCodeEditorListener(this);
            editorElt->getEditor()->getCursor()->addCursorListener(this);
        }
    }

    return panelElt;
}

/**
 * creer un nouveau panneau d'edition du type passe en parametre
 * @param type type d'editeur a creer
 * @return editeur cree
 */
EditorPanelElement * XPEMainWindow::createNewEditorTab(FileTabType type)
{
    static int iCreatedTabs = 0;
    EditorPanelElement * panelElt = dynamic_cast<EditorPanelElement *>(this->_createNewFileTab(type));
    if(panelElt != NULL)
    {
        panelElt->setName(wxString(wxTr("New file ")) + wxString::Format(wxT("%d"),++iCreatedTabs));
        this->getCenterPanel()->setElementVisible( panelElt->getID(), true );
        panelElt->getEditor()->addCodeEditorListener(this);
        panelElt->getEditor()->getCursor()->addCursorListener(this);
        this->getCenterPanel()->setElementVisible(panelElt->getID(),true);
    }
    return panelElt;
}

/**
 * charge le fichier sFilename
 */
bool XPEMainWindow::loadFile(const wxString & _sFilename)
{
    if(!libfile::exists(_sFilename))
        return false;

    wxString sFilename = libfile::normalize( _sFilename );
    TFilenameToElementMap::iterator it = this->openFiles.find(sFilename);
    if(it == this->openFiles.end())
    {
        FileTabType type = Povfile;
        wxString sExt = libfile::extension(sFilename);
        sExt.MakeLower();
        if(libfile::isBinary(sFilename))
        {
            // est-ce une image ?
            wxFileType * ft = CurrentApplication()->getMimeTypesManager().GetFileTypeFromExtension(sExt);
            if(ft)
            {
                wxString sMimeType;
                if(ft->GetMimeType(&sMimeType))
                {
                    if(sMimeType.StartsWith(wxT("image/")))
                        type = ImageFile;
                    else
                        return false;
                }
                else
                {
                    LOG_MESSAGE(wxString(wxT("Type de fichier indetermine : ")) + sExt, logging::_ERROR_);
                    return false; // type de fichier indetermine
                }
            }
            else
                return false;
        }
        else
        {
            if(sExt == wxT(".ini"))
                type = Inifile;
        }

        FileViewerPanelElement * panelElt = NULL;
        if(this->getCenterPanel()->getElementsCount() == 1)
        {
            if(type == Povfile)
                panelElt = dynamic_cast<PovPanelElement *>(this->getCenterPanel()->getElementAt(0));
            else if(type == Inifile)
                panelElt = dynamic_cast<IniPanelElement *>(this->getCenterPanel()->getElementAt(0));
            if((!panelElt) || panelElt->isModified() || panelElt->getFilename().length())
                panelElt = NULL;
        }

        bool bRemovePanelOnFail = (panelElt == NULL);
        if(panelElt == NULL)
            panelElt = this->_createNewFileTab(type);

        if(panelElt == NULL)
            return false;

        if(panelElt->loadFile(sFilename))
        {
            this->openFiles[sFilename] = panelElt;
            this->filesHistory->AddFileToHistory(sFilename);

            this->getCenterPanel()->setElementVisible(panelElt->getID(),true);

            return true;
        }
        else
        {
            if(bRemovePanelOnFail)
                this->getCenterPanel()->removeElement(panelElt->getID(),true);
            return false;
        }
    }
    else
    {
        this->getCenterPanel()->setElementVisible((*it).second->getID(), true);
        return true;
    }
}

/**
 * recherche un fichier dans la liste des fichiers ouverts
 */
TPanelElement * XPEMainWindow::getTabFromFile(const wxString & _sFilename)
{
    TFilenameToElementMap::iterator it = this->openFiles.find(libfile::normalize( _sFilename ));
    if(it == this->openFiles.end())
        return NULL;
    return (*it).second;
}

/**
 * recherche un editeur dans la liste des fichiers ouverts
 */
TPanelElement * XPEMainWindow::getTabFromId(int iEditorId)
{
    return this->getCenterPanel()->getElement(iEditorId);
}

/**
 * ecris l'editeur actuellement visible dans un fichier selectionnable
 */
bool XPEMainWindow::writeFileAs()
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    return this->writeFileAs(static_cast<EditorPanelElement *>(elt));
}

/**
 * ecris l'editeur dans un fichier selectionnable
 */
bool XPEMainWindow::writeFileAs(FileViewerPanelElement * elt)
{
    if(!elt)
        return false;

    wxFileDialog * dlg = new wxFileDialog(this,elt->getName() + wxTr("- Save as ..."),wxT(""),wxT(""),wxT("*.*"),wxSAVE|wxOVERWRITE_PROMPT);
    int iRes = dlg->ShowModal();
    bool bSucces = false;
    if(iRes == wxID_OK)
    {
        wxString sNewFilename = dlg->GetPath();
        wxString sExt = libfile::extension(sNewFilename);
        if(!sExt.length())
        {
            if(!strcmp(elt->getElementType(),PELT_TYPE_POVEDITOR))
                sNewFilename += wxT(".pov");
            else if(!strcmp(elt->getElementType(),PELT_TYPE_INIEDITOR))
                sNewFilename += wxT(".ini");
        }
        bSucces = this->writeFile(elt,sNewFilename);
    }
    delete dlg;
    return bSucces;
}

/**
 * ecris l'editeur actuellement visible sous le nom de fichier sFilename
 */
bool XPEMainWindow::writeFile()
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    return this->writeFile(static_cast<FileViewerPanelElement *>(elt));
}

/**
 * ecris l'editeur actuellement visible sous le nom de fichier sFilename
 */
bool XPEMainWindow::writeFile(const wxString & sFilename)
{
    FileViewerPanelElement * elt = static_cast<FileViewerPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if(elt == NULL)
        return false;
    return this->writeFile(elt,sFilename);
}

/**
 * ecris l'editeur passe en parametre sous le nom de fichier sFilename
 */
bool XPEMainWindow::writeFile(FileViewerPanelElement * elt)
{
    if(elt)
    {
        if(elt->getFilename().length() == 0)
            return this->writeFileAs(elt);
        else
            return elt->writeFile();
    }

    return false;
}

/**
 * ecris l'editeur passe en parametre sous le nom de fichier sFilename
 */
bool XPEMainWindow::writeFile(FileViewerPanelElement * elt, const wxString & sFilename)
{
    wxString sOldFileName = elt->getFilename();
    bool bRes = elt->writeFile(sFilename);
    if(bRes)
    {
        this->openFiles.erase(sOldFileName);
        this->openFiles[libfile::normalize(sFilename)] = elt;
    }
    return bRes;
}

/**
 * ferme l'onglet courrant apres avoir procede a une eventuelle sauvegarde
 */
void XPEMainWindow::closeTab()
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if(elt)
        this->closeTab(static_cast<FileViewerPanelElement *>(elt));
}

/**
 * ferme l'onglet apres avoir procede a une eventuelle sauvegarde
 */
void XPEMainWindow::closeTab(FileViewerPanelElement * elt)
{
    if(!elt)
        return;

    if(elt->isModified())
    {
        int iRes = wxMessageBox(
                            wxTr("This file has been modified. Do you want to save modifications ?"),
                            wxTr("Modified file"),
                            wxYES_NO | wxCANCEL,
                            this);

        if(iRes == wxYES)
        {
            if(!this->writeFile())
                return;
        }
        if(iRes == wxCANCEL)
            return;
    }

    EditorPanelElement * editorElt = dynamic_cast<EditorPanelElement *>(elt);
    if(editorElt)
    {
        editorElt->getEditor()->removeCodeEditorListener(this);
        editorElt->getEditor()->getCursor()->removeCursorListener(this);
    }

    TFilenameToElementMap::iterator it = this->openFiles.find(elt->getFilename());
    if(it != this->openFiles.end())
        this->openFiles.erase(it);

    this->getCenterPanel()->removeElement(elt->getID());
    elt = NULL;

    if(!this->getCenterPanel()->getElementsCount())
        this->createNewEditorTab(Povfile);
}

/** demande la fermeture de la fenetre */
bool XPEMainWindow::tryToClose()
{
    return this->askForModifiedFilesSave();
}

/** demande quels fichiers modifies il faut sauvegarder */
bool XPEMainWindow::askForModifiedFilesSave()
{
    // recherche des fichiers modifies
    XPEExitDlg::TEltsList elts;
    int iTabsCount = this->getCenterPanel()->getElementsCount();
    for(int i = 0 ; i < iTabsCount ; i++)
    {
        EditorPanelElement * elt = static_cast<EditorPanelElement *>(this->getCenterPanel()->getElementAt(i));
        if(elt->isModified())
        {
            elts.push_back(elt);
        }
    }

    if(elts.size())
    {
        XPEExitDlg * dlg = new XPEExitDlg(this);

        dlg->setModifiedElements( elts );

        int iRes = dlg->ShowModal();
        elts = dlg->getSelectedElements();
        delete dlg;

        if(iRes != wxID_OK)
            return false;


        XPEExitDlg::TEltsList::const_iterator itB = elts.begin();
        XPEExitDlg::TEltsList::const_iterator itE = elts.end();

        while(itB != itE)
        {
            bool bOk = this->writeFile(*itB);
            if(!bOk)
                return false;
            itB++;
        }
    }

    return true;
}

/** charge les parametres par defaut */
void XPEMainWindow::loadDefaultParameters()
{
    if(this->bDefaultParametersLoaded)
        return;

    this->Maximize();

    if(!this->getCenterPanel()->getElementsCount())
        this->createNewEditorTab(Povfile);

    CurrentApplication()->builElement( PELT_TYPE_TCLOCK, this->getLeftPanel(), -1)->setName(wxTr("Clock"));
    CurrentApplication()->builElement( PELT_TYPE_DOCUMENTS, this->getLeftPanel(), -1)->setName(wxTr("Documents"));
    CurrentApplication()->builElement( PELT_TYPE_NOTES, this->getLeftPanel(), -1)->setName(wxTr("Notepad"));
    CurrentApplication()->builElement( PELT_TYPE_NAVIGATOR, this->getLeftPanel(), -1)->setName(wxTr("Navigator"));

    CurrentApplication()->builElement( PELT_TYPE_TOOLBAR_FILE, this->getTopPanel(), -1)->setName(wxTr("File toolbar"));
    CurrentApplication()->builElement( PELT_TYPE_TOOLBAR_EDIT, this->getTopPanel(), -1)->setName(wxTr("Edit toolbar"));
    CurrentApplication()->builElement( PELT_TYPE_TOOLBAR_EDIT2, this->getTopPanel(), -1)->setName(wxTr("Advanced edition toolbar"));
    CurrentApplication()->builElement( PELT_TYPE_TOOLBAR_SEARCH, this->getTopPanel(), -1)->setName(wxTr("Search toolbar"));
    CurrentApplication()->builElement( PELT_TYPE_TOOLS, this->getTopPanel(), -1)->setName(wxTr("Toolsbar"));

    CurrentApplication()->builElement( PELT_TYPE_TCALCULATOR, this->getRightPanel(), -1)->setName(wxTr("Calculator"));
    CurrentApplication()->builElement( PELT_TYPE_FILE_EXPLORER, this->getRightPanel(), -1)->setName(wxTr("Files explorer"));

    CurrentApplication()->builElement( PELT_TYPE_RENDERER, this->getBottomPanel(), -1)->setName(wxTr("Povray output"));
    CurrentApplication()->builElement( PELT_TYPE_HELP, this->getBottomPanel(), -1)->setName(wxTr("Help"));

#ifdef __WXMSW__
    wxString sInsertMenuPath = static_cast<XPE *>(CurrentApplication())->getPovrayInstallPath();
    if(sInsertMenuPath.length())
    {
        sInsertMenuPath += wxT("/Insert Menu/");
        if(libfile::isDirectory(sInsertMenuPath))
            this->setInsertMenuPath(sInsertMenuPath);
    }
#else
    wxString sInsertMenuPath = static_cast<XPE *>(CurrentApplication())->getInstallPrefix() + wxT("/share/xpe/Insert Menu/");
    if(!libfile::isDirectory(sInsertMenuPath))
        sInsertMenuPath = static_cast<XPE *>(CurrentApplication())->getInstallPrefix() + wxT("/share/xpe/Insert_Menu/");
    if(libfile::isDirectory(sInsertMenuPath))
        this->setInsertMenuPath(sInsertMenuPath);
#endif
}

#define XML_PARAM_NODE_INSERT_MENU "InsertMenu"
#define XML_PARAM_NODE_LASTFILES "LastOpenedFiles"
#define XML_PARAM_NODE_RECENTFILES "RecentFiles"
#define XML_PARAM_NODE_FILE "File"
#define XML_PARAM_ATTR_FILE_NAME "name"

/** charge les parametres du composant a partir des informations contenues dans le noeud passe en parametre */
bool XPEMainWindow::loadParameters(TiXmlElement * parametersNode)
{
    TMainWindow::loadParameters(parametersNode);

    TiXmlElement * elt = NULL;

    elt = parametersNode->FirstChildElement(XML_PARAM_NODE_RECENTFILES);
    if(elt)
    {
        // vidange
        while(this->filesHistory->GetCount())
            this->filesHistory->RemoveFileFromHistory(this->filesHistory->GetCount()-1);

        // on fait une lecture en ordre inverse pour gerer l'ordre de "recenti-isme"
        elt = dynamic_cast<TiXmlElement *>(elt->LastChild(XML_PARAM_NODE_FILE));
        while(elt)
        {
            const char * szName = elt->Attribute( XML_PARAM_ATTR_FILE_NAME );
            if(szName && szName[0])
            {
                this->filesHistory->AddFileToHistory(ISO2WX( szName ));
            }
            elt = dynamic_cast<TiXmlElement *>(elt->PreviousSibling(XML_PARAM_NODE_FILE));
        }
    }

    elt = parametersNode->FirstChildElement(XML_PARAM_NODE_LASTFILES);
    if(elt)
    {
        elt = elt->FirstChildElement(XML_PARAM_NODE_FILE);
        while(elt)
        {
            const char * szName = elt->Attribute( XML_PARAM_ATTR_FILE_NAME );
            if(szName && szName[0])
            {
                this->loadFile(ISO2WX( szName ));
            }
            elt = elt->NextSiblingElement(XML_PARAM_NODE_FILE);
        }
    }

    elt = parametersNode->FirstChildElement(XML_PARAM_NODE_INSERT_MENU);
    if(elt)
        this->setInsertMenuPath(ISO2WX(elt->GetText()));
    else
        this->updateInsertMenu();

    if(!this->getCenterPanel()->getElementsCount())
        this->createNewEditorTab(Povfile);

    return true;
}

/** renvoie les parametres du composant sous la forme d'un noeud xml */
TiXmlElement * XPEMainWindow::getParameters()
{
    TiXmlElement * root = TMainWindow::getParameters();

    TiXmlElement * lastsElt = new TiXmlElement(XML_PARAM_NODE_LASTFILES);
    for(int i = 0 ; i < this->getCenterPanel()->getElementsCount() ; i++)
    {
        FileViewerPanelElement * editor = dynamic_cast<FileViewerPanelElement *>(this->getCenterPanel()->getElementAt(i));
        if(editor && editor->getFilename().length())
        {
            TiXmlElement * elt = new TiXmlElement(XML_PARAM_NODE_FILE);
            elt->SetAttribute( XML_PARAM_ATTR_FILE_NAME, (const char *)editor->getFilename().fn_str() );
            lastsElt->LinkEndChild( elt );
        }
    }
    root->LinkEndChild( lastsElt );

    TiXmlElement * recentsElt = new TiXmlElement(XML_PARAM_NODE_RECENTFILES);
    for(size_t i = 0 ; i < this->filesHistory->GetCount() ; i++)
    {
        wxString sFilename = this->filesHistory->GetHistoryFile(i);
        if(sFilename.length())
        {
            TiXmlElement * elt = new TiXmlElement(XML_PARAM_NODE_FILE);
            elt->SetAttribute( XML_PARAM_ATTR_FILE_NAME, (const char *)sFilename.fn_str() );
            recentsElt->LinkEndChild( elt );
        }
    }
    root->LinkEndChild( recentsElt );

    TiXmlElement * insertElt = new TiXmlElement(XML_PARAM_NODE_INSERT_MENU);
    TiXmlText * insertPathElt = new TiXmlText((const char *)this->sInsertMenuPath.fn_str());
    insertPathElt->SetCDATA( true );
    insertElt->LinkEndChild( insertPathElt );
    root->LinkEndChild( insertElt );

    return root;
}

void XPEMainWindow::OnEditUndoRedo( wxCommandEvent& event )
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if((!elt) || (static_cast<EditorPanelElement *>(elt)->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    switch(event.GetId())
    {
        case Edit_Undo:
            static_cast<EditorPanelElement *>(elt)->getEditor()->undo();
            break;
        case Edit_Redo:
            static_cast<EditorPanelElement *>(elt)->getEditor()->redo();
            break;
        default:
            event.Skip();
            break;
    }
}

void XPEMainWindow::OnEditCutCopyPaste( wxCommandEvent& event )
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if((!elt) || (static_cast<EditorPanelElement *>(elt)->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    switch(event.GetId())
    {
        case Edit_Cut:
            static_cast<EditorPanelElement *>(elt)->getEditor()->clipboardCut();
            break;
        case Edit_Copy:
            static_cast<EditorPanelElement *>(elt)->getEditor()->clipboardCopy();
            break;
        case Edit_Paste:
            static_cast<EditorPanelElement *>(elt)->getEditor()->clipboardPaste();
            break;
        default:
            event.Skip();
            break;
    }
}

void XPEMainWindow::OnEditSelectAll( wxCommandEvent& event )
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if((!elt) || (static_cast<EditorPanelElement *>(elt)->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    TDocument * doc = static_cast<EditorPanelElement *>(elt)->getEditor()->getDocument();
    long iLine = doc->getLinesCount() - 1;
    long iCol = doc->getLine(iLine).length();
    static_cast<EditorPanelElement *>(elt)->getEditor()->setSelection(TPoint(0,0),TPoint(iCol,iLine));
}

void XPEMainWindow::OnEditJoinLines( wxCommandEvent& event )
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if((!elt) || (static_cast<EditorPanelElement *>(elt)->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    TDocument * doc = static_cast<EditorPanelElement *>(elt)->getEditor()->getDocument();
    TCursor * cursor = static_cast<EditorPanelElement *>(elt)->getEditor()->getCursor();
    long iLine = cursor->getLine();
    doc->removeCharAt(iLine, doc->getLineLength(iLine));
}

void XPEMainWindow::OnEditDeleteLine( wxCommandEvent& event )
{
    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if((!elt) || (static_cast<EditorPanelElement *>(elt)->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    TDocument * doc = static_cast<EditorPanelElement *>(elt)->getEditor()->getDocument();
    TCursor * cursor = static_cast<EditorPanelElement *>(elt)->getEditor()->getCursor();
    unsigned long iLine = cursor->getLine();
    TPoint debut(0,iLine);
    TPoint fin(0,iLine+1);
    if(iLine == (doc->getLinesCount() - 1)) // derniere ligne
    {
        if(iLine)  // dans el cas de la premiere et derniere ligne on ne touche aps le debut
            debut = TPoint( doc->getLineLength( iLine - 1) , iLine - 1);
        fin = TPoint(doc->getLineLength( iLine ), iLine);
    }
    doc->removeRange(debut,fin);
}

void XPEMainWindow::OnEditComment( wxCommandEvent& event )
{
    PovPanelElement * elt = dynamic_cast<PovPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if((!elt) || (elt->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    if(event.GetId() == Edit_CommentIn)
        elt->commentIn();
    else
        elt->commentOut();
}

void XPEMainWindow::OnEditGoToLine( wxCommandEvent& event )
{
    EditorPanelElement * elt = dynamic_cast<EditorPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if((!elt) || (static_cast<EditorPanelElement *>(elt)->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }
    TCodeEditor * editor = elt->getEditor();
    TDocument * doc = editor->getDocument();
    TCursor * cursor = editor->getCursor();
    long iLine = cursor->getLine()+1;

    iLine = wxGetNumberFromUser(wxTr("Go to line :"),wxT(""),wxTr("Got to line"), iLine, 1, doc->getLinesCount(), this);

    if(iLine > 0)
    {
        iLine--;
        cursor->setLine(iLine);
        cursor->setColumn(0);
    }
}

void XPEMainWindow::OnEditFind( wxCommandEvent& event )
{
    EditorPanelElement * elt = reinterpret_cast<EditorPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if((!elt) || (elt->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    if(!this->searchDlg)
    {
        this->searchDlg = new SearchDlg(this);
    }

    wxString sInitData(elt->getEditor()->getSelectedText());
    if(!sInitData.length())
        sInitData = this->sSearchPattern;

    if(this->searchDlg->show(sInitData))
    {
        this->bModeReplace = false;
        this->bCaseSensitive = this->searchDlg->isCaseSensitive();
        this->sSearchPattern = this->searchDlg->getSearchString();

        elt->getEditor()->SetFocus();

        if(this->sSearchPattern.length())
            this->findNextIn(elt->getEditor(), true);
    }
}

/** recherche la selection courrante */
void XPEMainWindow::OnEditFindSel( wxCommandEvent& event )
{
    EditorPanelElement * elt = reinterpret_cast<EditorPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if((!elt) || (elt->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    // quelle est la selection ?
    wxString sSel = elt->getEditor()->getSelectedText();
    if(!sSel.length())
    {
        // aucune selection ? on cherche le mot ou on est place
        TPoint pos = elt->getEditor()->getCursor()->getPosition();
        if(pos.isValid())
        {
            wxString sLine = elt->getEditor()->getDocument()->getLine(pos.y);
            // recherche du debut du mot
            uint iDeb = pos.x;
            for(iDeb = pos.x ; iDeb > 0 ; iDeb--)
            {
                wxChar c = sLine[iDeb];
                if(wxIsspace(c) || wxIspunct(c))
                {
                    iDeb++;
                    break;
                }
            }
            // recherche de la fin du mot
            uint iFin = pos.x;
            for(iFin = uint(pos.x) > iDeb ? pos.x : iDeb; iFin < sLine.length() ; iFin++)
            {
                wxChar c = sLine[iFin];
                if(wxIsspace(c) || wxIspunct(c))
                {
                    iFin--;
                    break;
                }
            }

            sSel = sLine.Mid(iDeb,iFin-iDeb+1);
        }
    }

    if(!sSel.length())
    {
        return;
    }

    this->bModeReplace = false;
    this->sSearchPattern = sSel;

    this->findNextIn(elt->getEditor(), true);
}

void XPEMainWindow::OnEditFindNext( wxCommandEvent& event )
{
    if(!this->sSearchPattern.length())
    {
        this->OnEditFind(event);
        return;
    }

    EditorPanelElement * elt = reinterpret_cast<EditorPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if((!elt) || (elt->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    this->bModeReplace = false;
    this->findNextIn(elt->getEditor(), true);
}

/**
 * recherche l'occurence suivante du texte recherche dans l'editeur fourni en parametre
 * @param bRollover peut relancer la recherche depuis le debut de l'editeur si aucune occurence n'est trouvee
 */
void XPEMainWindow::findNextIn( TCodeEditor * editor, bool bRollover )
{
    TDocument * doc = editor->getDocument();
    TCursor * cursor = editor->getCursor();
    TPoint searchPoint = cursor->getPosition();
    bool bContinue = true;
    bool bMightShowWarning = true;

    do
    {
        TPoint pt = doc->find(this->sSearchPattern,searchPoint,this->bCaseSensitive);

        if( pt.isValid() )
        {
            bMightShowWarning = false;
            bContinue = this->bModeReplace;
            TPoint ptEnd(pt.x + this->sSearchPattern.length(),pt.y);
            cursor->setPosition(ptEnd);
            editor->setSelection(pt, ptEnd);
            if(this->bModeReplace)
            {
                int iAnswer = (this->bReplaceAll) ? wxYES : wxMessageBox(wxTr("Replace this occurence ?"), wxTr("Replace"),
                                                                         wxYES_NO | wxCANCEL, this);

                if(iAnswer == wxCANCEL)
                {
                    bContinue = false;
                }
                else if(iAnswer == wxYES)
                {
                    editor->getDocument()->startComposedAction();
                    editor->eraseSelection();
                    editor->insert(this->sReplaceText.c_str());
                    editor->getDocument()->stopComposedAction();
                    searchPoint.x = pt.x + this->sReplaceText.length();
                    searchPoint.y = pt.y;
                }
                else // if(iAnswer == wxNO)
                {
                    searchPoint = ptEnd;
                }
            }
        }
        else
        {
            if(bRollover)
            {
                bRollover = false;
                searchPoint.x = 0;
                searchPoint.y = 0;
            }
            else
            {
                if(bMightShowWarning)
                    wxMessageBox(wxString::Format(wxTr("Unable to find %s"), this->sSearchPattern.c_str()),
                                 this->bModeReplace ? wxTr("Replace") : wxTr("Find"), wxOK|wxICON_INFORMATION, this);
                bContinue = false;
            }
        }
    }
    while (bContinue);
}

void XPEMainWindow::OnEditReplace( wxCommandEvent& event )
{
    EditorPanelElement * elt = reinterpret_cast<EditorPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if((!elt) || (elt->getEditor() != wxWindow::FindFocus()))
    {
        event.Skip();
        return;
    }

    if(!this->replaceDlg)
    {
        this->replaceDlg = new ReplaceDlg(this);
    }

    wxString sInitData(elt->getEditor()->getSelectedText());
    if(!sInitData.length())
        sInitData = this->sSearchPattern;

    if(this->replaceDlg->show(sInitData))
    {
        this->bModeReplace = true;
        this->bCaseSensitive = this->replaceDlg->isCaseSensitive();
        this->sSearchPattern = this->replaceDlg->getSearchString();
        this->sReplaceText = this->replaceDlg->getReplaceString();
        this->bReplaceAll = this->replaceDlg->getMightReplaceAll();

        elt->getEditor()->SetFocus();

        if(this->sSearchPattern.length())
        {
            if(this->bReplaceAll)
                elt->getEditor()->getDocument()->startComposedAction();

            this->findNextIn(elt->getEditor(), true);

            if(this->bReplaceAll)
                elt->getEditor()->getDocument()->stopComposedAction();
        }
    }
}

void XPEMainWindow::OnEditPreferences( wxCommandEvent& event )
{
    TConfigDlg * dlg = new TConfigDlg();
    dlg->addConfigElement( new MainWindowConfigPanelElement(this,dlg->getMainPanel()));
    dlg->addConfigElement( new KeywordsConfigPanelElement(dlg->getMainPanel()));
    dlg->addConfigElement( new EditorConfigPanelElement(dlg->getMainPanel()));
    dlg->addConfigElement( new RendererConfigPanelElement(dlg->getMainPanel()));
    dlg->addConfigElement( new PathsConfigPanelElement(dlg->getMainPanel()));
    dlg->addConfigElement( new MiscConfigPanelElement(this,dlg->getMainPanel()));
    dlg->ShowModal();
    dlg->destroyWindowContent();
    delete dlg;
}

/** indique que le mode de saisie a change */
void XPEMainWindow::typeModeChanged(TCodeEditor * ce)
{
    this->updateCursorStatusInfos();
}

/** indique le curseur s'est deplace */
void XPEMainWindow::cursorMoved(TCursor * cursor)
{
    this->updateCursorStatusInfos();
}

/** indique qu'un element devient visible / cache */
void XPEMainWindow::elementVisibilityChanged(TApplicationPanel * panel, TPanelElement * elt, bool bVisible)
{
    if(panel != this->getCenterPanel())
        return;
    this->updateCursorStatusInfos();

    if(bVisible)
    {
        PovPanelElement * povelt = dynamic_cast<PovPanelElement *>(elt);
        this->GetMenuBar()->FindItem(Edit_CommentIn)->Enable(povelt != NULL);
        this->GetMenuBar()->FindItem(Edit_CommentOut)->Enable(povelt != NULL);
    }
}

/** mets a jour les informations concernant le curseur dans la barre d'etat */
void XPEMainWindow::updateCursorStatusInfos()
{
    EditorPanelElement * elt = NULL;
    if(this->getCenterPanel())
        elt = dynamic_cast<EditorPanelElement *>(this->getCenterPanel()->getFirstVisibleElement());
    if(!elt || (this->getCenterPanel()->getVisibleElementsCount() != 1))
    {
        this->GetStatusBar()->SetStatusText( wxTr("Line : -----  Col : -----"), 1);
        this->GetStatusBar()->SetStatusText(wxTr("INS"), 2);
        return;
    }
    TCodeEditor * editor = elt->getEditor();
    TCursor * cursor = editor->getCursor();

    this->GetStatusBar()->SetStatusText( wxString::Format(wxTr("Line : %5d  Col : %5d"),cursor->getLine()+1,cursor->getColumn()+1) , 1);
    this->GetStatusBar()->SetStatusText(editor->getTypeMode() == TCodeEditor::Insert ? wxTr("INS") : wxTr("OWR"), 2);

}

/** defini le panneau central */
void XPEMainWindow::setCenterPanel(TApplicationPanel * panel, bool bDeleteOld)
{
    if(this->getCenterPanel())
        this->getCenterPanel()->removePanelListener(this);
    TMainWindow::setCenterPanel(panel,bDeleteOld);
    panel->addPanelListener(this);
}

/** cree une liste indexee des elements qu'il est possible de mettre dans la fenetre */
XPEMainWindow::TAvailableEltsList XPEMainWindow::createAvailableElementsInfoList() const
{
    TAvailableEltsList map;

    TPanelElementInfo info;

    info = ClockPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = CalculatorPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = DocumentsPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = FileExplorerPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = HelpPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = NavigatorPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = NotesPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = RendererPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = ToolsPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = ToolbarFilePanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = ToolbarEditPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = ToolbarEdit2PanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    info = ToolbarSearchPanelElement::getElementInfo();
    map.insert(TAvailableEltsList::value_type(info.getTypeName(), info));

    // a continuer avec d'autres types

    return map;
}

void XPEMainWindow::OnInsertReload( wxCommandEvent& event )
{
    this->updateInsertMenu();
}

/** declanche lors du click sur un element dynamique du menu d'insertion */
void XPEMainWindow::OnInsertEntry( wxCommandEvent& event )
{
    TIncludesMap::iterator it = this->includes.find(event.GetId());
    if(it == this->includes.end())
    {
        LOG_DEBUG("");
        return;
    }

    TPanelElement * elt = this->getCenterPanel()->getFirstVisibleElement();
    if(!elt)
        return;

    wxFFileInputStream is((*it).second);
    if(!is.Ok())
        return;

    unsigned char buffer[64536]; // 64K buffer
    buffer[64535] = 0;
    wxString sData;
    while(!is.Eof())
    {
        is.Read(buffer,64535);
        buffer[is.LastRead()] = 0;
        sData += ISO2WX((char *)buffer);
    }

    sData.Replace(wxT("\r"),wxT(""));

    static_cast<EditorPanelElement *>(elt)->getEditor()->eraseSelection(TCODEEDITOR_DEFAULT_SELECTION);
    static_cast<EditorPanelElement *>(elt)->getEditor()->insert(sData);
//    static_cast<EditorPanelElement *>(elt)->getEditor()->getDocument()->fireDocumentHeavilyModified(); // contournement de bug
}

/** mets a jour le contenu du menu d'insertion */
void XPEMainWindow::updateInsertMenu( )
{
    this->includes.erase(this->includes.begin(),this->includes.end());

    // nettoyage du menu
    while(this->menuInsert->GetMenuItemCount())
    {
        wxMenuItem * item = this->menuInsert->FindItemByPosition(0);
        this->menuInsert->Remove(item);
        delete item;
    }

    this->buildInsertMenu(this->menuInsert,this->sInsertMenuPath);

    this->menuInsert->AppendSeparator();
    this->menuInsert->Append( Insert_Reload, wxTr( "Reload ..." ), wxTr( "Reloads the insert menu") );
}

/** rempli l'objet menu passe en param a partir du repertoire dont le chemin est le 2nd param */
void XPEMainWindow::buildInsertMenu(wxMenu * menu, wxString sPath)
{
    if(!wxDir::Exists(sPath))
        return;

    wxArrayString files;
    wxArrayString dirs;

    libfile::TDirTraverser traverser(files,dirs);

    wxDir dir(sPath);
    dir.Traverse(traverser,wxEmptyString,wxDIR_FILES|wxDIR_DIRS);

    dirs.Sort();
    // gestion des sous-repertoires
    for(uint i = 0 ; i < dirs.Count() ; i++)
    {
        wxMenu * item = new wxMenu;

        this->buildInsertMenu(item,dirs[i]);

        wxString sMenuName = libfile::basename(dirs[i]);
        sMenuName.Replace(wxT("_"),wxT(" "));
        if(sMenuName.Find(wxT(" - ")) == 2)
            sMenuName = sMenuName.Mid(5);

        menu->Append( new wxMenuItem(menu, -1, sMenuName, wxT(""), wxITEM_NORMAL, item));
    }

    files.Sort();
    // gestion des fichiers
    for(uint i = 0 ; i < files.Count() ; i++)
    {
        if(files[i].Right(4).Upper() != wxT(".TXT"))
            continue;

        wxString sMenuName = libfile::basename(files[i]);
        sMenuName.Replace(wxT("_"),wxT(" "));
        if(sMenuName.Find(wxT(" - ")) == 2)
            sMenuName = sMenuName.Mid(5);

        sMenuName = sMenuName(0,sMenuName.length() - 4); // suppression de l'extension

        long iId = Insert_Custom + static_cast<XPE *>(CurrentApplication())->getUPEID();
        menu->Append( iId, sMenuName, wxT("") );
        this->Connect( iId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(XPEMainWindow::OnInsertEntry ), NULL, this );
        this->includes[iId] = files[i];
    }
}

/** defini le repertoire a utiliser pour le menu d'insertion */
void XPEMainWindow::setInsertMenuPath(const wxString & sPath)
{
    this->sInsertMenuPath = sPath;
    this->updateInsertMenu();
}

void XPEMainWindow::requestTabClose(FileViewerPanelElement * eltToClose)
{
    wxCommandEvent evt(EVENT_CLOSE_TAB);
    evt.SetEventObject(eltToClose);
    this->AddPendingEvent(evt);
}

/**
 * recherche l'existance d'une version plus récente sur le site web et affiche un avertissement si c'est le cas
 * @param bNoError ne pas afficher de messages d'erreur
 */
void XPEMainWindow::checkForUpdate(bool bNoError)
{
    wxString sTempFile = wxFileName::CreateTempFileName(wxT("xpe_update_check"));
    wxString sRessource(wxT(XPE_VERSION_FILE));

    if(!getHttpRessource(wxT(XPE_WEB_SERVER),sRessource,sTempFile))
    {
        if(!bNoError)
            wxMessageBox(wxTr("Unable to find ressource http://") + ISO2WX(XPE_WEB_SERVER) + sRessource, wxTr("Error"), wxICON_ERROR);
        return;
    }

    wxFFileInputStream stream(sTempFile);
    char szNewVersion[9];
    memset(szNewVersion,0,9);
    stream.Read(szNewVersion,8);
    libfile::remove(sTempFile);

    if(stream.LastRead() < 8)
    {
        if(!bNoError)
            wxMessageBox(wxTr("Incomplete ressource : http://") + ISO2WX(XPE_WEB_SERVER) + sRessource, wxTr("Error"), wxICON_ERROR);
        return;
    }

    if(atol(szNewVersion) > XPE_VERSION)
    {
        wxMessageBox(wxTr("A new version of XPE is available at http://") + ISO2WX(XPE_WEB_SERVER), wxTr("Information"), wxICON_INFORMATION);
    }
}

TApplicationPanel * getMainWindowCenterPanel()
{
    if(CurrentApplication()->getMainWindow())
        return CurrentApplication()->getMainWindow()->getCenterPanel();
    else
        return NULL;
}
