/***************************************************************************
 *   Copyright (C) 2005 by Reel Multimedia                                 *
 *                                                                         *
 *                                                                         *
 *   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 <vector>
#include <iostream>
#include <sstream>

#include <vdr/osd.h>

#include "filebrowser.h"
#include "stringtools.h"
#include "menushow.h"
#include "menufileinfo.h"
#include "convert.h"
#include "mountmanager.h"
#include "def.h"
#include "threadprovider.h"
#include "menuplaylist.h"
#include "userIf.h"
#include "filetools.h"
#include "menuBrowser.h"

#include "i18n.h"

//---------listings of files and directories to be handled individually---------

// "directory", "old name", "new name", expert mode
const uint adjustableDirEntriesSize_expert = 2;
const char *const adjustableDirEntries_expert[][3] =
{
    {BASE_DIR, "hd", "Hard Drive"},
    {BASE_DIR, "dvd", "DVD"},
};

// "directory", "old name", "new name", restricted/autostart mode
const uint adjustableDirEntriesSize_restricted = 7;
const char *const adjustableDirEntries_restricted[][3] =
{
    {BASE_DIR, "hd",       "Hard Drive"},
    {BASE_DIR, "dvd",      "DVD"},
    {HD_DIR, "music",      "My Music"},
    {HD_DIR, "pictures",   "My Images"},
    {HD_DIR, "video",      "My Videos"},
    {HD_DIR, "recordings", "My Recordings"},
    {VIDEO_DIR, "dvd",     "My DVDs"}
};

// "base directory", "directory name", "pretitle for entries in this directory", restricted/autostart mode
const uint preTitleEntriesSize = 5;
const char *const preTitleEntries[][3] =
{
    {HD_DIR, "music",      "My Music"},
    {HD_DIR, "pictures",   "My Images"},
    {VIDEO_DIR, "dvd",     "My DVDs"},
    {HD_DIR, "video",      "My Videos"},
    {HD_DIR, "recordings", "My Recordings"}
};

// "base directory", "directory name", "entry", alternative pretitle, restricted/autostart mode
const uint preTitleExceptionsSize = 1;
const char *const preTitleExceptions[][4] =
{
    {HD_DIR, "video",  "dvd",  ""}
};

// "directory" - dirs in which hidden entries are not displayed
const uint hideHiddenEntryDirsSize= 1;
const char *const hideHiddenEntryDirs[] =
{
    BASE_DIR
};

// "directory", "name" - empty "directory" means in all directories
const uint forbiddenDirEntriesSize = 7;
const char *const forbiddenDirEntries[][2] =
{
    {"", "."},
    {"", "protection.fsk"},
    {HD_DIR, "Channels.conf"},
    {HD_DIR, "Channels.conf.tmp"},
    {HD_DIR, "epg.data"},
    {HD_DIR, "sys.log"},
    {HD_DIR, "home"}
};

// "directory", "name", restricted/autostart mode - only these entries will appear in the specified dir
const uint allowedDirEntriesSize = 4;
const char *const allowedDirEntries[][2] =
{
    {HD_DIR, "music"},
    {HD_DIR, "pictures"},
    {HD_DIR, "video"},
    {HD_DIR, "recordings"}
};

// "directory", "name" - entries will appear in same order
const uint positionedDirEntriesSize = 2;
const char *const positionedDirEntries[][2] =
{
    {BASE_DIR, "hd"},
    {BASE_DIR, "dvd"}
};

//---------Utilities-------------------------------

bool sortDirEntry(const cMenuDirEntryItem *item1, const cMenuDirEntryItem *item2)
{
    return GetLast(item1->GetPath()) <  GetLast(item2->GetPath());
}

//----------cMenuFileBrowser-----------------------

cThreadProvider cMenuFileBrowser::provider_;
cPlayList cMenuFileBrowser::playlist_;

cMenuFileBrowser::cMenuFileBrowser(const std::string title, cFileBrowserStatus *newstatus, cFileCache *cache, cImageConvert *convert)
: cMenuFileBrowserBase(title), currentdir_(newstatus->GetStartDir()), cache_(cache), convert_(convert), playlistReplaying_(false)
{
    printf("#####cMenuFileBrowser: currentdir_ = %s mode = %d\n", currentdir_.c_str(), newstatus->GetMode());
    SetCols(2, 2, 2);

    status = newstatus;
    status->Startup();

    if(status->GetMode() == browseplaylist)
    {
        printf("#####cMenuFileBrowser: browseplaylist\n"); 
        userIf_ = cMenuBrowserBrowsePlayListIf::Instance();
        userIf_->EnterState(this);
    }
    else if(status->GetMode() == autostart)
    {
        printf("#####cMenuFileBrowser: autostart\n"); 
        userIf_ = cMenuBrowserAutoStartIf::Instance();
        userIf_->EnterState(this);
    }
    else if(status->GetMode() == expert)
    {
        printf("#####cMenuFileBrowser: expert\n");
        if(status->ClosePlayList())
        {
 	    userIf_ = cMenuBrowserShutdownRequestIf::Instance();
            userIf_->EnterState(this, cMenuBrowserStandardIf::Instance());
        }
        else
        {
	    userIf_ = cMenuBrowserStandardIf::Instance();
            userIf_->EnterState(this);
        }
    }
    else if(status->GetMode() == restricted)
    {
        printf("#####cMenuFileBrowser: restricted\n");
        if(status->ClosePlayList())
        {
 	    userIf_ = cMenuBrowserShutdownRequestIf::Instance();
            userIf_->EnterState(this, cMenuBrowserStandardIf::Instance());
        }
        else
        {
	    userIf_ = cMenuBrowserRestrictedIf::Instance();
            userIf_->EnterState(this);
        }
    }

    if(!Refresh(status->GetStartFile(), true))
    {
        //start dir cannot be opened -> use BASE_DIR instead
        currentdir_ = BASE_DIR;
        Refresh(itemId(), true);
    }

    if(status->EnterPlayList())
    {
        if(status->GetPlayList() != playlist_.GetName())
        {
            LoadPlayList(cPlayListItem(status->GetPlayList()));
        }
        if(!playlist_.CurrentIsSet() || playlist_.GetCurrent().GetPath() != status->GetPlayListEntry())
        {
            playlist_.SetCurrent(status->GetPlayListEntry(), true);
        }
        cUserIfBase::RemoveLastIf();
        EnterPlayList();
    }

    status->Started();
}

cMenuFileBrowser::~cMenuFileBrowser()
{
    Shutdown();
}

void cMenuFileBrowser::Shutdown()
{
    //make sure, conversion has finished
    if(convert_)
    {
        RemoveItemsFromConversionList();
    }

    //shutdown submenus of browser type in reverse order
    ShutdownBrowserSubMenu();

    //clear playlist if not active
    if(!status->PlayListIsActive())
    {
        ClearPlayList();
    }

    status->Shutdown(currentdir_, GetCurrentItem() ? GetCurrentItem()->GetPath() : "",
                    playlist_.GetName(), playlist_.CurrentIsSet() ? playlist_.GetCurrent().GetPath() : "");
}

eOSState cMenuFileBrowser::ProcessKey(eKeys Key)
{
    eOSState state = osUnknown;
    if(Key != kInfo)
    {
        state = userIf_->AnyKey(this, Key);
    }
    RefreshIfDirty();

    if(state == osUnknown && !GetBrowserSubMenu())
    {
        switch (Key)
        {
            case kOk:
                state = userIf_->OkKey(this);
                break;
            case kBack:
                state = userIf_->BackKey(this);
                break;
            case kRed:
                state = userIf_->RedKey(this);
                break;
            case kGreen:
                state = userIf_->GreenKey(this);
                break;
            case kYellow:
                state = userIf_->YellowKey(this);
                break;
            case kBlue:
                state = userIf_->BlueKey(this);
                break;
            case kInfo:
                state = userIf_->InfoKey(this);
                break;
            default:
                state = osContinue;
                break;
        }
    }
    return state;
}

eOSState cMenuFileBrowser::ShowFileWithImageViewer(cPlayListItem &item, bool asPlaylist)
{
    //printf("---cMenuFileBrowser::ShowFileWithImageViewer item = %s asPlaylist = %d---\n", item.GetPath().c_str(), asPlaylist);
    ClearMarks();
    if(asPlaylist)
    {
        actualPlaylist_.Clear();
        playlist_.GetPartialListOfSimilarItems(item, actualPlaylist_);
        playlistReplaying_ = true;
    }
    else
    {
        BuildActualPlayList(item,  actualPlaylist_);
        actualPlaylist_.SetCurrent(item, true);
        playlistReplaying_ = true;
    }
    return AddFileBrowserSubMenu(new cMenuShowFile(DESCRIPTION, &actualPlaylist_, cache_, convert_));
}

eOSState cMenuFileBrowser::ShowPlayListWithXine()
{
     if(playlist_.CurrentIsSet())
     {
        return ShowFileWithXine(playlist_.GetCurrent(), true);
     }
     return osContinue;
}

eOSState cMenuFileBrowser::ShowFileWithXine(const cPlayListItem &item, bool asPlaylistItem)
{
    //printf("---------cMenuFileBrowser::ShowFileWithXine, asPlaylist = %d--------\n", (int)asPlaylist);
    std::vector<std::string> playlistEntries; //empty list
    if(asPlaylistItem)
    {
        cPlayList partialList;
        playlist_.GetPartialListOfSimilarItems(item, partialList);
        playlistEntries = partialList.GetPathList();
    }
    std::string tmp = item.GetPath().c_str();
    if(strstr("://", tmp.c_str()))
    {
	tmp = std::string("file://") + item.GetPath().c_str();
    }

    struct
    {
        char const *mrl;
        bool playlist;
        std::vector<std::string> playlistEntries;
    } xinePlayData =
    {
        tmp.c_str(),
        asPlaylistItem,
        playlistEntries
    };

    cPluginManager::CallAllServices("Xine Play mrl", &xinePlayData);
    XineStarted(asPlaylistItem);
    return osEnd;
}

eOSState cMenuFileBrowser::ShowDvdWithXine(const cPlayListItem &item, bool asPlaylistItem)
{
    //printf("---------cMenuFileBrowser::ShowDvdFileWithXine, asPlaylist = %d--------\n", (int)asPlaylist);
    std::vector<std::string> playlistEntries; //empty list
    if(asPlaylistItem)
    {
        cPlayList partialList;
        playlist_.GetPartialListOfSimilarItems(item, partialList);
        playlistEntries = partialList.GetPathList();
    }
    std::string tmp = item.GetPath().c_str();
    if(!strstr("dvd://", tmp.c_str()))
    {
	tmp = std::string("dvd://") + item.GetPath().c_str();
    }

    struct
    {
        char const *mrl;
        bool playlist;
        std::vector<std::string> playlistEntries;
    } xinePlayData =
    {
        tmp.c_str(),
        asPlaylistItem,
        playlistEntries
    };

    cPluginManager::CallAllServices("Xine Play mrl", &xinePlayData);
    XineStarted(asPlaylistItem);
    return osEnd;
}

eOSState cMenuFileBrowser::ShowThumbnail(cPlayListItem item, bool hide)
{
    static cPlugin *skinreelng = 0;
    if(skinreelng == 0) skinreelng = cPluginManager::GetPlugin("skinreelng");

    if(hide)
    {
        //printf("HideThumbnail\n");
        if(skinreelng) skinreelng->Service("setThumb", NULL);
    }
    else
    {
        //printf("ShowThumbnail\n");
        std::string thumb;
        //TODO: make sure, cache exists
        if(!cache_->FetchFromCache(item.GetPath(), thumb, true))
        {
            std::string cmd = "anytopnm \"" + item.GetPath() + "\" |pnmscale -xysize 150 150 |pnmtopng > \"" + thumb + "\"";
            printf("executing command: \"%s\"\n", cmd.c_str());
            //instantly convert and save in filecache
            SystemExec(cmd.c_str());
        }

        /* tell skinreelng that a new thumb is available */
        if(skinreelng) skinreelng->Service("setThumb", (void*) (thumb.c_str()));
    }
    return osContinue;
}

eOSState cMenuFileBrowser::OpenFileInfo(const cMenuFileItem &file)
{
    return AddFileBrowserSubMenu(new cMenuFileInfo(DESCRIPTION, file));
}

eOSState cMenuFileBrowser::EnterSubDir(std::string pathname)
{
    std::string lastdir = currentdir_;
    if(GetLast(pathname) == "..")
    {
        ExitDir();
    }
    else if (!ChangeDir(pathname))
    {
        //go back to last directory in case of error
        ChangeDir(lastdir);
    }
    return osContinue;
}

eOSState cMenuFileBrowser::LoadAndEnterPlayList(cPlayListItem item)
{
    LoadPlayList(item);
    return EnterPlayList();
}

//rename some entries in root dir, inefficient for larger numbers of entries!!
std::string cMenuFileBrowser::GetAdjustedEntryName(std::string path) const
{
    std::string dir = RemoveName(path);
    std::string name = GetLast(path);

    if(status->GetMode() == restricted || status->GetMode() == autostart || status->GetMode() == browseplaylist)
    {
        for (uint i = 0; i < adjustableDirEntriesSize_restricted; i++)
        {
            if(adjustableDirEntries_restricted[i][0] == dir
            && adjustableDirEntries_restricted[i][1] == name)
            {
                return tr(adjustableDirEntries_restricted[i][2]);
            }
        }
    }
    else if(status->GetMode() == expert || status->GetMode() == browseplaylist)
    {
        for (uint i = 0; i < adjustableDirEntriesSize_expert; i++)
        {
            if(adjustableDirEntries_expert[i][0] == dir
            && adjustableDirEntries_expert[i][1] == name)
            {
                return tr(adjustableDirEntries_expert[i][2]);
            }
        }
    }
    return name;
}

eOSState cMenuFileBrowser::EnterPlayList(bool play)
{
    std::string title = "Playlist: " + RemoveEnding(GetLast(playlist_.GetName()));
    return AddFileBrowserSubMenu(new cMenuPlayList(title.c_str(), &playlist_, cache_, convert_, play));
}

eOSState cMenuFileBrowser::OpenMarked(bool &playlistEntered)
{
    if(!markedEntries_.empty())
    {
        int oldsize = playlist_.Size();
        playlist_.Insert(markedEntries_);
        if(playlist_.Size() > oldsize)
        {
            cPlayListItem currentItem = playlist_.GetNthItem(oldsize);
            playlist_.SetCurrent(currentItem);
            playlistEntered = true;
            eOSState state;
            state = currentItem.Open(this, true);
            return state;
        }
    }
    return osContinue;
}

eOSState cMenuFileBrowser::ExitDir()
{
    if(currentdir_ == status->GetExitDir() || currentdir_ == BASE_DIR) //never go beyond BASE_DIR!
    {
        status->NormalExit();
        return osBack;
    }
    else
    {
        if(mountMgr_.IsMounted(currentdir_))
        {
            if(convert_)
            {
                RemoveItemsFromConversionList();
                convert_->WaitUntilCopied();
            }
            mountMgr_.Umount();
        }
        ChangeDir(RemoveName(currentdir_), currentdir_);
        return osContinue;
    }
}

eOSState cMenuFileBrowser::StandardKeyHandling(eKeys Key)
{
    if((Key == kBack || Key == kInfo) && !HasSubMenu()) //these keys are handled separately
    {
        return osUnknown;
    }
    else
    {
        return cOsdMenu::ProcessKey(Key);
    }
}

void cMenuFileBrowser::GetFinishedTasks()
{
    cTask *task;
    if(provider_.GetNextFinishedTask(&task))
    {
        delete task;
        Refresh();
    }
}

void cMenuFileBrowser::DeleteMarkedEntries()
{
    std::vector<std::string> entriesToDelete;
    for(std::set<itemId>::iterator i = markedEntries_.begin(); i != markedEntries_.end(); i++)
    {
        if(convert_ && GetFileItem(*i))
        {
            convert_->RemoveFromConversionList((*i).path_);
            if (convert_->IsInConversion((*i).path_))
                convert_->WaitUntilCopied();
        }
        entriesToDelete.push_back((*i).path_);
    }
    provider_.InsertNewTask(new cDeleteTask(entriesToDelete, currentdir_));
}

void cMenuFileBrowser::DeleteMarkedOrCurrent()
{
    if(markedEntries_.empty())
    {
        cMenuDirEntryItem *item = GetCurrentDirEntryItem();
        if(item && GetLast(item->GetPath()) != "..")
        {
            if(convert_ && item->IsFile())
            {
                if (convert_->IsInConversion(item->GetPath()))
                    convert_->WaitUntilCopied();
            }
            std::vector<std::string> entriesToDelete;
            entriesToDelete.push_back(item->GetPath());
            provider_.InsertNewTask(new cDeleteTask(entriesToDelete, currentdir_));
        }
    }
    else
    {
        DeleteMarkedEntries();
    }
}

void cMenuFileBrowser::InsertCopiedEntries()
{
    Paste(false);
}

void cMenuFileBrowser::InsertMovedEntries()
{
    Paste(true);
}

void cMenuFileBrowser::CopyMarkedEntries()
{
    for(std::set<itemId>::iterator i = markedEntries_.begin(); i != markedEntries_.end(); i++)
    {
        copiedEntries_.push_back((*i).path_);
    }
}

void cMenuFileBrowser::CopyMarkedOrCurrent()
{
    if(markedEntries_.empty())
    {
        cMenuDirEntryItem *item = GetCurrentDirEntryItem();
        if(item && GetLast(item->GetPath()) != "..")
        {
            copiedEntries_.push_back(item->GetPath());
        }
    }
    else
    {
        CopyMarkedEntries();
    }
}

bool cMenuFileBrowser::RenameEntry(std::string oldname, std::string newname)
{
    std::string cmd = std::string("mv ") + "\"" + currentdir_  + "/" + oldname + "\" " +  "\"" + currentdir_ + "/" + newname + "\"";
    //printf("----%s-----\n", cmd.c_str());
    return !::system(cmd.c_str());
}

bool cMenuFileBrowser::CreateDirectory(std::string name)
{
    std::string cmd = std::string("mkdir ") + "\"" + currentdir_ + "/" + name + "\"";
    //printf("----%s----\n", cmd.c_str());
    return !::system(cmd.c_str());
}

bool cMenuFileBrowser::InsertCurrentInPlayList()
{
    cMenuDirEntryItem *item = GetCurrentDirEntryItem();
    if(item && GetLast(item->GetPath()) != "..")
    {
        return playlist_.Insert(item);
    }
    return playlist_.Insert(markedEntries_);
}

bool cMenuFileBrowser::InsertMarkedEntriesInPlayList()
{
    return playlist_.Insert(markedEntries_);
}

bool cMenuFileBrowser::InsertMarkedOrCurrentInPlayList()
{
    if(markedEntries_.empty())
    {
        return InsertCurrentInPlayList();
    }
    else
    {
        return InsertMarkedEntriesInPlayList();
    }
    return true;
}

bool cMenuFileBrowser::HasUnfinishedTasks()
{
    return provider_.HasTasks();
}

bool cMenuFileBrowser::Refresh(itemId newItemId, bool initial)
{
    std::string newCurrentPath = newItemId.path_;
    std:: string currentPath = GetCurrentItemPath();

    if(initial)
    {

    }

    if(initial && playlistReplaying_)
    {
        currentPath = actualPlaylist_.CurrentIsSet() ? actualPlaylist_.GetCurrent().GetPath() : "";
        playlistReplaying_ = false;
    }
    if(newCurrentPath != "")
    {
        currentPath = newCurrentPath;
    }

    SetTitle(GetTitleString().c_str());
    ClearMarks();
    Clear();

    //create menu entries
    bool success = OpenDir();

    //set current entry
    if(success && currentPath != "")
    {
        for (int i= 0; i < Count(); i++)
        {
            if(GetItem(i)->GetPath() == currentPath)
            {
                SetCurrent(Get(i));
                UpdateCurrent();
                break;
            }
        }
    }

    if(success)
    {
        //start conversion for convertable items
        InsertItemsInConversionList();
        convert_->StartConversion();
        FlagItems();
    }

    //refresh user if
    userIf_->SetMode(this, status->GetMode());
    userIf_->SetHelp(this);
    Display();

    return success;
}

void cMenuFileBrowser::Hide(bool hide)
{
    static int cur = 0;
    if(!hide)
    {
        Clear();
        OpenDir();
        ReMarkItems();
        FlagItems();
        SetCurrent(Get(cur));
        UpdateCurrent();
        userIf_->SetHelp(this);
    }
    else
    {
        cur = Current();
        Clear();
    }
    Display();
}

bool cMenuFileBrowser::OpenDir()
{
    if (!mountMgr_.Mount(currentdir_))
    {
        Skins.Message(mtError, tr("Cannot mount media"));
        return false;
    }

    //use BASEDIR if currentdir_ is empty
    std::string dir = currentdir_;
    if (dir == "")
    {
        dir = BASE_DIR;
    }

    std::vector<Filetools::dirEntryInfo>  dirs;
    std::vector<Filetools::dirEntryInfo>  files;
    std::vector<Filetools::dirEntryInfo>  dirLinks;
    std::vector<Filetools::dirEntryInfo>  fileLinks;

    //search for entries in directory
    if(!Filetools::GetDirEntries(dir, dirs, files, dirLinks, fileLinks))
    {
        printf("couldn't open %s\n", dir.c_str());
        return false;
    }

    std::vector<cMenuDirItem*> dirEntries;
    std::vector<cMenuFileItem*> fileEntries;

    //create the corresponding menu entries
    for(uint i = 0; i < dirs.size(); i++)
    {
        dirEntries.push_back(new cMenuDirItem(dirs[i].name_, this));
    }
    for(uint i = 0; i < dirLinks.size(); i++)
    {
        dirEntries.push_back(new cMenuDirLinkItem(dirLinks[i].name_, this));
    }
    for(uint i = 0; i < files.size(); i++)
    {
        fileEntries.push_back(new cMenuFileItem(files[i].name_, this));
    }
    for(uint i = 0; i < fileLinks.size(); i++)
    {
        fileEntries.push_back(new cMenuFileLinkItem(fileLinks[i].name_, this));
    }

    //Sort menu entries alphabetically
    std::stable_sort(dirEntries.begin(), dirEntries.end(), sortDirEntry);
    std::stable_sort(fileEntries.begin(), fileEntries.end(), sortDirEntry);

    //Remove "forbidden" entries, resort
    AdjustEntries(dirEntries, fileEntries);

    //Add menu entries
    uint i = 0;
    if(currentdir_ != status->GetExitDir() && currentdir_ != BASE_DIR)
    {
        for (i = 0; i < dirEntries.size(); ++i)
        {
            if(GetLast(dirEntries[i]->GetPath()) == "..")
            {
                Add(dirEntries[i]);
                dirEntries[i]->Set();
                break;
            }
        }
    }
    for (i  = 0; i < dirEntries.size(); ++i)
    {
        if(GetLast(dirEntries[i]->GetPath()) != "..")
        {
            Add(dirEntries[i]);
            dirEntries[i]->Set();
        }
    }
    for (i = 0; i < fileEntries.size(); ++i)
    {
        Add(fileEntries[i]);
        fileEntries[i]->Set();
    }

    return true;
}

bool cMenuFileBrowser::ChangeDir(std::string pathname, std::string currentItem)
{
    currentdir_ = pathname;
    if(convert_)
    {
        RemoveItemsFromConversionList();
    }
    return Refresh(currentItem);
}

void cMenuFileBrowser::ClearPlayList()
{
    //printf("----------cMenuFileBrowser::ClearPlaylist--------\n");
    playlist_.Clear(status->GetExitDir());
}

void cMenuFileBrowser::SavePlayList()
{
    //printf("----------cMenuFileBrowser::SavePlaylist--------\n");
    playlist_.SaveToFile();
    ClearPlayList();
}

void cMenuFileBrowser::CopyPlayListToUsb()
{
    //printf("----------cMenuFileBrowser::CopyPlaylistToUsb--------\n");
    //TODO: determine actual mount point for usb device!!!
    std::string usbdir = "/media/USB_DISK_2.0";
    std::string listdir = usbdir + "/" + RemoveEnding(GetLast(playlist_.GetName()));
    std::string cmd = std::string("mkdir ") + listdir;
    ::system(cmd.c_str());
    provider_.InsertNewTask(new cCopyTask(playlist_.GetPathList(), listdir));
}

void cMenuFileBrowser::CopyPlayListToDvd()
{
    playlist_.SaveToFile(); //?????????????
    std::string cmd =  std::string("sudo mp3_2_media.sh ") + playlist_.GetName();
    printf("-----CopyPlaylistToDvd %s--------\n", cmd.c_str());
    ::system(cmd.c_str());
}

bool cMenuFileBrowser::PlayListIsEmpty() const
{
    return playlist_.IsEmpty();
}

void cMenuFileBrowser::Paste(bool remove)
{
    if(!remove)
    {
         provider_.InsertNewTask(new cCopyTask(copiedEntries_, currentdir_));
    }
    else
    {
        for (uint i= 0; i< copiedEntries_.size(); i++)
        {
            if(convert_)
            {
                convert_->RemoveFromConversionList(copiedEntries_[i]);
                if(convert_->IsInConversion(copiedEntries_[i]))
                    convert_->WaitUntilCopied();
            }
        }
        provider_.InsertNewTask(new cMoveTask(copiedEntries_, currentdir_, RemoveName(copiedEntries_[0])));
    }
    copiedEntries_.clear();
}

void cMenuFileBrowser::InsertItemsInConversionList() const
{
    cMenuFileItem *fileitem;
    std::map<std::string, cPlayListItem> convItems;
    for (int i = 0; i < Count(); i++)
    {
        fileitem = GetFileItem(i);
        if(fileitem && fileitem->GetFileType().IsOfSimilarType(tp_jpg))
        {
            if (!cache_->InCache(fileitem->GetPath()) && convert_)
            {
                convItems[fileitem->GetPath()] = fileitem->GetPlayListItem();
            }
        }
    }
    convert_->InsertInConversionList(convItems);
}

void cMenuFileBrowser::RemoveItemsFromConversionList() const
{
    cMenuFileItem *fileitem;
    for (int i= 0; i < Count(); i++)
    {
        fileitem = GetFileItem(i);
        if(fileitem && fileitem->GetFileType().IsOfSimilarType(tp_jpg))
        {
            convert_->RemoveFromConversionList(fileitem->GetPath());
        }
    }
}

std::string cMenuFileBrowser::GetTitleString() const
{
    std::string titlestring;
    if(status->GetMode() == restricted /*|| status->GetMode() == browseplaylist*/)
    {
        titlestring = GetPreTitle(currentdir_);
        titlestring += GetLastN(GetAdjustedEntryName(currentdir_), 20);
    }
    else if(status->GetMode() == expert || status->GetMode() == autostart)
    {
        titlestring = tr(DESCRIPTION) + std::string(": ");
        titlestring += GetLastN(currentdir_, 20);
    }
    else if(status->GetMode() == browseplaylist)
    {
        titlestring = GetPreTitle(currentdir_);
        titlestring += GetLastN(GetAdjustedEntryName(currentdir_), 20);
        titlestring += std::string(": ") + tr("Insert in playlist");
    }
    return titlestring;
}

void cMenuFileBrowser::LoadPlayList(cPlayListItem item)
{
    playlist_.LoadFromFile(item);
}

void cMenuFileBrowser::FlagItems()
{
    cMenuFileItem *fileitem;
    for (int i = 0; i < Count(); i++)
    {
        fileitem = GetFileItem(i);
        if(fileitem)
        {
            if(status->GetMode() == browseplaylist && playlist_.IsInList(fileitem->GetPlayListItem()))
            {
                fileitem->Flag();
            }
            else
            {
                fileitem->UnFlag();
            }
        }
    }
}

std::string cMenuFileBrowser::GetPreTitle(std::string entry) const
{
    std::string pretitle = "";
    for (uint i = 0; i < preTitleEntriesSize; i++)
    {
         if (StartsWith2(entry, std::string(preTitleEntries[i][0]) + "/" + preTitleEntries[i][1]))
         {
              pretitle = std::string(tr(preTitleEntries[i][2])) + ": ";
              break;
         }
    }
    for (uint i = 0; i < preTitleExceptionsSize; i++)
    {
         if (entry == std::string(preTitleExceptions[i][0]) + "/" + preTitleExceptions[i][1] + "/" + preTitleExceptions[i][2])
         {
              pretitle = preTitleExceptions[i][3]; 
              break;
         }
    }
    return pretitle;
}

bool cMenuFileBrowser::IsForbiddenDirEntry(std::string entry) const
{
    std::string dir = RemoveName(entry);
    std::string name = GetLast(entry);
    for (uint i = 0; i < forbiddenDirEntriesSize; i++)
    {
         if (forbiddenDirEntries[i][1] == name && (forbiddenDirEntries[i][0] == dir || forbiddenDirEntries[i][0] == ""))
         {
              return true;
         }
    }
    return false;
}

bool cMenuFileBrowser::IsAllowedDirEntry(std::string entry) const
{
    if(status->GetMode() == expert || status->GetMode() == browseplaylist)
    {
        return true;
    }
    std::string dir = RemoveName(entry);
    std::string name = GetLast(entry);
    bool foundDir = false;
    for (uint i = 0; i < allowedDirEntriesSize; i++)
    {
       if(allowedDirEntries[i][0] == dir || allowedDirEntries[i][0] == "")
       {
           foundDir = true;
       }
    }
    if(!foundDir)
    {
        return true;
    }
    for (uint i = 0; i < allowedDirEntriesSize; i++)
    {
         if (allowedDirEntries[i][1] == name && (allowedDirEntries[i][0] == dir || allowedDirEntries[i][0] == ""))
         {
              return true;
         }
    }
    return false;
}

bool cMenuFileBrowser::IsHiddenDirEntry(std::string entry) const
{
    std::string dir = RemoveName(entry);
    std::string name = GetLast(entry);
    for (uint i = 0; i < hideHiddenEntryDirsSize; i++)
    {
        if(dir == hideHiddenEntryDirs[i])
        {
            if(StartsWith(name, ".") && name != "..")
            {
                return true;
            }
        }
    }
    //TODO: limit to resume files, not all hidden entries
    if(StartsWith(name, ".") && name != "..") // remove .files
    {
	    return true;
    }
    return false;
}

bool cMenuFileBrowser::IsInsideFilter(cMenuFileItem &item) const
{
    uint filter = status->GetFilter();
    if(filter & cl_unknown)
    {
        return true;
    }
    if(filter & item.GetFileType().GetClass())
    {
        return true;
    }
    return false;
}

//reposition entries in browser, inefficient!!!
void cMenuFileBrowser::RepositionDirEntries(std::vector<cMenuDirItem*> &direntries)
{
    std::vector<cMenuDirItem*> temp;

    for (uint i = 0; i < positionedDirEntriesSize; ++i)
    {
        for (std::vector<cMenuDirItem*>::iterator itd = direntries.begin(); itd < direntries.end(); )
        {
            std::string dir = RemoveName((*itd)->GetPath());
            std::string name = GetLast((*itd)->GetPath());
            if(positionedDirEntries[i][0] == dir && positionedDirEntries[i][1] == name)
            {
                temp.push_back(*itd);
                itd = direntries.erase(itd);
            }
            else
            {
                ++itd;
            }
        }
    }

    for (std::vector<cMenuDirItem*>::iterator itd = direntries.begin(); itd < direntries.end(); ++itd)
    {
        temp.push_back(*itd);
    }

    direntries = temp;
}

//adjust entry display, inefficient!!!
void cMenuFileBrowser::AdjustEntries(std::vector<cMenuDirItem*> &direntries, std::vector<cMenuFileItem*> &fileentries)
{
    //Big TODO: make it halfway efficient!
    //remove forbidden entries and hidden entries
    for (std::vector<cMenuDirItem*>::iterator itd = direntries.begin(); itd < direntries.end(); )
    {
        if (IsForbiddenDirEntry((*itd)->GetPath())
         || IsHiddenDirEntry((*itd)->GetPath())
         ||!IsAllowedDirEntry((*itd)->GetPath()))
        {
            itd = direntries.erase(itd);
        }
        else
        {
            ++itd;
        }
    }

    for (std::vector<cMenuFileItem*>::iterator itf = fileentries.begin(); itf < fileentries.end(); )
    {
        if (IsForbiddenDirEntry((*itf)->GetPath())
         || IsHiddenDirEntry((*itf)->GetPath())
         ||!IsAllowedDirEntry((*itf)->GetPath())
         ||!IsInsideFilter((**itf)))
        {
            itf = fileentries.erase(itf);
        }
        else
        {
             ++itf;
        }
    }
    //reposition entries
    RepositionDirEntries(direntries);
}
