//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2015 by PDSoft (Attila Padar)                *
//*                http://mpxplay.sourceforge.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:skip in playlist

//#define MPXPLAY_USE_DEBUGF 1
#define MPXPLAY_DEBUG_OUTPUT stdout

#include "mpxplay.h"
#include "control\cntfuncs.h"
#include "diskdriv\diskdriv.h"
#include "display\display.h"
#include "mpxinbuf.h"

extern unsigned int playcontrol,playreplay,playrand,intsoundcontrol,intsoundconfig;
extern unsigned int refdisp,desktopmode,mpxplay_programcontrol;

unsigned int playlist_skip(struct mainvars *mvp)
{
 funcbit_disable(playcontrol,PLAYC_ABORTNEXT);

 if(!mvp->newfilenum)
  playlist_get_newfilenum(mvp);

 if(mvp->newfilenum){
  //if(mvp->psie->editorhighline==mvp->aktfilenum)
  // playlist_editorhighline_set(mvp->psie,mvp->newfilenum);
  mvp->aktfilenum=mvp->newfilenum;
  mvp->newfilenum=NULL;
  return 1;
 }
 return 0;
}

struct playlist_entry_info *playlist_get_newfilenum(struct mainvars *mvp)
{
 struct playlist_side_info *psi = mvp->psip;
 struct mpxpframe_s *frp;
 struct playlist_entry_info *pei, *newsong, *last_failed_entry = NULL;
 int loc_playrand;
 char sout[128];

 if(!psi->firstentry || (psi->lastentry<psi->firstentry))
  return NULL;

 display_clear_timed_message();

 funcbit_disable(playcontrol,PLAYC_ABORTNEXT);
 loc_playrand = playrand;
 pei = (mvp->newfilenum)? mvp->newfilenum : mvp->aktfilenum;
 newsong = mvp->newsong;

 if(pei<(psi->firstsong-1)) // ???
  pei=psi->firstsong-1;
 else if(pei>psi->lastentry)
  pei=psi->lastentry;

 if(newsong){
  if(loc_playrand)
   playlist_randlist_setsignflag(newsong);
  if(newsong==pei)
   pei--;
  mvp->direction=newsong-pei;
  loc_playrand=0;
  mvp->newsong=NULL;
 }else{
  if(mvp->step!=0)
   mvp->direction=mvp->step;
  else if(mvp->direction==0)
   mvp->direction=1;
 }
 mvp->step=0;

 do{
  pei+=mvp->direction;
  if(mvp->direction>=0){
   if(loc_playrand)
    pei=playlist_randlist_getnext(psi);
   if((pei>=psi->firstentry) && (pei<=psi->lastentry))
    mvp->direction=1;              // corrects direction > 1
   else{
    if((psi->editloadtype&PLL_JUKEBOX) && (psi!=mvp->psie) && (pei>(psi->firstsong+1)))
     mvp->direction=-1;
    else{
     if((playreplay&REPLAY_LIST) && mvp->foundfile)
      pei=psi->firstsong;
     else
      pei=NULL;
     mvp->foundfile=0;
    }
   }
  }else{
   if(loc_playrand)
    pei=playlist_randlist_getprev(pei);
   if(pei>=psi->firstentry)
    mvp->direction=-1;             // corrects direction < -1
   else{
    if((playreplay&REPLAY_LIST) && mvp->foundfile)
     pei=psi->lastentry;
    else
     pei=NULL;
    mvp->foundfile=0;
   }
  }
  if((pei>=psi->firstsong) && (pei<=psi->lastentry) && (!(psi->editloadtype&PLL_FILTERED) || !(pei->infobits&PEIF_FILTEROUT))){
   if((intsoundcontrol&INTSOUND_DECODER) || (pei->infobits&PEIF_INDEXED)){
    int retcode = playlist_chkentry_get_onefileinfos_entry(psi,pei);
    if(pei->entrytype>=DFT_AUDIOFILE)
     break;
    if(retcode == MPXPLAY_ERROR_DISKDRIV_OPENMODE) // FIXME: hack for DTV + crossfade (signed as valid entry)
     break;
    if(retcode == MPXPLAY_ERROR_DISKDRIV_CONNECT_TERMINATED){
     funcbit_enable(playcontrol,PLAYC_ABORTNEXT);
     break;
    }
    sprintf(sout,"Checking next file (%2d/%d)",pei-psi->firstsong+1,psi->lastentry-psi->firstsong+1);
    display_message(0,0,sout);
    sout[0]=0;
    display_message(1,0,sout);
    last_failed_entry=pei;
   }else{
    if((pei->entrytype>=DFT_AUDIOFILE) || (pei->entrytype==DFT_NOTCHECKED))
     break;
   }
  }

  if(!mpxplay_control_keyboard_get_topfunc() && pds_wipeout_by_extkey(KEY_ESC))
   funcbit_enable(playcontrol,PLAYC_ABORTNEXT);

 }while(pei && (mvp->direction!=0) && !funcbit_test(playcontrol,PLAYC_ABORTNEXT));

 if(funcbit_test(playcontrol,PLAYC_ABORTNEXT))
  pei=NULL;

 if((pei<psi->firstsong) || (pei>psi->lastentry))
  pei=NULL;

 frp = mvp->fr_primary;
 if(pei){
  if(!(desktopmode&DTM_EDIT_MAGNETFOLLOWSKIP) || (psi->editorhighline==mvp->aktfilenum) || (psi->editorhighline==mvp->newfilenum))
   playlist_editorhighline_set(psi,pei);
  mvp->newfilenum=pei;
  playlist_skiplist_reset_loadnext(mvp);
  if(playrand && newsong)
   mvp->direction=0;
  if(!(frp->filetype & HFT_FILE_ALL) && (mvp->aktfilenum >= psi->firstsong)) // !!!
   mvp->aktfilenum = pei;
 }else{
  if(loc_playrand && (mvp->direction<0) && !mvp->newfilenum) // push back
   playlist_randlist_pushq(psi,mvp->aktfilenum);             // current file
  //if((mvp->direction < 0) && (frp->filetype & HFT_FILE_ALL) && !(frp->filetype & HFT_STREAM)) // seek to bof
  // mvp->seek_absolute = frp->index_start + 1;
  mvp->direction=mvp->seek_relative=0; // TODO: check
  funcbit_disable(playcontrol,PLAYC_CONTINUOUS_SEEK);
  refdisp|=RDT_EDITOR;
 }
 //mvp->direction=mvp->seek_relative=0;  // TODO: check
 if(intsoundcontrol&INTSOUND_DECODER)
  clear_message();
 if(last_failed_entry){
  snprintf(sout,sizeof(sout),"Couldn't play file: %s",pds_getfilename_any_from_fullname(last_failed_entry->filename));
  display_timed_message(sout);
 }

 return pei;
}

//--------------------------------------------------------------------------
//gray-'/' & '*' ; alt-pgup & alt-pgdn
struct playlist_entry_info *playlist_get_nextalbum(struct playlist_entry_info *pei,struct playlist_side_info *psi,int step,unsigned int steplevel,unsigned int ring)
{
 unsigned int lcount,actsubdirs,cutlevel;
 char *pointer,actpath[MAX_PATHNAMELEN],newpath[MAX_PATHNAMELEN];//,sout[100];

 if(psi->lastentry<psi->firstsong)
  return NULL;

 if(step==-1){
  if(pei<=psi->firstsong){
   if(ring)
    pei=psi->lastentry;
   else
    return NULL;
  }else
   pei--;
 }else
  if(pei<psi->firstsong)
   return psi->firstsong;
 pds_strcpy(actpath,pei->filename);

 if(steplevel){
  pointer=&actpath[0];
  actsubdirs=0;
  do{
   pointer=pds_strchr(pointer,PDS_DIRECTORY_SEPARATOR_CHAR);
   if(!pointer)
    break;
   pointer++;
   actsubdirs++;
  }while(1);

  if(steplevel>actsubdirs)
   return NULL;

  lcount=0;
  do{
   pointer=pds_strrchr(actpath,PDS_DIRECTORY_SEPARATOR_CHAR);
   if(!pointer)
    break;
   *pointer=0;
   lcount++;
  }while(lcount<=steplevel);

  cutlevel=actsubdirs-steplevel;
 }else{
  pointer=pds_strrchr(actpath,PDS_DIRECTORY_SEPARATOR_CHAR);
  if(pointer<=(&actpath[0]))
   return NULL;
  *pointer=0;
 }

 //sprintf(sout,"ACT: %s %d %d",actpath,cutlevel,actsubdirs);
 //pds_textdisplay_printf(sout);

 pei-=step;
 do{
  pei+=step;
  pds_strcpy(newpath,pei->filename);
  if(steplevel){
   pointer=&newpath[0];
   lcount=0;
   do{
    char *next=pds_strchr(pointer,PDS_DIRECTORY_SEPARATOR_CHAR);
    if(!next)
     break;
    pointer=next;
    lcount++;
    if(lcount>=cutlevel)
     break;
    pointer++;
   }while(1);
  }else{
   pointer=pds_strrchr(newpath,PDS_DIRECTORY_SEPARATOR_CHAR);
   if(!pointer)
    pointer=&newpath[0];
  }
  *pointer=0;
  //sprintf(sout,"new: %s %d",newpath,lcount);
  //pds_textdisplay_printf(sout);
 }while((pds_utf8_stricmp(actpath,newpath)==0) && (pei>=psi->firstsong) && (pei<=psi->lastentry));

 if(step==-1){
  //if(steplevel && pei<psi->firstsong)
  // return NULL;
  pei++;
 }

 if(pei>psi->lastentry && !ring)
  return NULL;
 //sprintf(sout,"END: %s ",pei->filename);
 //pds_textdisplay_printf(sout);
 return pei;
}

//------------------------------------------------------------------------
void playlist_newsong_enter(struct mainvars *mvp,struct playlist_side_info *psi)
{
 struct playlist_entry_info *pei=psi->editorhighline;
 unsigned long oldentrytype=pei->entrytype;
 struct mpxpframe_s *frp1 = mvp->fr_primary->fro;
 unsigned int loadnext_ok = 0;
 int retcode = MPXPLAY_ERROR_OK;

 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT, "playlist_newsong_enter BEGIN");

#ifndef __DOS__
 if( (mpxplay_programcontrol & (MPXPLAY_PROGRAMC_SYSTEMAPPOPEN_UNKNOWN|MPXPLAY_PROGRAMC_SYSTEMAPPOPEN_ALLFILES))
   && (GET_HFT(pei->entrytype)!=HFT_DFT)
   && pds_filename_get_extension(pei->filename)
   && (((desktopmode&DTM_MASK_COMMANDER)!=DTM_MASK_COMMANDER) || !playlist_loadlist_check_extension(pei->filename))
   && ((mpxplay_programcontrol & MPXPLAY_PROGRAMC_SYSTEMAPPOPEN_ALLFILES) || (!(mpxplay_programcontrol & MPXPLAY_PROGRAMC_AUTODETECTALWAYS) && ((retcode=mpxplay_infile_get_infilefuncs_by_ext(frp1,pei->mdds,pei->filename,MPXPLAY_INFILE_OPENMODE_PLAY)) < 0) && (retcode != MPXPLAY_ERROR_INFILE_FILETYPE) && !MPXPLAY_ERROR_IS_DISKDRIV(retcode)))
 ){
  mpxplay_system_opendefaultapplication(pei->filename);
  return;
 }
#endif

 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT, "playlist_newsong_enter 2. ret:%d", retcode);

 if(MPXPLAY_ERROR_IS_DISKDRIV(retcode))
  return;
 if(pei->entrytype==DFT_UNKNOWN)
  pei->entrytype=DFT_NOTCHECKED;

 if( (intsoundconfig&INTSOUND_DECODER) && (GET_HFT(pei->entrytype)!=HFT_DFT) && !mvp->cfi->usecrossfade && !(frp1->buffertype&PREBUFTYPE_LOADNEXT_MASK) // not opened already
  && ((mvp->aktfilenum < psi->firstsong) || !(pei->infobits&PEIF_INDEXED) || !(mvp->aktfilenum->infobits&PEIF_INDEXED) || (pds_strcmp(mvp->pei0->filename,pei->filename)!=0))) // isn't the same file with index(es)
 {
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT, "playlist_open_infile");
  retcode = playlist_open_infile(psi,pei,frp1);
  mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT, "playlist_open_infile END ret:%d", retcode);
  if((retcode == MPXPLAY_ERROR_OK) && ((frp1->filetype==HFT_FILE_EXT) || mpxplay_mpxinbuf_alloc(mvp,frp1))){
   mvp->newfilenum=pei;
   loadnext_ok=1;
  }
 }else
  retcode = playlist_chkentry_get_onefileinfos_entry(psi,pei);

 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT, "playlist_newsong_enter 3. ret:%d", retcode);

 // if(MPXPLAY_ERROR_IS_DISKDRIV(retcode))  // TODO: possible alternative
 if(retcode == MPXPLAY_ERROR_DISKDRIV_CONNECT_TERMINATED)
  return;

 if(GET_HFT(pei->entrytype)==HFT_DFT){
  playlist_change_sublist_or_directory(psi,pei->entrytype);
 }else{
//  if(loadnext_ok)  // TODO: check moved code
//   mvp->adone=ADONE_RESTART;
//  else
//   mvp->newsong=pei;
  if((mvp->psip!=psi) && ((psi->editloadtype&PLL_JUKEBOX) || !(psi->psio->editloadtype&PLL_JUKEBOX))){
   mvp->psip=psi;
   if(mvp->cfi->usecrossfade)
    mvp->aktfilenum=psi->firstsong-1;
   else
    mvp->aktfilenum=psi->editorhighline;
   playlist_randlist_clearall(psi);
   refdisp|=RDT_TABINFOS;
  }
  if(!(playcontrol&PLAYC_RUNNING)){
   crossfade_reset(mvp);
   funcbit_enable(playcontrol,(PLAYC_STARTNEXT|PLAYC_STARTFLAG));
  }
  if(!(playcontrol&PLAYC_HIGHSCAN))
   funcbit_enable(playcontrol,PLAYC_STARTFLAG);
  if(!mvp->foundfile && (oldentrytype==DFT_UNKNOWN)){
   playlist_chkentry_enable_entries(psi);
   playlist_chkfile_start_norm(psi,NULL);
  }
  if(loadnext_ok){
   funcbit_enable(frp1->buffertype,PREBUFTYPE_LOADNEXT_OK);
   mvp->adone=ADONE_RESTART;
  }else
   mvp->newsong=pei;
 }
 mpxplay_debugf(MPXPLAY_DEBUG_OUTPUT, "playlist_newsong_enter END");
}

void playlist_nextsong_select(struct mainvars *mvp,struct playlist_side_info *psi)
{
 struct playlist_entry_info *pei=psi->editorhighline;

 if(psi==mvp->psip)
  playlist_randlist_resetsignflag(mvp->newfilenum);

 if((mvp->newfilenum==pei) && MPXPLAY_IS_FILE_OPEN(mvp->fr_primary)){
   mvp->newfilenum=NULL;
 }else{
  playlist_chkentry_get_onefileinfos_entry(psi,pei);
  if((mvp->psip!=psi) && ((psi->editloadtype&PLL_JUKEBOX) || !(psi->psio->editloadtype&PLL_JUKEBOX))){
   struct playlist_entry_info *peia;
   struct mpxpframe_s *frp=mvp->fr_primary;
   long timempos;

   mvp->newfilenum=NULL;
   mvp->psip=psi;
   playlist_randlist_clearall(psi);

   timempos=(frp->allframes)? ((long)((float)frp->infile_infos->timemsec*(float)frp->frameNum/(float)frp->allframes)):-1;
   peia=playlist_search_filename(psi,mvp->pei0->filename,timempos,NULL,0);
   if(peia){
    mvp->aktfilenum=peia;
    playlist_pei0_set(mvp,peia,(EDITLIST_MODE_ID3|EDITLIST_MODE_INDEX));
    playlist_randlist_pushq(psi,peia);
    mpxplay_calculate_index_start_end(frp,mvp,peia);
   }else
    mvp->aktfilenum=psi->firstsong-1;
   refdisp|=RDT_TABINFOS;
  }
  if(pei->entrytype>=DFT_AUDIOFILE){
   if(!(playcontrol&PLAYC_RUNNING))
    mvp->newsong=pei;
   else{
    mvp->newfilenum=pei;
    playlist_randlist_setsignflag(pei);
   }
  }
 }
 playlist_skiplist_reset_loadnext(mvp);
}

void playlist_skiplist_reset_loadnext(struct mainvars *mvp)
{
 funcbit_disable(mvp->fr_primary->fro->buffertype,PREBUFTYPE_LOADNEXT_MASK); // !!! reset/reload next file
}
