/**********************************************************************

  Audacity: A Digital Audio Editor

  UploadDialog.cpp

  Mike Underwood - munderwood@bedheaddesign.com

  Much like the author, this code is crazy at times but it gets the job
  done.

*******************************************************************//**

\class UploadDialog
\brief A contributed class for uploading audio via FTP.

*//*******************************************************************/

#include "Audacity.h"

#include <fstream>
#include <math.h>
#include <wx/dialog.h>
#include <wx/html/htmlwin.h>
#include <wx/button.h>
#include <wx/dcclient.h>
#include <wx/gdicmn.h>
#include <wx/imaglist.h>
#include <wx/sizer.h>
#include <wx/statbmp.h>
#include <wx/statusbr.h>
#include <wx/string.h>
#include <wx/intl.h>
#include <wx/wfstream.h>
#include <wx/listctrl.h>
#include <wx/checkbox.h>
#include <wx/progdlg.h>
#include <wx/menuitem.h>
#include <wx/utils.h>
#include <wx/dir.h>
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include "UploadDialog.h"
#include "PlatformCompatibility.h"
#include "FileNames.h"
#include "Theme.h"
#include "AllThemeResources.h"
#include "Project.h"

#include "FileDialog.h"

//#include "../images/AudacityLogo.xpm"
//#include "../images/UploadImages.h"

#ifdef __WXMSW__
# define DLOG_HEIGHT 430
#else
# if defined(__WXMAC__) && ((wxMAJOR_VERSION == 2) && (wxMINOR_VERSION >= 5))
#  define DLOG_HEIGHT 430
# else
#  define DLOG_HEIGHT 400
# endif
#endif

// Icon images

///\todo get these XPMs out of here and into Theme.

// ----------------------------------------------------------------------------
// icons
// ----------------------------------------------------------------------------
BEGIN_EVENT_TABLE(UploadDialog, wxDialog)
   EVT_MENU(wxID_POPUP_DOWNLOAD, UploadDialog::OnPopupMenu)
   EVT_MENU(wxID_POPUP_DELETE, UploadDialog::OnPopupMenu)
   EVT_MENU(wxID_POPUP_RENAME, UploadDialog::OnPopupMenu)

   EVT_BUTTON(wxID_UPLOAD_FILE, UploadDialog::OnUploadFile)
   EVT_BUTTON(wxID_UPLOAD_DIR, UploadDialog::OnUploadDir)
   EVT_BUTTON(wxID_CREATEDIR, UploadDialog::OnCreateDir)
   EVT_BUTTON(wxID_CANCEL, UploadDialog::OnCancel)
   EVT_BUTTON(wxID_CONNECT, UploadDialog::OnConnect)
   EVT_BUTTON(wxID_DISCONNECT, UploadDialog::OnDisconnect)

   EVT_LIST_ITEM_ACTIVATED(wxID_FILEMANAGER, UploadDialog::OnActivateItem)
   EVT_LIST_ITEM_ACTIVATED(wxID_SITELIST, UploadDialog::OnActivateSite)
   EVT_LIST_ITEM_SELECTED(wxID_SITELIST, UploadDialog::OnSelectSite)
   EVT_LIST_ITEM_RIGHT_CLICK(wxID_FILEMANAGER, UploadDialog::OnListRightClick)

   EVT_BUTTON(wxID_DELSITE, UploadDialog::OnDeleteSite)
END_EVENT_TABLE()

IMPLEMENT_CLASS(UploadDialog, wxDialog)

UploadDialog::UploadDialog(wxWindow * parent)
:  wxDialog(parent, -1, wxT("Audacity FTP"),
         wxDefaultPosition, wxSize(640, 480), wxDEFAULT_DIALOG_STYLE | wxWANTS_CHARS)
{
    ftp = NULL;
    dirnameList = new wxArrayString();
    dirpermList = new wxArrayString();
    dirsizeList = new wxArrayString();
    filenameList = new wxArrayString();
    filepermList = new wxArrayString();
    filesizeList = new wxArrayString();
    displayNames = new wxArrayString();
    displayPerm  = new wxArrayString();
    displaySizes  = new wxArrayString();
    ftpList = new wxArrayString();

    icons = new wxImageList(16, 16, false, 2);
    wxIcon *folderIcon = new wxIcon;
    folderIcon->CopyFromBitmap(theTheme.Bitmap( bmpUploadFolder));
    wxIcon *fileIcon = new wxIcon;
    fileIcon->CopyFromBitmap(theTheme.Bitmap( bmpUploadFile));
    wxIcon *mp3Icon = new wxIcon;
    mp3Icon->CopyFromBitmap(theTheme.Bitmap( bmpUploadMp3));
    wxIcon *upIcon = new wxIcon;
    upIcon->CopyFromBitmap(theTheme.Bitmap( bmpUploadUp));
    icons->Add(*folderIcon);
    icons->Add(*fileIcon);
    icons->Add(*mp3Icon);
    icons->Add(*upIcon);
    
    wxFlexGridSizer *topSizer = new wxFlexGridSizer(2, 1);  
    wxStaticBoxSizer *connectionBox = new wxStaticBoxSizer(new wxStaticBox(this, -1, wxT("FTP Connection"), wxDefaultPosition, wxDefaultSize, 0, wxT("")), wxVERTICAL);   
    wxStaticBoxSizer *fileBox = new wxStaticBoxSizer(new wxStaticBox(this, -1, wxT("File Manager"), wxDefaultPosition, wxDefaultSize, 0, wxT("")), wxVERTICAL);
    wxStaticBoxSizer *siteBox = new wxStaticBoxSizer(new wxStaticBox(this, -1, wxT("Site Manager"), wxDefaultPosition, wxDefaultSize, 0, wxT("")), wxVERTICAL);

    wxFlexGridSizer *connectionSizer = new wxFlexGridSizer(2, 4);
    wxBoxSizer *leftSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *rightSizer = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer *fileButtonSizer = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer *siteButtonSizer = new wxBoxSizer(wxHORIZONTAL);
    
    wxStdDialogButtonSizer *stdButtonSizer = new wxStdDialogButtonSizer();

    txtFtpName = new wxTextCtrl(this, wxID_FTPNAME, wxT(""), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, wxT(""));
    txtFtpHost = new wxTextCtrl(this, wxID_FTPHOST, wxT(""), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, wxT(""));
    txtFtpUser = new wxTextCtrl(this, wxID_FTPUSER, wxT(""), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator, wxT(""));
    txtFtpPass = new wxTextCtrl(this, wxID_FTPPASS, wxT(""), wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD, wxDefaultValidator, wxT(""));
    btnConnect = new wxButton(this, wxID_CONNECT, wxT("&Connect"), wxDefaultPosition, wxDefaultSize);
    btnDisconnect = new wxButton(this, wxID_DISCONNECT, wxT("&Disconnect"), wxDefaultPosition, wxDefaultSize);
    btnDisconnect->Enable(false);

    btnUploadFile = new wxButton(this, wxID_UPLOAD_FILE, wxT("Upload &File"), wxDefaultPosition, wxDefaultSize);
    btnUploadFile->Enable(false);
    btnUploadDir = new wxButton(this, wxID_UPLOAD_DIR, wxT("Upload F&older"), wxDefaultPosition, wxDefaultSize);
    btnUploadDir->Enable(false);
    btnCreateDir = new wxButton(this, wxID_CREATEDIR, wxT("N&ew Folder"), wxDefaultPosition, wxDefaultSize);
    btnCreateDir->Enable(false);

    btnDelSite = new wxButton(this, wxID_DELSITE, wxT("&Remove Site"), wxDefaultPosition, wxDefaultSize);

    fileManager = new wxListView(this, wxID_FILEMANAGER, wxDefaultPosition, wxSize(350, 350), wxLC_REPORT, wxDefaultValidator, wxT(""));
    fileManager->AssignImageList(icons, wxIMAGE_LIST_SMALL);
    //fileManager->Show(false);
    fileManager->InsertColumn(0, wxT("Name"));
    fileManager->InsertColumn(1, wxT("Size (bytes)"));
    fileManager->InsertColumn(2, wxT("Permissions"));

    siteList = new wxListView(this, wxID_SITELIST, wxDefaultPosition, wxSize(200, 215), wxLC_REPORT | wxLC_NO_HEADER, wxDefaultValidator, wxT(""));
    siteList->InsertColumn(0, wxT(""));

    connectionSizer->Add(new wxStaticText(this, -1, wxT("Name:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT, wxT("")));
    connectionSizer->Add(txtFtpName);
    connectionSizer->Add(new wxStaticText(this, -1, wxT("Host:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT, wxT("")));
    connectionSizer->Add(txtFtpHost);
    connectionSizer->Add(new wxStaticText(this, -1, wxT("Username:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT, wxT("")));
    connectionSizer->Add(txtFtpUser);
    connectionSizer->Add(new wxStaticText(this, -1, wxT("Password:"), wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT, wxT("")));
    connectionSizer->Add(txtFtpPass);
    connectionSizer->Add(btnConnect, 0, wxALIGN_LEFT | wxALL, 5);
    connectionSizer->Add(btnDisconnect, 0, wxALIGN_LEFT | wxALL, 5);

    connectionBox->Add(connectionSizer, 0, wxALIGN_CENTER);
    connectionBox->Add(200, 0);

    stdButtonSizer->AddButton(new wxButton(this, wxID_CANCEL, _("&Cancel")));
    stdButtonSizer->Realize();

    fileButtonSizer->Add(btnUploadFile, 0, wxALL, 5);
    fileButtonSizer->Add(btnUploadDir, 0, wxALL, 5);
    fileButtonSizer->Add(btnCreateDir, 0, wxALL, 5);

    //siteButtonSizer->Add(btnNewSite, 0, wxALL, 5);
    siteButtonSizer->Add(btnDelSite, 0, wxALL, 5);

    fileBox->Add(fileManager, 0, wxALIGN_CENTER);
    fileBox->Add(fileButtonSizer, 0, wxALIGN_CENTER);
    //fileBox->Add(300, 0);

    siteBox->Add(siteList, 0, wxALIGN_CENTER);
    siteBox->Add(siteButtonSizer, 0, wxALIGN_LEFT);

    leftSizer->Add(connectionBox);
    leftSizer->Add(siteBox, 0, wxTOP, 10);
    rightSizer->Add(fileBox);
    rightSizer->Add(stdButtonSizer, 0, wxALIGN_RIGHT | wxALIGN_BOTTOM | wxALL, 5 );

    topSizer->Add(leftSizer, 0, wxALL, 10);
    topSizer->Add(rightSizer, 0, wxTOP | wxBOTTOM | wxRIGHT, 10);

    SetSizerAndFit(topSizer);

    // populate siteList
    UpdateSiteList();

}

UploadDialog::~UploadDialog()
{
    
}

void UploadDialog::OnCancel(wxCommandEvent & event)
{
   if (ftp)
      OnDisconnect(event);

   EndModal(0);
}

void UploadDialog::OnConnect(wxCommandEvent & WXUNUSED(event))
{

    wxString system;

    SetTitle(wxT("Connecting..."));
    SetCursor(wxCURSOR_WAIT);

    //int connectionExists = -1;

    ftp = new wxFTP();
    ftp->SetUser(txtFtpUser->GetValue());
    ftp->SetPassword(txtFtpPass->GetValue());
    
    if (ftp->Connect(txtFtpHost->GetValue()))
    {

        // check which system ftp is running on
        ftp->SendCommand(wxT("SYST"));
        system = ftp->GetLastResult();
        system = system.Lower();

        //wxMessageBox(system, wxT("FTP Status"), wxOK | wxICON_INFORMATION, this);

        if (system.Find(wxT("unix"))==-1 && system.Find(wxT("windows"))==-1)
        {
            wxString msg;
            msg.Printf(wxT("Unknown FTP Server type: %s\n\nOnly Unix based and Windows systems are supported/tested at this time."), (const wxChar*)system);
            wxMessageBox(msg, wxT("Error"), wxOK | wxICON_INFORMATION, this);
        }

        btnConnect->Enable(false);
        btnDisconnect->Enable(true);
        btnUploadFile->Enable(true);
        btnUploadDir->Enable(true);
        btnCreateDir->Enable(true);
        btnDelSite->Enable(false);

        fileManager->Show(true);
        siteList->Show(false);

        txtFtpName->Enable(false);
        txtFtpHost->Enable(false);
        txtFtpUser->Enable(false);
        txtFtpPass->Enable(false);

        if (txtFtpName->GetValue().Trim() == wxT(""))
            txtFtpName->SetValue(wxT("New Site"));

        // save login into to connections file
        if (SaveFtpSite(txtFtpName->GetValue(), txtFtpHost->GetValue(), txtFtpUser->GetValue(), txtFtpPass->GetValue()))
        {
            // add site to site list
            long tmp = siteList->InsertItem(siteList->GetItemCount(), txtFtpName->GetValue(), 0);
            siteList->SetItemData(tmp, 0);
        }

        SetTitle(wxT("Connected to: ") + txtFtpHost->GetValue());
    
        RefreshFiles();
        
    }

    else
    {
        wxMessageBox(wxT("Connection cannot be established"), wxT("FTP Status"), wxOK | wxICON_INFORMATION, this);
      delete ftp;
      ftp = NULL;
    }

    SetCursor(wxCURSOR_ARROW);

}

void UploadDialog::OnDisconnect(wxCommandEvent & WXUNUSED(event))
{

   delete ftp;
   ftp = NULL;


    btnDisconnect->Enable(false);
    btnConnect->Enable(true);
    btnUploadFile->Enable(false);
    btnUploadDir->Enable(false);
    btnCreateDir->Enable(false);
    btnDelSite->Enable(true);

    fileManager->Show(false);
    fileManager->DeleteAllItems();
    siteList->Show(true);

    txtFtpName->Enable(true);
    txtFtpHost->Enable(true);
    txtFtpUser->Enable(true);
    txtFtpPass->Enable(true);

    SetTitle(wxT("No Connection"));
    fileManager->Show(false);

    LoadFtpSiteList();
}


void UploadDialog::OnUploadFile(wxCommandEvent & WXUNUSED(event))
{
    unsigned int count;
    wxString name;
    wxString path;
    wxArrayString files;

    abort = false;

    FileDialog open(this, wxT("Choose file(s) to upload"),
                    ::wxGetCwd(), wxT(""),
                    wxT("All files (*.*)|*.*"),
                    wxFD_OPEN | wxFD_MULTIPLE | wxRESIZE_BORDER); 
    
    if (open.ShowModal()==wxID_OK)
    {
        SetCursor(wxCURSOR_WAIT);

        // get the file(s) the user selected
        open.GetPaths(files);

        for (count = 0; count < files.GetCount(); count++)
        {   
            if (!abort)
            {
                // remove path from filename
                int index = files.Item(count).Find(wxT('\\'), true);
                wxString name = files.Item(count).Mid(index+1, files.Item(count).Length() - index);
                wxString path = ftp->Pwd()+wxT("/")+name.MakeLower();
            

                // upload the file
                UploadFile(files.Item(count), path.MakeLower());
            }
        }

        RefreshFiles();

        SetCursor(wxCURSOR_ARROW);

    }
}

void UploadDialog::OnUploadDir(wxCommandEvent & WXUNUSED(event))
{

    wxDirDialog open(this, wxT("Choose folder to upload"), wxT("")); 
    int result = open.ShowModal();

    abort = false;

    if (result ==  wxID_OK)
    {
        SetCursor(wxCURSOR_WAIT);
        UploadDir(open.GetPath(), wxT(""));
        SetCursor(wxCURSOR_ARROW);
    }
}

void UploadDialog::OnListRightClick(wxListEvent &event)
{
    
    listIndex = event.m_itemIndex;

    wxMenu *menu = new wxMenu();
    wxMenuItem *del = new wxMenuItem(menu, wxID_POPUP_DELETE, wxT("Delete"), wxT("Delete file(s) from server"));
    wxMenuItem *rn  = new wxMenuItem(menu, wxID_POPUP_RENAME, wxT("Rename"), wxT("Rename file"));
    wxMenuItem *dl  = new wxMenuItem(menu, wxID_POPUP_DOWNLOAD, wxT("Download"), wxT("Download this file(s) to your computer"));

    wxMenuItem *sep  = new wxMenuItem(menu, -1, wxT(""), wxT(""));

    menu->Insert(0, dl);
    menu->Insert(1, sep);
    menu->Insert(2, del);
    menu->Insert(3, rn);

    fileManager->GetItemPosition(event.m_itemIndex ,mousePos);
    PopupMenu(menu, mousePos.x + 250, mousePos.y + 50);
}

void UploadDialog::OnActivateSite (wxListEvent &event)
{



}

void UploadDialog::OnPopupMenu (wxCommandEvent & event)
{

    if (event.GetId() == wxID_POPUP_DOWNLOAD)
    {
        abort = false;

        if (fileManager->GetSelectedItemCount() > 1)
        {
            SetCursor(wxCURSOR_WAIT);
            DownloadMultipleItems();
            SetCursor(wxCURSOR_ARROW);
        }

        else
        {
            SetCursor(wxCURSOR_WAIT);
            wxString item = fileManager->GetItemText(listIndex);

            if (displayPerm->Item(listIndex).GetChar(0)=='d')
                DownloadItem(item, true);    
            else
                DownloadItem(item, false);
            
            SetCursor(wxCURSOR_ARROW);
        }
    }

    if (event.GetId() == wxID_POPUP_DELETE)
    {
        

        if (fileManager->GetSelectedItemCount() > 1)
        {

            int result = wxMessageBox(wxT("Delete selected items?"), wxT("Confirm"), wxYES_NO, NULL);

            if (result == wxYES)
            {
                SetCursor(wxCURSOR_WAIT);

                long item = -1;
                wxArrayString *selectList = new wxArrayString();
                wxArrayString *selectPerm = new wxArrayString();

                item = fileManager->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                while (item != -1)
                {
                    // add selected item to list
                    selectList->Add(displayNames->Item(item));
                    selectPerm->Add(displayPerm->Item(item));

                    // get next item
                    item = fileManager->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
                }

                unsigned int count;
                for (count = 0; count < selectList->GetCount(); count++)
                {
                    if (selectList->Item(count) != wxT(".."))
                    {
                        // if directory
                        if (selectPerm->Item(count).GetChar(0) == wxT('d'))
                        {
                            mProgress = new ProgressDialog(wxT("Deleting..."), wxT(""));

                            deleteFileList = new wxArrayString();
                            deleteDirList = new wxArrayString();

                            GetDeleteList(selectList->Item(count));
                            RemoveItems(deleteFileList, deleteDirList);

                            deleteFileList->Clear();
                            deleteDirList->Clear();

                            delete mProgress;
                        }

                        else
                            ftp->RmFile(selectList->Item(count));
                                                    
                    }
                }

                selectList->Clear();
                selectPerm->Clear();

                SetCursor(wxCURSOR_ARROW);
            }

            RefreshFiles();
        }
        

        else
        {

            wxString confirm;
            confirm.Printf(wxT("Delete %s?"),
                           displayNames->Item(listIndex).c_str());
            
            int result = wxMessageBox(confirm, wxT("Confirm"), wxYES_NO, NULL);

            if (result == wxYES)
            {
                SetCursor(wxCURSOR_WAIT);

                    // if directory
                    if (displayPerm->Item(listIndex).GetChar(0) == 'd')
                    {
                        // create progress bar
                        mProgress = new ProgressDialog(wxT("Delete"), wxT(""));

                        deleteFileList = new wxArrayString();
                        deleteDirList = new wxArrayString();    

                        GetDeleteList(displayNames->Item(listIndex));
                        RemoveItems(deleteFileList, deleteDirList);

                        deleteFileList->Clear();
                        deleteDirList->Clear();

                        delete mProgress;
                    }
                    else
                    {
                        //DeleteItem(displayNames->Item(listIndex), false);
                        ftp->RmFile(displayNames->Item(listIndex));
                    }
                SetCursor(wxCURSOR_ARROW);
            }

            RefreshFiles();
    
        }
    }

    if (event.GetId() == wxID_POPUP_RENAME)
    {
        wxString result = wxGetTextFromUser(wxT("Please enter the new file/folder name:"), wxT("Rename"), fileManager->GetItemText(listIndex), this);

        if (result != wxT(""))
        {
            result.Replace(wxT(" "), wxT("_"), true);

            if (ftp->Rename(fileManager->GetItemText(listIndex).MakeLower(), result))
                RefreshFiles();
            else
                wxMessageBox(wxT("Error renaming file, check permissions."), wxT("FTP Status"), wxOK, NULL);
        }
    }

}

void UploadDialog::GetDeleteList (wxString src)
{
    unsigned int count;
    
        ftp->ChDir(src);
        GetDirContents();
        
        for (count = 0; count < displayNames->GetCount(); count++)
        {
            if (displayPerm->Item(count).GetChar(0) == wxT('d'))
            {
                GetDeleteList(displayNames->Item(count));
            }
            else
            {
                if (displayNames->Item(count) != wxT(".."))
                {
                    deleteFileList->Add(ftp->Pwd()+wxT("/")+displayNames->Item(count));
                }
            }

            mProgress->Update(count, (int)displayNames->GetCount(), wxT("Preparing to delete"));
        }

        deleteDirList->Add(ftp->Pwd());

        ftp->ChDir(wxT(".."));
        GetDirContents();

}

void UploadDialog::RemoveItems(wxArrayString *files, wxArrayString *dirs)
{
    unsigned int count;

    for (count = 0; count < files->GetCount(); count++)
    {
        ftp->RmFile(files->Item(count));
        
        mProgress->Update(count, (int)files->GetCount(), wxT("Deleting files"));
    }
    
    for (count = 0; count < dirs->GetCount(); count++)
    {
        ftp->RmDir(dirs->Item(count));

        mProgress->Update(count, (int)dirs->GetCount(), wxT("Deleting directories"));
    }

}

void UploadDialog::GetDirContents (void)
{
    unsigned int count;
    wxString filename;
    wxString buf;
    wxString size;

    wxArrayString *rawList = new wxArrayString();

    dirnameList->Empty();
    dirpermList->Empty();
    dirsizeList->Empty();
    filenameList->Empty();
    filepermList->Empty();
    filesizeList->Empty();
    displayNames->Empty();
    displayPerm->Empty();
    displaySizes->Empty();

    if (ftp->GetDirList(*rawList))
    {   
        
        // get Directory list
        for (count = 0; count < rawList->GetCount(); count++)
        {                   

            filename = rawList->Item(count);

            wxArrayString *info = new wxArrayString();
            ExtractListData(filename, info);    
    
            if (info->Item(3) == wxT("yes")) 
            {
                dirnameList->Add(info->Item(0));
                dirpermList->Add(info->Item(1));
                dirsizeList->Add(info->Item(2));
            }
                
        }

        // get File list    
        for (count = 0; count < rawList->GetCount(); count++)
        {                   

            filename = rawList->Item(count);

            wxArrayString *info = new wxArrayString();
            ExtractListData(filename, info);
            
            if (info->Item(3) == wxT("no"))  
            {
                filenameList->Add(info->Item(0));
                filepermList->Add(info->Item(1));
                filesizeList->Add(info->Item(2));
            }
            
        }

        dirnameList->Insert(wxT(".."), 0);
        dirpermList->Insert(wxT("up"), 0);
        dirsizeList->Insert(wxT("-"), 0);


        // add directories and files
        for (count = 0; count < dirnameList->GetCount(); count++)   
        {
            displayNames->Add(dirnameList->Item(count));
            displayPerm->Add(dirpermList->Item(count));
            displaySizes->Add(dirsizeList->Item(count));
        }

        for (count = 0; count < filenameList->GetCount(); count++)  
        {
            if (!filenameList->Item(count).IsNumber())
            {
                displayNames->Add(filenameList->Item(count));
                displayPerm->Add(filepermList->Item(count));
                displaySizes->Add(filesizeList->Item(count));
            }
        }
    }
    else
        wxMessageBox(wxT("Unable to retrieve directory contents."), wxT("FTP Status"), wxOK | wxICON_INFORMATION, this);


}

void UploadDialog::OnActivateItem (wxListEvent &event)
{

if (ftp->ChDir(displayNames->Item(event.m_itemIndex)))
{
    RefreshFiles();
}



}

void UploadDialog::RefreshFiles(void)
{
    unsigned int count;
    long tmp;

    // get directory listing and save it
    GetDirContents();
    
    // clear filemanager
    fileManager->DeleteAllItems();

        for (count = 0; count < displayNames->GetCount(); count++)
        {
            if (displayPerm->Item(count)[0] == wxT('d') || displayNames->Item(count) == wxT(".."))
            {
                if (displayNames->Item(count) == wxT(".."))
                    tmp = fileManager->InsertItem(count, displayNames->Item(count), 3);
                else
                    tmp = fileManager->InsertItem(count, displayNames->Item(count), 0);

            }
            else
            {
                if (displayNames->Item(count).Mid(displayNames->Item(count).Length()-4, 4) == wxT(".mp3"))
                    tmp = fileManager->InsertItem(count, displayNames->Item(count), 2);
                else
                    tmp = fileManager->InsertItem(count, displayNames->Item(count), 1);
            
            }

            fileManager->SetItemData(tmp, count);

            // filesize
            if (displayPerm->Item(count)[0] == wxT('d') || displayNames->Item(count) == wxT(".."))
                fileManager->SetItem(count, 1, wxT("-"));
            else
                fileManager->SetItem(count, 1, displaySizes->Item(count));

            // file permissions
            fileManager->SetItem(count, 2, displayPerm->Item(count));
        }

        // show
        fileManager->Show(true);
    


}


// This function extracts the data from a ftp list string
void UploadDialog::ExtractListData (wxString string, wxArrayString *results)
{
    int index;
    wxString permissions;
    wxString name;
    wxString size;
    wxString isDir = wxT("no");

    // trim string
    string.Trim();

    
    // extract data left to right

    // extract permissions
    index = string.Find(' ');
    permissions = string.Mid(0, index);
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);
    
    // junk it
    index = string.Find(' ');
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // junk it
    index = string.Find(' ');
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // junk it
    index = string.Find(' ');
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // extract filesize
    index = string.Find(' ');
    size = string.Mid(0, index);
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // junk it
    index = string.Find(' ');
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // junk it
    index = string.Find(' ');
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // junk it
    index = string.Find(' ');
    string = string.Mid(index+1, string.Length());      
    string.Trim(false);

    // extract filename
    name = string.Mid(0, string.Length());
    string.Trim();
    string.Trim(false);

    if (permissions[0] == wxT('d'))
        isDir = wxT("yes");
    else
        isDir = wxT("no");

    results->Add(name);
    results->Add(permissions);
    results->Add(size);
    results->Add(isDir);

}

void UploadDialog::DownloadFile (wxString src, wxString dest)
{

    wxInputStream *in;
    wxFileOutputStream *out;
    size_t size;
    char *chunk;
    int iterations;
    int count;

    if (!abort)
    {
        in = ftp->GetInputStream(src);

        if ( !in )
        {
                wxLogError(wxT("Could not get file: ")+src);
        }
        else
        {
                
            size = in->GetLength();

            if (size > CHUNKSIZE)
                chunk = new char[CHUNKSIZE];
            else
                chunk = new char[size];

            mProgress = new ProgressDialog(wxT("Download Progress"), wxT(""));

            // create output file
            out = new wxFileOutputStream(dest);

            if (size > 0)
            {
                // find number of iterations needed
                if (size > CHUNKSIZE)
                    iterations = size / CHUNKSIZE;
                else
                    iterations = 1;
                
                for (count = 0; count < iterations; count++)
                {
                    if (!abort)
                    {
                        if (size > CHUNKSIZE)
                        {
                            in->Read(chunk, CHUNKSIZE);
                            out->Write(chunk, CHUNKSIZE);
                        }
                        else
                        {
                            in->Read(chunk, size);
                            out->Write(chunk, size);
                        }
                    }
                    
                    int updateResult = mProgress->Update(count, iterations, src);
                    if (updateResult != eProgressSuccess)
                    {
                        //wxMessageBox("ABORT", wxT("FTP Status"), wxOK | wxICON_INFORMATION, NULL);

                        abort = true;
                        break;
                    }
                        
                }

                if (!abort)
                {
                    int remSize = size - (CHUNKSIZE * iterations);

                    if (remSize > 0)
                    {

                        char *endChunk = new char[remSize];

                        in->Read(endChunk, remSize);
                        out->Write(endChunk, remSize);

                        delete [] endChunk;
                    }
                }
            }

            delete in;
            delete out;
            delete [] chunk;

            if (abort)
            {
                wxRemoveFile(dest);         
                ftp->Reconnect();
            }

            delete mProgress;
        }       
    }
}

void UploadDialog::UploadFile(wxString src, wxString dest)
{
    wxFileInputStream *in_stream;
    size_t size;
    char *chunk;
    int iterations;
    int count;

    in_stream = new wxFileInputStream(src);

    size = in_stream->GetLength();
        
    if (size > CHUNKSIZE)
        chunk = new char[CHUNKSIZE];
    else
        chunk = new char[size];

    // create progress bar
    mProgress = new ProgressDialog(wxT("Upload Progress"), wxT(""));

    // find number of iterations needed
    if (size > CHUNKSIZE)
        iterations = size / CHUNKSIZE;
    else
        iterations = 1;
        
    // create output file on server
    dest.Replace(wxT(" "), wxT("_"), true);
    dest = dest.MakeLower();
        
    wxOutputStream *out_stream = ftp->GetOutputStream(dest);    

    if (out_stream == NULL)
    {
       wxMessageBox(ftp->GetLastResult());
    }
    else
    {
        if (size > 0)
        {
            for (count = 0; count < iterations; count++)
            {
                if (size > CHUNKSIZE)
                {
                    in_stream->Read(chunk, CHUNKSIZE);
                    out_stream->Write(chunk, CHUNKSIZE);
                }
                else
                {
                    in_stream->Read(chunk, size);
                    out_stream->Write(chunk, size);
                }

                // result is false, user clicked abort
                if(!mProgress->Update(count, iterations, dest))
                {
                    abort = true;
                        break;
                }
                    
            }
    
            if (!abort)
            {
                int remSize = size - (CHUNKSIZE * iterations);

                if (remSize > 0)
                {

                    char *endChunk = new char[remSize];

                    in_stream->Read(endChunk, remSize);
                    out_stream->Write(endChunk, remSize);

                    delete [] endChunk;
                }
            }

        }
        delete out_stream;
    }

    delete [] chunk;
    delete in_stream;

    // if aborted, delete incomplete file
    if (abort)
        ftp->RmFile(dest);

    delete mProgress;
}

void UploadDialog::UploadDir (wxString src, wxString dest)
{

    wxDir *dir = new wxDir();
    wxArrayString *files = new wxArrayString();
    wxArrayString *dirs = new wxArrayString();
    wxString debug;
    wxString name;
    bool unique;
    int index;
    unsigned int count, count2;

    // get list of directories
    dir->GetAllFiles(src, files, wxT(""), wxDIR_FILES | wxDIR_DIRS);

    // extract directories from filenames
    for (count = files->GetCount()-1; count > 0; count--)
    {

        // remove filename
        index = files->Item(count).Find(wxT('\\'), true);
        name = files->Item(count).Mid(0, index);

        // remove root dir
        index = name.Find(wxT('\\'));
        name = name.Mid(index, name.Length() - index);
        
        // replace '\' with '/'
        name.Replace(wxT("\\"), wxT("/"), true);
        name = name.MakeLower();

        unique = true;
        for (count2 = 0; count2 < dirs->GetCount(); count2++)
        {
            if (name == dirs->Item(count2))
            {
                unique = false;
                break;
            }
        }

        if (unique)
            dirs->Add(name);
        
    }

    // create directories on server
    for (count = 0; count < dirs->GetCount(); count++)
    {
        wxString dirname = ftp->Pwd()+dirs->Item(count);
        ftp->MkDir(dirname.MakeLower());
    }

    // upload files
    for (count = 0; count < files->GetCount(); count++)
    {
        if (!abort)
        {
            index = files->Item(count).Find(wxT('\\'));
            name = files->Item(count).Mid(index, files->Item(count).Length() - index);

            name.Replace(wxT("\\"), wxT("/"), true);
            name = ftp->Pwd()+name;
            
            UploadFile(files->Item(count), name);
        }
    }

    RefreshFiles();
}

void UploadDialog::DownloadDir (wxString src, wxString dest)
{
    if (!abort)
    {
    wxString dirName;

    if (dest.Last() == wxT('\\'))
        dirName = dest+src;
    else
        dirName = dest+wxT("\\")+src;

    // create directory on users computer
    if (!wxDirExists(dirName))
        wxMkdir(dirName);
    
    // change to src directory
    if (ftp->ChDir(src))
    {
        GetDirContents();
        
        // loop through each item and download
        unsigned int count;
        for (count = 0; count < displayNames->GetCount(); count++)
        {
            if (!abort)
            {
                bool isDir = false;
                wxString destName;

                if (displayNames->Item(count) != wxT(".."))
                {
                    if (displayPerm->Item(count).GetChar(0) == wxT('d'))
                        isDir = true;

                    //destName = dirName+"\\"+displayNames->Item(count);

                    DownloadItem(displayNames->Item(count), dirName, isDir, true);
                }
            }
        }

        // switch back to parent
        ftp->ChDir(wxT(".."));
        GetDirContents();

    }
    else
        wxMessageBox(wxT("Cannot copy folder: ")+src, wxT("Error"), wxOK, NULL);

    }


}

void UploadDialog::DownloadItem (wxString &src, wxString &dest,
                                 bool dir, bool multi)
{
    if (abort)
        return;

    if (dir)
    {
        if (multi)
        {
            DownloadDir(src, dest);
        }

        else
        {
            wxDirDialog *saveDir = new wxDirDialog(this, wxT("Download Folder"), wxT(""));
            int result = saveDir->ShowModal();

            if (result == wxID_OK)
                DownloadDir(src, saveDir->GetPath());
        }

    }
    else
    {
        // if part of a multi file download, don't ask what to save file as...
        // just save to dest argument
        if (multi)
        {
            DownloadFile(src, dest+wxT("\\")+src);
        }
        else
        {
            FileDialog saveFile(this, wxT("Download File"),
                      wxT(""), src,
                      wxT("All files (*.*)|*.*"), wxFD_SAVE | wxRESIZE_BORDER);
            int result = saveFile.ShowModal();
    
            if (result == wxID_OK)
                DownloadFile(src, saveFile.GetPath());
        }
    }
}

void UploadDialog::DownloadItem (wxString &src, bool dir)
{
    if (abort)
        return;

    if (dir)
    {
        
        wxDirDialog saveDir(this, wxT("Download Folder"), wxT(""));
        int result = saveDir.ShowModal();

        if (result == wxID_OK)
            DownloadDir(src, saveDir.GetPath());

    }
    else
    {

        FileDialog saveFile(this, wxT("Download File"), wxT(""), src, wxT("All files (*.*)|*.*"), wxFD_SAVE | wxRESIZE_BORDER);
        int result = saveFile.ShowModal();
    
        if (result == wxID_OK)
            DownloadFile(src, saveFile.GetPath());
        
    }
}

void UploadDialog::DownloadMultipleItems (void)
{

    long item = -1;

    // get save directory
    wxDirDialog *saveDir = new wxDirDialog(this, wxT("Download Files"), wxT(""));
    saveDir->ShowModal();

    // download selected items
    item = fileManager->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
    while (item != -1)
    {
        // if directory
        if (displayPerm->Item(item).GetChar(0) == wxT('d'))
        {
            //DownloadItem(fileManager->GetItemText(listIndex), saveDir->GetPath(), true, true);    
            DownloadDir(displayNames->Item(item), saveDir->GetPath()+wxT("\\"));
    
        }
        else
        {
            DownloadFile(displayNames->Item(item), saveDir->GetPath()+wxT("\\")+displayNames->Item(item));
        }

        // get next item
        item = fileManager->GetNextItem(item, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);

    }

}

void UploadDialog::OnCreateDir(wxCommandEvent &event)
{

    wxString result = wxGetTextFromUser(wxT("Please enter new folder name:"), wxT("New Folder"), wxT(""), this);

    if (result != wxT(""))
    {
        result.Replace(wxT(" "), wxT("_"), true);

        if (ftp->MkDir(result.MakeLower()))
            RefreshFiles();
        else
           wxMessageBox(ftp->GetLastResult());
    }

}

void UploadDialog::OnNewSite (wxCommandEvent &event)
{
    int count;
    int index;
    long tmp;
    wxListItem listItem;
    wxString newSite = wxT("New Site");
    
    index = siteList->GetItemCount();

    tmp = siteList->InsertItem(index, newSite, 0);
    siteList->SetItemData(tmp, 0);

    // make sure all items are deselected
    for (count = 0; count < siteList->GetItemCount(); count++)
        siteList->SetItemState(count, 0, wxLIST_STATE_SELECTED);
    
    // select added item
    siteList->SetItemState(tmp, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED);

    txtFtpName->SetValue(newSite);

    ftpIndex = tmp;
}

void UploadDialog::OnDeleteSite (wxCommandEvent &event)
{

    wxString debug;

//  debug.Printf("%d", index);
//  wxMessageBox(debug, wxT("FTP Status"), wxOK | wxICON_INFORMATION, this);
    
    wxFileName fn( FileNames::DataDir(), wxT("connections.ini") );

    wxTextFile *file = new wxTextFile(fn.GetFullPath());

    if (file->Exists())
    {
        file->Open();

        file->RemoveLine(ftpIndex);
        file->RemoveLine(ftpIndex);
        file->RemoveLine(ftpIndex);
        file->RemoveLine(ftpIndex); 

        file->Write();
        file->Close();

        siteList->DeleteItem(ftpIndex);
    }

    UpdateSiteList();

}

void UploadDialog::OnFtpChange (wxCommandEvent &event)
{

    siteList->SetItemText(ftpIndex, txtFtpName->GetValue());
}

void UploadDialog::OnSelectSite (wxListEvent &event)
{

    currentFtp = event.m_itemIndex;
    ftpIndex = event.m_itemIndex;

    txtFtpName->SetValue(ftpList->Item((ftpIndex * 4)+0));
    txtFtpHost->SetValue(ftpList->Item((ftpIndex * 4)+1));
    txtFtpUser->SetValue(ftpList->Item((ftpIndex * 4)+2));
    txtFtpPass->SetValue(ftpList->Item((ftpIndex * 4)+3));

    //wxString debug;
    //debug.Printf("ftpIndex %d", ftpIndex);
    //wxMessageBox(debug, wxT("FTP Status"), wxOK | wxICON_INFORMATION, NULL);


}

bool UploadDialog::SaveFtpSite(wxString name, wxString host, wxString user, wxString pass)
{
    wxFileName fn( FileNames::DataDir(), wxT("connections.ini") );

    wxTextFile *file = new wxTextFile(fn.GetFullPath());

    if (file->Exists())
        file->Open();
    else
    {
        file->Create();
        file->Open();
    }

    // see if this ftp is already in our file
    unsigned int count = 0;
    int found = -1;

    while (count < file->GetLineCount())
    {
    
        if (file->GetLine(count) == name)
        {
            found = count;
            break;
        }

        count += 4;
    }

    // add new site
    if (found == -1)
    {
        file->AddLine(name);
        file->AddLine(host);
        file->AddLine(user);
        file->AddLine(pass);
        
        file->Write();
        file->Close();

        return true;

    }
    else
    {
        file->RemoveLine(found);
        file->RemoveLine(found);
        file->RemoveLine(found);
        file->RemoveLine(found);

        file->InsertLine(pass, found);
        file->InsertLine(user, found);
        file->InsertLine(host, found);
        file->InsertLine(name, found);
        
        file->Write();
        file->Close();

        return false;
    }




}

void UploadDialog::LoadFtpSiteList (void)
{
    wxFileName fn( FileNames::DataDir(), wxT("connections.ini") );

    wxTextFile *file = new wxTextFile(fn.GetFullPath());
    unsigned int count;

    if (file->Exists())
    {
        file->Open();
    
        ftpList->Empty();
    
        for (count = 0; count < file->GetLineCount(); count++)
            ftpList->Add(file->GetLine(count));         
    
        file->Close();
    }
        
}

void UploadDialog::UpdateSiteList (void)
{
    unsigned int count;
    unsigned int insert_count;
    long tmp;

    LoadFtpSiteList();


    count = 0;
    insert_count = 0;
    
    siteList->DeleteAllItems();

    while (count < ftpList->GetCount())
    {
        //wxMessageBox(ftpList->Item(count), wxT("Error"), wxOK, NULL);

        tmp = siteList->InsertItem(insert_count, ftpList->Item(count), 0);
        siteList->SetItemData(tmp, insert_count);

        count += 4;
        insert_count++;
    }

}

// Indentation settings for Vim and Emacs and unique identifier for Arch, a
// version control system. Please do not modify past this point.
//
// Local Variables:
// c-basic-offset: 4
// indent-tabs-mode: nil
// End:
//
// vim: et sts=4 sw=4

