/***************************************************************************
 *   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 "explorer_panelelt.h"

#include <time.h>

#include "components/stdgui/tlistctrl.h"
#include <wx/filename.h>
#include <wx/dir.h>
#include <wx/arrstr.h>
#include <wx/mimetype.h>

#include "components/framework/tapplicationpanel.h"
#include "components/framework/tapplication.h"
#include "components/stdgui/tpanel.h"
#include "components/stdgui/tbitmap.h"

#include "lib/lib_string.h"
#include "lib/lib_logging.h"
#include "lib/lib_file.h"

#include "xpe_components/mainwindow.h"

#include "bmp_id.h"

#define IDX_FOLDER 0
#define IDX_BINARY 1
#define IDX_IMAGE 2
#define IDX_INI 3
#define IDX_POVRAY 4
#define IDX_TXT 5


int wxCALLBACK _FilesCompareFunction(long iItem1Data, long iItem2Data, long iSortData);

FileExplorerPanelElement::FileExplorerPanelElement(TApplicationPanel * _owner, int iID)
    : TPanelElement(_owner, iID, wxT(""), wxT("")),
    path(NULL),
    files(NULL),
    icons(16,16),
    iLastResizeTime(0),
    iResizeCount(0)
{
    this->setTooltip(wxTr("Files explorer"));
    this->setExtensivity(1);
    this->setBitmap(getDefaultIcon());

    this->icons.Add(*GET_BMP(BMP_FOLDER_ID));
    this->icons.Add(*GET_BMP(BMP_FILE_BINARY_ID));
    this->icons.Add(*GET_BMP(BMP_FILE_IMAGE_ID));
    this->icons.Add(*GET_BMP(BMP_FILE_INI_ID));
    this->icons.Add(*GET_BMP(BMP_FILE_POVRAY_ID));
    this->icons.Add(*GET_BMP(BMP_FILE_TXT_ID));
}

FileExplorerPanelElement::~FileExplorerPanelElement()
{
}

const TBitmap * FileExplorerPanelElement::getDefaultIcon()
{
    return GET_BMP(BMP_DOCUMENTS_ID);
}

/** construit le panneau conteneur et son contenu (appell� automatiquement par getContentPanel et d�truit automatiquement par le destructeur) */
TPanel * FileExplorerPanelElement::buildContentPanel()
{
    TPanel * contentPanel = new TPanel(this->getOwner()->getContentPanel());
    wxBoxSizer * sizer = new wxBoxSizer( wxVERTICAL);
    contentPanel->SetSizer(sizer);

    this->path = new wxTextCtrl(contentPanel, -1, wxT(""), wxDefaultPosition, wxDefaultSize,
                                wxTE_PROCESS_ENTER | wxTE_LEFT);
    sizer->Add(this->path,0,wxEXPAND);
    sizer->Show(this->path,true);

    this->files = new TListCtrl(contentPanel, -1, wxDefaultPosition, wxDefaultSize,
                                wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL | wxSUNKEN_BORDER );
    sizer->Add(this->files,1,wxEXPAND);
    sizer->Show(this->files,true);
    this->files->SetImageList(&this->icons,wxIMAGE_LIST_SMALL);

    // entetes des colonnes (cach�es)
    wxListItem itemCol;
    itemCol.SetText(wxT(" "));
    itemCol.SetImage(-1);
    this->files->InsertColumn(0, itemCol);
    this->files->InsertColumn(1, itemCol);

    this->path->Connect(wxEVT_COMMAND_TEXT_ENTER,wxCommandEventHandler(FileExplorerPanelElement::onNewPathEntered), NULL, this);
    this->files->Connect(wxEVT_SIZE,wxSizeEventHandler(FileExplorerPanelElement::onListViewSize), NULL, this);
    this->files->Connect(wxEVT_COMMAND_LIST_ITEM_ACTIVATED,wxCommandEventHandler(FileExplorerPanelElement::onListDblClick), NULL, this);

    this->displayDirectory(wxFileName::GetHomeDir());

    return contentPanel;
}

/**
 * mets a jour l'affichage avec le chemin pass� en param�tre
 * @param sPath chemin a afficher
 */
void FileExplorerPanelElement::displayDirectory(wxString sPath)
{
    if(!this->files)
        return;

    this->files->DeleteAllItems();
    this->datas.erase(this->datas.begin(), this->datas.end());

    wxFileName fn(sPath + wxT("/")); // contournement de bug de WX pour etre sur de virer tous les ".."
    fn.Normalize(wxPATH_NORM_DOTS, wxEmptyString, wxPATH_UNIX);
    sPath = fn.GetFullPath();
    this->sCurrentPath = libfile::normalize(sPath);
    if(this->sCurrentPath.GetChar(this->sCurrentPath.length()-1) != '/' )
        this->sCurrentPath += wxT("/");
    this->path->SetValue(this->sCurrentPath);

    wxArrayString dirsList;
    wxArrayString filesList;
    libfile::TDirTraverser traverser(filesList,dirsList);
    wxDir dir(this->sCurrentPath);
    dir.Traverse(traverser);

    // r�pertoire parent
    TStringList::iterator it = this->datas.insert(this->datas.end(),wxT(".."));
    long iItemId = this->files->InsertItem(0,wxT(".."));
    this->files->SetItemData(iItemId,(long int)(&(*it)));
    this->files->SetItemImage(iItemId,IDX_FOLDER);

    for( uint i = 0 ; i < dirsList.GetCount() ; i++)
    {
        wxString s = libfile::basename(dirsList[i]);
        if(s.GetChar(0) == '.')
            continue;
        TStringList::iterator it = this->datas.insert(this->datas.end(),s);
        iItemId = this->files->InsertItem(i+1,s);
        this->files->SetItemData(iItemId,(long int)(&(*it)));
        this->files->SetItemImage(iItemId,IDX_FOLDER);
    }

    for( uint i = 0 ; i < filesList.GetCount() ; i++)
    {
        wxString s = libfile::basename(filesList[i]);
        if(s.GetChar(0) == '.')
            continue;
        TStringList::iterator it = this->datas.insert(this->datas.end(),s);
        iItemId = this->files->InsertItem(i+1,s);
        this->files->SetItemData(iItemId,(long int)(&(*it)));
        int iIconIdx = -1;
        wxString sExt = libfile::extension(s).MakeLower();
        if(sExt == wxT("pov"))
            iIconIdx = IDX_POVRAY;
        else if(sExt == wxT("ini"))
            iIconIdx = IDX_INI;
        else
        {
            wxFileType * ft = CurrentApplication()->getMimeTypesManager().GetFileTypeFromExtension(sExt);
            if(ft)
            {
                wxString sMimeType;
                if(ft->GetMimeType(&sMimeType))
                {
                    if(sMimeType.StartsWith(wxT("image/")))
                        iIconIdx = IDX_IMAGE;
                }
            }

            if(iIconIdx < 0)
            {
                if(libfile::isBinary(filesList[i]))
                    iIconIdx = IDX_BINARY;
                else
                    iIconIdx = IDX_TXT;
            }
        }
        this->files->SetItemImage(iItemId,iIconIdx);
    }

    this->files->SortItems(&_FilesCompareFunction,(long int)(&this->sCurrentPath));

}

void FileExplorerPanelElement::onNewPathEntered(wxCommandEvent & event)
{
    if(wxFileName::DirExists(this->path->GetValue()))
        this->displayDirectory(this->path->GetValue());
}


void FileExplorerPanelElement::onListViewSize(wxSizeEvent & evt)
{
    long iCurrentTime = time(NULL);
    if(iLastResizeTime == iCurrentTime) // limite a 5 resize / seconde pour contourner un bug windows
    {
        if(iResizeCount > 5)
            return;
    }
    else
        iResizeCount = 0;
    iLastResizeTime = iCurrentTime;
    iResizeCount++;
    evt.Skip();
    this->files->SetColumnWidth( 0, 20 );
    if(this->files && this->files->GetClientSize().GetWidth() > 25)
    {
        this->files->SetColumnWidth( 0, this->files->GetClientSize().GetWidth() - 22 - 2 );
    }
}

void FileExplorerPanelElement::onListDblClick(wxCommandEvent & event)
{
    if(!this->files)
        return;

    for(int iItemId = 0 ; iItemId < this->files->GetItemCount() ; iItemId++)
    {
        if(this->files->GetItemState(iItemId,wxLIST_STATE_SELECTED))
        {
            wxString sFile(this->sCurrentPath + (*reinterpret_cast<wxString *>( this->files->GetItemData(iItemId) )));
            if(wxFileName::DirExists(sFile))
            {
                this->displayDirectory(sFile);
            }
            else
            {
                bool bOpenInternaly = true;
                wxString sMimeType;
                wxString sExt = libfile::extension(sFile).MakeLower();
                wxFileType * ft = CurrentApplication()->getMimeTypesManager().GetFileTypeFromExtension(sExt);
                if(ft)
                {
                    if(ft->GetMimeType(&sMimeType))
                    {
                        if(sMimeType.StartsWith(wxT("application/")))
                            bOpenInternaly = false;
                    }
                    else
                        sMimeType = sExt;
                }
                if((!bOpenInternaly) || (!static_cast<XPEMainWindow*>(CurrentApplication()->getMainWindow())->loadFile(sFile)))
                {
                    if(ft)
                    {
                        wxString sCmd = ft->GetOpenCommand(sFile);
                        if(sCmd.length())
                        {
                            system((const char *)(sCmd + wxT(" &")).fn_str());
                        }
                        else
                            wxMessageBox(wxString::Format(wxTr("No application found to open  %s files"),sMimeType.c_str()),wxTr("Error"),wxOK|wxICON_EXCLAMATION);
                    }
                    else
                        wxMessageBox(wxString::Format(wxTr("Unknown file type. Unable to open %s"),sFile.c_str()),wxTr("Error"),wxOK|wxICON_EXCLAMATION);
                }
            }
            break;
        }
    }
}


int wxCALLBACK _FilesCompareFunction(long iItem1Data, long iItem2Data, long iSortData)
{
    wxString sPath(*reinterpret_cast<wxString *>( iSortData ));
    wxString sFile1(*reinterpret_cast<wxString *>( iItem1Data ));
    wxString sFile2(*reinterpret_cast<wxString *>( iItem2Data ));

    bool bFile1IsDir = wxFileName::DirExists(sPath + sFile1);
    bool bFile2IsDir = wxFileName::DirExists(sPath + sFile2);

    if(bFile1IsDir && (!bFile2IsDir))
        return -1;

    if((!bFile1IsDir) && bFile2IsDir)
        return 1;

    return sFile1.CmpNoCase(sFile2);
}
