//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2006 by PDSoft (Attila Padar)                *
//*                    http://mpxplay.cjb.net                              *
//*                  email: mpxplay@freemail.hu                            *
//**************************************************************************
//*  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.                  *
//*  Please contact with the author (with me) if you want to use           *
//*  or modify this source.                                                *
//**************************************************************************
//function:directory routines

#include "newfunc\newfunc.h"
#include "control\control.h"
#include "display\display.h"
#include "playlist.h"
#include <string.h>

#define SHOW_DRIVE_VOLUME_NAMES 1 // in playlist editor

#define MAX_DIRECTORY_DEPTH 32
#define LOADDIR_MAX_DRIVES ('Z'-'A'+1)

#define LOADDIR_FIRSTDRIVE 0       // A:
#define LOADDIR_FIRSTDRV_BROWSER 2 // C:

typedef struct drive_info_t{
 unsigned int type;
 char drivename[4];   // have to be filled (with "D:")
 char volumename[24];
}drive_info_t;

static struct playlist_entry_info *browser_get_drives(struct playlist_entry_info *,char **);
static struct playlist_entry_info *browser_get_directories(struct playlist_entry_info *,struct playlist_side_info *,char **);
static struct playlist_entry_info *browser_get_files_from_dir(struct playlist_entry_info *,struct playlist_side_info *,char **);
static void loaddir_select_drive_retry(struct playlist_side_info *psi);

extern unsigned int cdw_is_drive_cd(int);
extern struct playlist_entry_info *cdw_get_allfiles(struct playlist_entry_info *,char **,int,char *);

extern unsigned int desktopmode,refdisp,is_lfn_support,uselfn;

static unsigned int loaddir_lastvaliddrive;
static char allscanstring[16]={'d',':',PDS_DIRECTORY_SEPARATOR_CHAR,'*','.','*',PDS_DIRECTORY_SEPARATOR_CHAR,'*','.','*',0};
static drive_info_t drive_infos[LOADDIR_MAX_DRIVES];

// must match with browser_get_drives function!
static void loaddir_get_currdrivename(unsigned int drivenum,char *fnp)
{
 drive_info_t *di=&drive_infos[LOADDIR_FIRSTDRV_BROWSER];
 unsigned int i;
 for(i=LOADDIR_FIRSTDRV_BROWSER;i<=loaddir_lastvaliddrive;i++){
  if((di->type!=DRIVE_TYPE_NONE) && (pds_getdrivenum_from_path(di->drivename)==drivenum)){
   fnp+=pds_strcpy(fnp,di->drivename);
#ifdef SHOW_DRIVE_VOLUME_NAMES
   if(di->volumename[0]){
    *fnp++=' ';
    fnp+=pds_strncpy(fnp,di->volumename,8);
   }
#endif
   *fnp=0;
   break;
  }
  di++;
 }
}

static drive_info_t *loaddir_driveinfo_search_drivename(char *drvname)
{
 drive_info_t *di=&drive_infos[0];
 unsigned int i;
 for(i=0;i<=loaddir_lastvaliddrive;i++){
  if(di->type!=DRIVE_TYPE_NONE)
   if(pds_stricmp(drvname,di->drivename)==0)
    return di;
  di++;
 }
 return NULL;
}

static drive_info_t *loaddir_driveinfo_search_free_entry(unsigned int start)
{
 int i,end=LOADDIR_MAX_DRIVES,step=1,retry=2;
 do{
  drive_info_t *di=&drive_infos[start];
  for(i=start;i!=end;i+=step){
   if(di->type==DRIVE_TYPE_NONE)
    return di;
   di+=step;
  }
  end=-1;
  step=-1;
 }while(--retry);
 return NULL;
}

static void playlist_loaddir_get_driveinfos(void)
{
 unsigned int i;
 drive_info_t *di;
 char drivename[4],volumename[24];

 pds_memset((char *)&drive_infos[0],0,sizeof(drive_infos));

 // check drives
 di=&drive_infos[LOADDIR_FIRSTDRIVE];
 for(i=LOADDIR_FIRSTDRIVE;i<LOADDIR_MAX_DRIVES;i++,di++){
  di->type=pds_chkdrive(i);
  if(di->type!=DRIVE_TYPE_NONE){
   di->drivename[0]='A'+i;
   di->drivename[1]=':';
   di->drivename[2]=0;
   if((di->type==DRIVE_TYPE_HD) || (di->type==DRIVE_TYPE_CD))
    pds_drive_getvolumelabel(i,&di->volumename[0]);
   loaddir_lastvaliddrive=i;
  }
 }

 // check network
 if(!pds_network_check())
  return;

 // get network volume names
 for(i=0;i<LOADDIR_MAX_DRIVES;i++){
  int retcode;
  drivename[0]=volumename[0]=0;
  retcode=pds_network_query_assign(i,drivename,sizeof(drivename)-1,volumename,sizeof(volumename)-1);
  if(retcode==-1) // ??? end of assign list
   break;
  if(retcode==0){ // no error
   di=loaddir_driveinfo_search_drivename(drivename); // does this drive exist in the drive_infos already?
   if(!di){
    int drivenum=pds_getdrivenum_from_path(drivename);
    if(drivenum<0)
     drivenum=0;
    di=loaddir_driveinfo_search_free_entry(drivenum); // if not, search a free entry
    if(!di)
     break;
    loaddir_lastvaliddrive=di-(&drive_infos[0]);
   }
   di->type=DRIVE_TYPE_NETWORK;
   pds_strcpy(di->drivename,drivename);
   if(volumename[0])                                 // from network_query
    pds_strcpy(di->volumename,volumename);
   else{
    int drivenum=pds_getdrivenum_from_path(drivename);
    if(drivenum>=0)
     pds_drive_getvolumelabel(i,&di->volumename[0]); // from DOS
   }
  }
 }
}

/*void playlist_loaddir_get_driveinfos(void)
{
 unsigned int currdrive,lastdrive,i;
 drive_info_t *di;
 char drivename[4],volumename[24];

 pds_memset((char *)&drive_infos[0],0,sizeof(drive_infos));

 pds_drivesinfo(&currdrive,&lastdrive);

 if(lastdrive)
  lastdrive--;

 if(lastdrive>(LOADDIR_MAX_DRIVES-1))
  lastdrive=LOADDIR_MAX_DRIVES-1;

 // check drives
 di=&drive_infos[LOADDIR_FIRSTDRIVE];
 for(i=LOADDIR_FIRSTDRIVE;i<=lastdrive;i++,di++){
  di->type=pds_chkdrive(i);
  if(di->type!=DRIVE_TYPE_NONE){
   di->drivename[0]='A'+i;
   di->drivename[1]=':';
   di->drivename[2]=0;
   if((di->type==DRIVE_TYPE_HD) || (di->type==DRIVE_TYPE_CD))
    pds_drive_getvolumelabel(i,&di->volumename[0]);
   loaddir_lastvaliddrive=i;
  }
 }

 // check network
 if(!pds_network_check())
  return;

 // get network volume names
 for(i=0;i<=lastdrive;i++){
  int retcode;
  drivename[0]=volumename[0]=0;
  retcode=pds_network_query_assign(i,drivename,sizeof(drivename)-1,volumename,sizeof(volumename)-1);
  if(retcode==-1) // ??? end of assign list
   break;
  if(retcode==0){ // no error
   di=loaddir_driveinfo_search_drivename(drivename); // does this drive exist in the drive_infos already?
   if(!di){
    int drivenum=pds_getdrivenum_from_path(drivename);
    if(drivenum<0)
     drivenum=0;
    di=loaddir_driveinfo_search_free_entry(drivenum); // if not, search a free entry
    if(!di)
     break;
    loaddir_lastvaliddrive=di-(&drive_infos[0]);
   }
   di->type=DRIVE_TYPE_NETWORK;
   pds_strcpy(di->drivename,drivename);
   if(volumename[0])                                 // from network_query
    pds_strcpy(di->volumename,volumename);
   else{
    int drivenum=pds_getdrivenum_from_path(drivename);
    if(drivenum>=0)
     pds_drive_getvolumelabel(i,&di->volumename[0]); // from DOS
   }
  }
 }
}*/

static unsigned int loaddir_scansubdirs(struct playlist_side_info *psi,char *searchpath)
{
 struct playlist_entry_info *pei,*begine;
 unsigned int filecount=0;
 char *filenamesfieldp;
 struct pds_subdirscan_t dsi;
 char sout[64];

 if(!searchpath || !searchpath[0])
  return 0;

 begine=pei=psi->lastentry+1;
 filenamesfieldp=psi->filenameslastp;

 if(pds_subdirscan_open(searchpath,_A_NORMAL,&dsi))
  return 0;

 do{
  int fferror=pds_subdirscan_findnextfile(&dsi);
  if(fferror<0)
   break;
  if(dsi.flags&SUBDIRSCAN_FLAG_SUBDIR)
   display_message(1,0,dsi.currdir);
  if((fferror==0) && !(dsi.ff->attrib&(_A_SUBDIR|_A_VOLID)) && mpxplay_infile_check_extension(dsi.ff->name)){
   if((pei>psi->endentry) || (filenamesfieldp>=psi->filenamesendp))
    break;
   pei->filename=filenamesfieldp;
   filenamesfieldp+=pds_strcpy(filenamesfieldp,dsi.fullname)+1;
   pei++;
   sprintf(sout,"Read filenames (%3d) from ",++filecount);
   display_message(0,0,sout);
  }
 }while(pds_look_extgetch()!=KEY_ESC);

 pds_subdirscan_close(&dsi);

 if(pei==begine){  // files not found, try to load CDWs
  int drive=pds_getdrivenum_from_path(searchpath);
  char *shortfname=pds_getfilename_from_fullname(searchpath);
  pei=cdw_get_allfiles(pei,&filenamesfieldp,drive,shortfname);
 } // else we don't try to load cdw tracks (ie: from mixed-mode CDs)

 if(pei>psi->firstentry)
  playlist_enable_side(psi);
 else
  playlist_disable_side_full(psi);

 psi->lastentry=pei-1;
 psi->filenameslastp=filenamesfieldp;
 clear_message();

 if(pds_look_extgetch()==KEY_ESC){
  pds_extgetch();
  return KEY_ESC;
 }
 return 1;
}

void playlist_loaddir_scandrives(struct playlist_side_info *psi,char *searchpath,char *dslp)
{
 unsigned int len;
 char filemask[MAX_PATHNAMELEN];

 if(dslp && *dslp){
  if(!searchpath || !searchpath[0])
   searchpath=&allscanstring[0];
  do{
   len=0;
   if(searchpath[1]!=':'){
    len=pds_strcpy(filemask,"d:");
    if(searchpath[0]!=PDS_DIRECTORY_SEPARATOR_CHAR){
     len+=pds_strcpy(&filemask[len],PDS_DIRECTORY_SEPARATOR_STR);
     len+=pds_strcpy(&filemask[len],"*.*");
     len+=pds_strcpy(&filemask[len],PDS_DIRECTORY_SEPARATOR_STR);
    }
   }
   pds_strcpy(&filemask[len],searchpath);
   filemask[0]=dslp[0];
   if(loaddir_scansubdirs(psi,filemask)==KEY_ESC)
    break;
   dslp++;
  }while(*dslp);
 }else{
  loaddir_scansubdirs(psi,searchpath);
 }
}

//***************************************************************************
void playlist_loaddir_buildbrowser(struct playlist_side_info *psi)
{
 char *filenamesp;
 unsigned int savedrive;
 struct playlist_entry_info *pei;
 char savedir[MAX_PATHNAMELEN];

 pds_dir_save(&savedrive,savedir);

 playlist_clear_side(psi);
 playlist_enable_side(psi);

 filenamesp=psi->filenameslastp;
 pei=psi->firstentry;
 if((desktopmode&DTM_EDIT_DRIVES) && (loaddir_lastvaliddrive>LOADDIR_FIRSTDRV_BROWSER))
  pei=browser_get_drives(pei,&filenamesp);

 pds_setdrive(psi->currdrive);
 if(psi->currdrive!=pds_getdrive())
  goto end_bb;
 pds_chdir(psi->currdir);
 //if(pds_chdir(psi->currdir)<0) // this is not good for CDW
  //goto end_bb;

 pei=browser_get_directories(pei,psi,&filenamesp);
 pei=browser_get_files_from_dir(pei,psi,&filenamesp); // load all supported filetypes
 if(pei>psi->firstentry)
  psi->lastentry=pei-1;
 playlist_order_dft(psi);        // order directories & filenames
 pei=cdw_get_allfiles(pei,&filenamesp,psi->currdrive,"*.*"); // get all cdw files

end_bb:
 if(pei<=psi->firstentry){
  funcbit_disable(psi->editsidetype,PLT_ENABLED);
  return;
 }
 psi->lastentry=pei-1;
 psi->filenameslastp=filenamesp;
 playlist_search_firstsong(psi);
 pds_dir_restore(savedrive,savedir);
}

static struct playlist_entry_info *browser_get_drives(struct playlist_entry_info *pei,char **filenamesfieldp)
{
 drive_info_t *di=&drive_infos[LOADDIR_FIRSTDRV_BROWSER];
 char *fnp=*filenamesfieldp;
 unsigned int i;

 for(i=LOADDIR_FIRSTDRV_BROWSER;i<=loaddir_lastvaliddrive;i++){
  if(di->type!=DRIVE_TYPE_NONE){
   pei->entrytype=DFT_DRIVE;
   pei->filename=fnp;
   fnp+=pds_strcpy(fnp,di->drivename);
#ifdef SHOW_DRIVE_VOLUME_NAMES
   if(di->volumename[0]){
    *fnp++=' ';
    fnp+=pds_strncpy(fnp,di->volumename,8);
   }
#endif
   switch(di->type){
    case DRIVE_TYPE_FLOPPY :pei->id3info[I3I_DFT_STORE]="<FLOPPY>";break;
    case DRIVE_TYPE_CD     :pei->id3info[I3I_DFT_STORE]="<CD_ROM>";break;
    case DRIVE_TYPE_NETWORK:pei->id3info[I3I_DFT_STORE]="<NETWRK>";break;
    default:pei->id3info[I3I_DFT_STORE]=DFTSTR_DRIVE;break;
   }
   *fnp++=0;
   pei++;
  }
  di++;
 }
 *filenamesfieldp=fnp;
 return pei;
}

static struct playlist_entry_info *browser_get_directories(struct playlist_entry_info *pei,struct playlist_side_info *psi,char **filenamesfieldp)
{
 unsigned int error,len;
 struct pds_find_t ffblk;
 char *fnp,path[MAX_PATHNAMELEN],searchname[MAX_PATHNAMELEN];

 len=pds_strcpy(path,psi->currdir);
 if(path[len-1]!=PDS_DIRECTORY_SEPARATOR_CHAR)
  pds_strcpy(&path[len],PDS_DIRECTORY_SEPARATOR_STR);

 fnp=*filenamesfieldp;

 if(len>3){ // we assume this is not the root directory (more than "c:\")
  pei->entrytype=DFT_UPDIR;
  pei->id3info[I3I_DFT_STORE]=DFTSTR_UPDIR;
  pei->filename=fnp;
  fnp+=pds_strcpy(fnp,path);
  fnp+=pds_strcpy(fnp,"..")+1;
  pei++;
 }

 len=pds_strcpy(searchname,path);
 pds_strcpy(&searchname[len],"*.*");

 error=pds_findfirst(searchname,_A_SUBDIR,&ffblk);
 while(!error && (pei<=psi->endentry) && (fnp<psi->filenamesendp)){
  if((ffblk.attrib&_A_SUBDIR) && pds_strcmp(".",ffblk.name)!=0 && pds_strcmp("..",ffblk.name)!=0){
   pei->entrytype=DFT_SUBDIR;
   pei->id3info[I3I_DFT_STORE]=DFTSTR_SUBDIR;
   pei->filename=fnp;
   fnp+=pds_strcpy(fnp,path);
   fnp+=pds_strcpy(fnp,ffblk.name)+1;
   pei++;
  }
  error=pds_findnext(&ffblk);
 }
 pds_findclose(&ffblk);
 *filenamesfieldp=fnp;
 return pei;
}

static struct playlist_entry_info *browser_get_files_from_dir(struct playlist_entry_info *pei,
              struct playlist_side_info *psi,char **filenamesfieldp)
{
 unsigned int error,len;
 struct pds_find_t ffblk;
 char *fnp,path[MAX_PATHNAMELEN],searchname[MAX_PATHNAMELEN];

 len=pds_strcpy(path,psi->currdir);
 if(path[len-1]!=PDS_DIRECTORY_SEPARATOR_CHAR)
  pds_strcpy(&path[len],PDS_DIRECTORY_SEPARATOR_STR);

 len=pds_strcpy(searchname,path);
 pds_strcpy(&searchname[len],"*.*");

 fnp=*filenamesfieldp;

 error=pds_findfirst(searchname,_A_NORMAL,&ffblk);
 while(!error && (pei<=psi->endentry) && (fnp<psi->filenamesendp)){
  if(!(ffblk.attrib&(_A_SUBDIR|_A_VOLID))){
   if(playlist_loadlist_get_header_by_ext(pei,psi,ffblk.name) || mpxplay_infile_check_extension(ffblk.name)){
    pei->filename=fnp;
    fnp+=pds_strcpy(fnp,path);
    fnp+=pds_strcpy(fnp,ffblk.name)+1;
    pei++;
   }
  }
  error=pds_findnext(&ffblk);
 }
 pds_findclose(&ffblk);
 *filenamesfieldp=fnp;
 return pei;
}

struct playlist_side_info *playlist_loaddir_changedir(struct playlist_side_info *psi,unsigned long head)
{
 struct playlist_entry_info *pei=psi->editorhighline;
 char lastdir[MAX_PATHNAMELEN];

 lastdir[0]=0;
 if(head==DFT_ROOTDIR){
  pds_chdir(PDS_DIRECTORY_SEPARATOR_STR);
 }else{
  if(head==DFT_DRIVE){
   int drive;
   playlist_loaddir_get_driveinfos();
   loaddir_get_currdrivename(psi->currdrive,lastdir);
   drive=pds_getdrivenum_from_path(pei->filename);
   if(drive<0)
    return psi;
   pds_setdrive(drive);
   pds_getcwd(psi->currdir);
   if(!psi->currdir[0]){
    pds_chdir(PDS_DIRECTORY_SEPARATOR_STR);
    pds_getcwd(psi->currdir);
   }
   psi->currdrive=pds_getdrivenum_from_path(psi->currdir);
   if(psi->currdrive!=drive)
    return psi;
  }else{
   if(head==DFT_SUBDIR){
    if(pei->filename){
     unsigned int len=pds_strcpy(lastdir,pei->filename);
     len+=pds_strcpy(&lastdir[len],PDS_DIRECTORY_SEPARATOR_STR);
     len+=pds_strcpy(&lastdir[len],"..");
     pds_chdir(pei->filename);
    }
   }else{
    if(head==DFT_UPDIR){
     pds_getcwd(lastdir);
     pds_chdir("..");
    }
   }
  }
 }

 pds_getcwd(psi->currdir);
 //fprintf(stdout,"\"%s\" \"%s\"\n",lastdir,psi->currdir);
 psi->currdrive=pds_getdrivenum_from_path(psi->currdir);

 playlist_loaddir_buildbrowser(psi);
 playlist_id3list_load(psi->mvp,psi);
 playlist_search_lastdir(psi,lastdir);
 return psi;
}

void playlist_loaddir_search_paralell_dir(struct playlist_side_info *psi,int step)
{
 unsigned int found;
 struct playlist_entry_info *pei;
 char lastdir[MAX_PATHNAMELEN];

 pds_strcpy(lastdir,psi->currdir);
 playlist_loaddir_changedir(psi,DFT_UPDIR);
 if(pds_stricmp(lastdir,psi->currdir)!=0){
  found=0;
  pei=psi->editorhighline;
  pei+=step;
  while((step==1 && pei<=psi->lastentry) || (step==-1 && pei>=psi->firstentry)){
   if(pei->entrytype==DFT_SUBDIR){
    psi->editorhighline=pei;
    playlist_loaddir_changedir(psi,DFT_SUBDIR);
    found=1;
    break;
   }
   pei+=step;
  }
  if(!found)
   playlist_loaddir_changedir(psi,DFT_SUBDIR);
 }
 playlist_chkfile_start_norm(psi,0);
}

//-----------------------------------------------------------------------
static display_textwin_button_t drive_buttons[LOADDIR_MAX_DRIVES*2+1];
static char drive_button_str[LOADDIR_MAX_DRIVES*(sizeof(drive_info_t)+2)+sizeof("9:playlist")+sizeof("8:jukebox")+32];

static unsigned int loaddir_selectdrive_buildbuttons(struct mainvars *mvp,unsigned int side,display_textwin_button_t **selected_button)
{
 struct playlist_side_info *psi=mvp->psi0+side;
 display_textwin_button_t *bt=&drive_buttons[0];
 drive_info_t *di=&drive_infos[LOADDIR_FIRSTDRIVE];
 char *dbs=&drive_button_str[0];
 unsigned int i;

 playlist_loaddir_get_driveinfos();

 for(i=LOADDIR_FIRSTDRIVE;i<=loaddir_lastvaliddrive;i++){
  if(di->type!=DRIVE_TYPE_NONE){
   char *vol,drivenum,isdrivechar;
   unsigned int len;
   bt->text=dbs;
   *dbs++=' ';
   dbs+=pds_strcpy(dbs,di->drivename);
   *dbs++=' ';
   if(di->volumename[0])
    vol=&di->volumename[0];
   else{
    switch(di->type){
     case DRIVE_TYPE_FLOPPY :vol="<FLOPPY>";break;
     case DRIVE_TYPE_CD     :vol="<CD_ROM>";break;
     case DRIVE_TYPE_NETWORK:vol="<NETWRK>";break;
     default:vol=DFTSTR_DRIVE;break;
    }
   }

   len=pds_strcpy(dbs,vol);
   dbs+=len;
   do{
    *dbs++=' ';
   }while(++len<9); // min length of drive volume names (adds spaces to end)
   *dbs=0;

   drivenum=di->drivename[0];
   if((drivenum>='A') && (drivenum<='Z')){
    drivenum-='A';
    isdrivechar=1;
   }else if ((drivenum>='a') && (drivenum<='z')){
    drivenum-='a';
    isdrivechar=1;
   }else // '0'-'7'
    isdrivechar=0;

   if(drivenum==psi->currdrive)
    *selected_button=bt;

   if(isdrivechar){
    bt->extkey=newfunc_keyboard_char_to_extkey('A'+drivenum);
    bt++;
    bt->text=dbs;
    bt->extkey=newfunc_keyboard_char_to_extkey('a'+drivenum);
   }else
    bt->extkey=newfunc_keyboard_char_to_extkey(drivenum);

   bt++;
   dbs++;
  }
  di++;
 }
 if(!(psi->psio->editsidetype&PLT_DOOMQUEUE)){
  bt->text=" 8: jukebox  ";
  bt->extkey=newfunc_keyboard_char_to_extkey('8');
  bt++;
  bt->text=" 9: playlist ";
  bt->extkey=newfunc_keyboard_char_to_extkey('9');
  bt++;
 }

 if(bt==(&drive_buttons[0]))
  return 0;

 bt->text="";
 bt->extkey=KEY_ESC;
 bt++;
 bt->text=NULL;
 bt->extkey=0;

 return 1;
}

// change [sublist] entries to [playlist]
static void loaddir_selectdrive_sublist_to_playlist(struct playlist_side_info *psi)
{
 if(psi->editsidetype&PLT_DIRECTORY){
  struct playlist_entry_info *pei,*pei_end;
  pei=psi->firstentry;
  pei_end=psi->firstsong;
  do{
   if(pei->entrytype==DFT_SUBLIST){
    pei->entrytype=DFT_PLAYLIST;
    if(pds_strcmp(pei->id3info[I3I_DFT_STORE],DFTSTR_SUBLIST)==0)
     pei->id3info[I3I_DFT_STORE]=DFTSTR_PLAYLIST;
   }
   pei++;
  }while(pei<=pei_end);
 }
}

static void loaddir_selectdrive_playlist_to_sublist(struct playlist_side_info *psi)
{
 if(psi->editsidetype&PLT_DIRECTORY){
  struct playlist_entry_info *pei,*pei_end;
  pei=psi->firstentry;
  pei_end=psi->firstsong;
  do{
   if(pei->entrytype==DFT_PLAYLIST){
    pei->entrytype=DFT_SUBLIST;
    if(pds_strcmp(pei->id3info[I3I_DFT_STORE],DFTSTR_PLAYLIST)==0)
     pei->id3info[I3I_DFT_STORE]=DFTSTR_SUBLIST;
   }
   pei++;
  }while(pei<=pei_end);
 }
}

static void loaddir_selectdrive_keycheck(struct playlist_side_info *psi,unsigned int extkey)
{
 display_textwin_button_t *bt=&drive_buttons[0];
 if(extkey==KEY_ESC)
  return;
 while(bt->extkey){
  if(bt->extkey==extkey){
   char drive=newfunc_keyboard_extkey_to_char(extkey);
   if(drive!=0xff){ // found extkey
    struct mainvars *mvp=psi->mvp;
    unsigned int savedrive;
    switch(drive){
     case '8': // jukebox queue
      if(!(psi->editsidetype&PLT_DOOMQUEUE) && !(psi->psio->editsidetype&PLT_DOOMQUEUE)){
       psi->editsidetype=PLT_DOOMQUEUE;
       playlist_clear_side(psi);
       playlist_disable_side_full(psi);
       mvp->psip=psi;
       mvp->aktfilenum=psi->firstsong-1;
       mvp->newfilenum=NULL;
       loaddir_selectdrive_sublist_to_playlist(psi->psio);
       playlist_jukebox_set(mvp);
      }
      break;
     case '9': // normal playlist
      if(((psi->editsidetype&PLT_DIRECTORY) || (psi->editsidetype&PLT_DOOMQUEUE)) && !(psi->psio->editsidetype&PLT_DOOMQUEUE)){
       psi->editsidetype=0;
       playlist_clear_side(psi);
       playlist_disable_side_full(psi);
       loaddir_selectdrive_sublist_to_playlist(psi->psio);
       mvp->psil=psi;
       playlist_jukebox_set(mvp);
      }
      break;
     default: // drive
      if((drive>='0') && (drive<='7')){
       // reserved
       break;
      }
      if((drive>='a') && (drive<='z'))
       drive-='a';
      else
       drive-='A';
      if(!(psi->editsidetype&PLT_DIRECTORY)){
       loaddir_selectdrive_playlist_to_sublist(psi->psio);
       if(!(psi->psio->editsidetype&PLT_DIRECTORY))
        mvp->psil=psi->psio;
       psi->editsidetype=PLT_DIRECTORY;
      }
      psi->sublistlevel=0;
      if((psi!=mvp->psie) && (psi->psio->editsidetype&PLT_DIRECTORY) && !psi->psio->sublistlevel)
       savedrive=pds_getdrive();
      pds_setdrive(drive);
      pds_getcwd(psi->currdir);
      if(!psi->currdir[0]){
       pds_chdir(PDS_DIRECTORY_SEPARATOR_STR);
       pds_getcwd(psi->currdir);
      }
      psi->currdrive=pds_getdrivenum_from_path(psi->currdir);
      if(psi->currdrive==drive){
       playlist_loaddir_buildbrowser(psi);
       playlist_id3list_load(mvp,psi);
       playlist_chkfile_start_norm(psi,0);
       playlist_jukebox_set(mvp);
      }else{
       psi->currdrive=drive;
       pds_strcpy(psi->currdir,"C: ");
       psi->currdir[2]=PDS_DIRECTORY_SEPARATOR_CHAR;
       psi->currdir[0]='A'+drive;
       playlist_disable_side_full(psi);
       mpxplay_timer_addfunc(loaddir_select_drive_retry,psi,MPXPLAY_TIMERTYPE_WAKEUP,0);
      }
      if((psi!=mvp->psie) && (psi->psio->editsidetype&PLT_DIRECTORY) && !psi->psio->sublistlevel)
       pds_setdrive(savedrive);
      break;
    }
    refdisp|=RDT_EDITOR;
    if(psi==mvp->psip)
     refdisp|=RDT_BROWSER;
   }
   break;
  }
  bt++;
 }
}

void playlist_loaddir_select_drive(struct mainvars *mvp,unsigned int side)
{
 display_textwin_button_t *selected_button=NULL;
 char msg[64];

 if(loaddir_selectdrive_buildbuttons(mvp,side,&selected_button)){
  unsigned int flags=TEXTWIN_FLAG_MSGCENTERALIGN|TEXTWIN_FLAG_VERTICALBUTTONS|TEXTWIN_FLAG_NOWINMINSIZE;
  void *tw;
  sprintf(msg,"Choose %s drive:",((side)? "RIGHT":"LEFT"));
  tw=display_textwin_allocwindow_items(flags," Drive letter ",loaddir_selectdrive_keycheck,(mvp->psi0+side));
  display_textwin_additem_msg_alloc(tw,flags,0,-1,msg);
  display_textwin_additem_buttons(tw,flags,0,-1,drive_buttons,selected_button);
  display_textwin_openwindow_items(tw,0,0,0);
 }else
  display_textwin_openwindow_errormessage("Cannot build drive infos!");
}

static void loaddir_select_drive_retry(struct playlist_side_info *psi)
{
 struct mainvars *mvp=psi->mvp;
 unsigned int side=psi-mvp->psi0;
 display_textwin_button_t *selected_button=NULL;
 char msg[80];

 if(loaddir_selectdrive_buildbuttons(mvp,side,&selected_button)){
  unsigned int flags=TEXTWIN_FLAG_MSGCENTERALIGN|TEXTWIN_FLAG_VERTICALBUTTONS|TEXTWIN_FLAG_NOWINMINSIZE|TEXTWIN_FLAG_ERRORMSG;
  void *tw;
  sprintf(msg,"\nCouldn't read drive!\n\nChoose %s drive:",((side)? "RIGHT":"LEFT"));
  tw=display_textwin_allocwindow_items(flags," Drive letter ",loaddir_selectdrive_keycheck,(mvp->psi0+side));
  display_textwin_additem_msg_alloc(tw,flags,0,-1,msg);
  display_textwin_additem_buttons(tw,flags,0,-1,drive_buttons,selected_button);
  display_textwin_openwindow_items(tw,0,0,0);
 }else
  display_textwin_openwindow_errormessage("Cannot build drive infos!");
}

static char makedir_name[128];

static void loaddir_makedir_do(struct playlist_side_info *psi)
{
 unsigned int len;
 struct playlist_entry_info pei_tmp;
 char strtmp[MAX_PATHNAMELEN];

 if(!makedir_name[0])
  return;

 pds_sfn_limit(makedir_name);

 len=pds_strcpy(strtmp,psi->currdir);
 if(strtmp[len-1]!=PDS_DIRECTORY_SEPARATOR_CHAR)
  len+=pds_strcpy(&strtmp[len],PDS_DIRECTORY_SEPARATOR_STR);
 pds_strcpy(&strtmp[len],makedir_name);

 if(pds_mkdir(strtmp)<0){
  display_textwin_openwindow_errormessage("Couldn't create directory!");
  return;
 }else{
  struct playlist_entry_info *pei_pos;
  pds_memset(&pei_tmp,0,sizeof(struct playlist_entry_info));
  pei_tmp.filename=&strtmp[0];
  pei_tmp.entrytype=DFT_SUBDIR;
  pei_tmp.id3info[I3I_DFT_STORE]=DFTSTR_SUBDIR;
  playlist_editlist_addfile_one(NULL,psi,&pei_tmp,NULL,EDITLIST_MODE_ALL);
  pei_pos=playlist_order_entry(psi,psi->lastentry);
  playlist_editorhighline_set(psi,pei_pos);
  playlist_search_firstsong(psi);
  if((psi->psio->editsidetype&PLT_DIRECTORY) && !psi->sublistlevel && !psi->psio->sublistlevel && (pds_stricmp(psi->currdir,psi->psio->currdir)==0)){
   playlist_editlist_addfile_one(NULL,psi->psio,&pei_tmp,NULL,EDITLIST_MODE_ALL);
   playlist_order_entry(psi->psio,psi->psio->lastentry);
   playlist_search_firstsong(psi->psio);
  }
  refdisp|=RDT_EDITOR;
 }
}

#define MAKEDIR_WINSIZE_X 40

void playlist_loaddir_makedir_open(struct playlist_side_info *psi)
{
 void *tw;

 if((psi->editsidetype&PLT_DIRECTORY) && !psi->sublistlevel){
  makedir_name[0]=0;
  tw=display_textwin_allocwindow_items(TEXTWIN_FLAG_MSGCENTERALIGN|TEXTWIN_FLAG_CONFIRM|TEXTWIN_FLAG_NOWINMINSIZE," Make directory ",loaddir_makedir_do,psi);
  display_textwin_additem_msg_static(tw,0,0,-1," Create the directory");
  display_textwin_additem_editline(tw,TEXTWIN_FLAG_MSGCENTERALIGN,0,-1,MAKEDIR_WINSIZE_X,&makedir_name[0],120);
  display_textwin_openwindow_items(tw,0,0,0);
 }else
  display_textwin_openwindow_errormessage("Cannot create directory here (in playlist)!");
}
