//**************************************************************************
//*                     This file is part of the                           *
//*                      Mpxplay - audio player.                           *
//*                  The source code of Mpxplay is                         *
//*        (C) copyright 1998-2011 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: startup (restore the playing at the last position)

#include <mpxplay.h>
#include "control.h"
#include "cntfuncs.h"
#include "diskdriv\diskdriv.h"
#include "decoders\decoders.h"

#define STARTUP_FLAG_LOAD    1
#define STARTUP_FLAG_SAVE    2
#define STARTUP_FLAG_CMOS    4
#define STARTUP_FLAG_RESDIR  8 // restore directory and song-pos at non-playlist mode
#define STARTUP_FLAG_2SIDES 16 // restore both editorsides with all tabs

#define CMOS_SAVE_REFRESH 2 // in secs

//control.c
extern struct mainvars mvps;
extern char *drivescanletters;
extern unsigned int su_startupenabled,playlistload;
extern unsigned int intsoundconfig,intsoundcontrol;
extern unsigned int playcontrol,playstartsong;
extern int playstartlist,playstartpercent,playstartframe,playstartmsec;
extern int control_startup_type_override;
extern char *playstarttime;
extern mpxp_uint32_t mpxplay_playlistcontrol;

static unsigned int su_startuptype,su_oldlisttype;
static unsigned long su_oldsongnum,su_oldtimempos;
static char su_orilistname[MAX_PATHNAMELEN],su_oldsongname[MAX_PATHNAMELEN];

#ifdef __DOS__
static void shortdelay(val)
{
 while(--val){}
}
#endif

static void mpxplay_control_startup_savetocmos(struct mainvars *mvp)
{
#ifdef __DOS__
 struct mpxpframe_s *frp0=mvp->frp0;
 struct playlist_side_info *psip=mvp->psip;
 long index_pos=frp0->frameNum-frp0->index_start;
 unsigned long framenum=((mvp->adone==ADONE_EOF) || (index_pos<100))? 0:(index_pos-10);
 unsigned long percent=framenum*100/frp0->index_len;      // 7 bits (song position in %)
 unsigned long filenum=(((mvp->adone==ADONE_EOF) && (mvp->aktfilenum==psip->lastentry)) || (mvp->aktfilenum<psip->firstsong))? 0:(mvp->aktfilenum-psip->firstsong+1);
 unsigned long listnum=(playstartlist>=0)? (playstartlist&0x7):0; // 3 bits
 unsigned int intsoundcntrl_save;

 MPXPLAY_INTSOUNDDECODER_DISALLOW;
 outp(0x70,1);
 shortdelay(1); // ???
 outp(0x71,filenum&0xff);                           // 8 bits filenum
 outp(0x70,3);
 shortdelay(1); // ???
 if(mpxplay_control_fastlist_enabled()){ // filenum: 8+6=14 bits
  outp(0x71,((filenum>>8)&0x3f)|((listnum&0x03)<<6));// 6 (higher) bits filenum & 2 (lower) bits listnum
  outp(0x70,5);
  shortdelay(1); // ???
  outp(0x71,(percent&0x7f)|((listnum&0x04)<<(7-2))); // 7 (lower) bits percent & 1 (higher) bit listnum
 }else{                                  // filenum: 8+8+1=17 bits
  outp(0x71,((filenum>>8)&0xff));                    // 8 bits filenum
  outp(0x70,5);
  shortdelay(1); // ???
  outp(0x71,(percent&0x7f)|((filenum>>(16-7))&0x80)); // 7 (lower) bits percent & 1 (higher) bit filenum
 }
 MPXPLAY_INTSOUNDDECODER_ALLOW;
#endif
}

static void mpxplay_control_startup_loadfromcmos_listnum(void)
{
#ifdef __DOS__
 unsigned int c2,c3;

 if((playstartlist<0) && mpxplay_control_fastlist_enabled()){
  outp(0x70,3);
  shortdelay(3);
  c2=inp(0x71);
  outp(0x70,5);
  shortdelay(3);
  c3=inp(0x71);
  playstartlist=((c2>>6)&0x03)|((c3>>(7-2))&0x04);
 }
#endif
}

static void mpxplay_control_startup_loadfromcmos_songpos(struct mainvars *mvp)
{
#ifdef __DOS__
 struct playlist_side_info *psip=mvp->psip;
 unsigned int c1,c2,c3;

 if(!playstartsong){
  outp(0x70,1);
  shortdelay(3);
  c1=inp(0x71);
  outp(0x70,3);
  shortdelay(3);
  c2=inp(0x71);
  outp(0x70,5);
  shortdelay(3);
  c3=inp(0x71);
  if(mpxplay_control_fastlist_enabled())
   playstartsong=c1|((c2&0x3f)<<8);
  else
   playstartsong=c1|(c2<<8)|((c3&0x80)<<(16-7));
  if((psip->editloadtype&PLL_TYPE_LOAD) && playstartsong<=((psip->lastentry-psip->firstsong)+1)){
   if(!playstartframe && !playstartpercent && !playstarttime)
    playstartpercent=c3&0x7f;
   playcontrol|=PLAYC_STARTNEXT;
  }
 }
#endif
}

//-------------------------------------------------------------------------
static void startup_get_tabsfilename(char *strbuf)
{
 pds_getpath_from_fullname(strbuf,freeopts[OPT_PROGNAME]);
 pds_filename_assemble_fullname(strbuf,strbuf,"MPXPTABS.INI");
}

void mpxplay_control_startup_loadlastlist(void)
{
 struct mainvars *mvp=&mvps;
 unsigned int is_inputfile;
 void *fp;
 char fullname[MAX_PATHNAMELEN],oridirname[MAX_PATHNAMELEN],strtmp[MAX_STRLEN];

 if(control_startup_type_override>=0)
  su_startuptype=control_startup_type_override;
 else
  su_startuptype=su_startupenabled;

#ifndef __DOS__
 funcbit_disable(su_startuptype,STARTUP_FLAG_CMOS);
#endif

 if(!su_startuptype&STARTUP_FLAG_LOAD)
  goto end_su_ll;

 if(playlistload&PLL_FASTLIST){ // -pslf
  if(su_startuptype&STARTUP_FLAG_CMOS)
   mpxplay_control_startup_loadfromcmos_listnum();
  mpxplay_control_fastlist_searchfilename(mvp->psil,NULL);
 }

 is_inputfile=((playlistload&PLL_TYPE_LOAD) || drivescanletters || playlist_loadsub_getinputfile(mvp->psil))? 1:0;

 startup_get_tabsfilename(strtmp);
 fp=mpxplay_diskdrive_textfile_open(NULL,strtmp,(O_RDONLY|O_TEXT));
 if(fp){
  struct playlist_side_info *psi=NULL;
  while(mpxplay_diskdrive_textfile_readline(fp,strtmp,sizeof(strtmp)-1)){
   char *d=pds_strchr(strtmp,'='),*n;
   if(!d)
    continue;
   *d++=0;
   n=pds_strchr(strtmp,'_');
   if(n){
    *n++=0;
    if(pds_strcmp(strtmp,"OldListType")==0){
     unsigned int v=pds_atol(n),side=v/100,tab=v%100;
     if((side>=PLAYLIST_MAX_SIDES) || (!side && funcbit_test(mpxplay_playlistcontrol,MPXPLAY_PLAYLISTC_DIRBROWSER1))) // -db
      goto su_ll_skiptab;
     if(tab<mvp->editorsides_num_tabs[side]){
      playlist_editlist_tab_select(mvp,side,tab);
      psi=playlist_editlist_tabp_get(mvp,side);
      if((psi==mvp->psil) && (!(su_startuptype&STARTUP_FLAG_2SIDES) || is_inputfile)){
       su_oldlisttype=pds_atol(d); // ???
       psi->editloadtype=playlistload;
       goto su_ll_skiptab;
      }
      playlist_editlist_tab_clear(psi);
     }else{
      if(!(su_startuptype&STARTUP_FLAG_2SIDES))
       goto su_ll_skiptab;
      playlist_editlist_editside_chg(mvp,side); // normally not required
      psi=playlist_editlist_tab_add(mvp,EDITLIST_ADDTABMODE_BLANK|EDITLIST_ADDTABMODE_TOEND);
     }
     psi->editloadtype=pds_atol(d);
     continue;
su_ll_skiptab:
     psi=NULL;
    }else if(pds_strcmp(strtmp,"OriListName")==0){
     if(psi){
      if(psi->editloadtype&PLL_TYPE_LISTS){
       pds_strcpy(psi->savelist_filename,d);
       psi->savelist_type=playlist_savelist_gettype_from_filename(psi,psi->savelist_filename);
      }
     }else
      pds_strcpy(su_orilistname,d); // ???
    }else if(!psi)
     continue;
    else if(pds_strcmp(strtmp,"OrderKeys")==0)
     playlist_sortlist_set_orderkeys_from_hexa(psi,pds_atol16(d));
    else if(pds_strcmp(strtmp,"EditorHighline")==0)
     playlist_editorhighline_seek(psi,pds_atol(d),SEEK_SET);
    else if(pds_strcmp(strtmp,"OriDirName")==0)
     pds_strcpy(oridirname,d);
    else if(pds_strcmp(strtmp,"OldListName")==0){
     if((psi!=mvp->psil) || (!(su_startuptype&STARTUP_FLAG_CMOS) && !is_inputfile)){
      if(psi->editloadtype&PLL_TYPE_LOAD){ // reload last playlist
       funcbit_disable(psi->editsidetype,PLT_DIRECTORY);
       if(psi->editloadtype&PLL_SUBLISTS)
        playlist_loadsub_sublist_setlevels(psi,d);
       else if(psi->editloadtype&PLL_FASTLIST)
        mpxplay_control_fastlist_searchfilename(psi,d);
       else
        playlist_loadsub_setnewinputfile(psi,d,psi->editloadtype);
      }else if(d[0]){ //if(strtmp[0]){
       funcbit_enable(psi->editsidetype,PLT_DIRECTORY);
       if(psi->editloadtype&PLL_SUBLISTS)
        playlist_loadsub_sublist_setlevels(psi,d);
       playlist_loaddir_initdirside(psi,d,oridirname);
      }
     }else if((playlistload&PLL_FASTLIST) && (psi==mvp->psil)){
      if(!(su_startuptype&STARTUP_FLAG_CMOS))
       mpxplay_control_fastlist_searchfilename(psi,d);
     }else if(psi->editsidetype&PLL_SUBLISTS){
      if(playlist_loadsub_sublist_setlevels(psi,d)){ // overwrites su_oldlistname (cuts the string at the end of the first listname), but this is good/required
       mpxplay_playlist_startfile_fullpath(fullname,freeopts[OPT_INPUTFILE]);
       if(pds_utf8_stricmp(d,fullname)!=0) // compare rootlistname with inputfilename
        playlist_loadsub_sublist_clear(psi);
      }else
       playlist_loadsub_sublist_clear(psi);
     }
     if(funcbit_test(psi->editloadtype,PLL_RESTORED))
      pds_strcpy(psi->restored_filename,&psi->sublistnames[psi->sublistlevel][0]);
     oridirname[0]=0;
    }else if(pds_strcmp(strtmp,"EditorHighTab")==0){
     unsigned int side=pds_atol(n),tab=pds_atol(d);
     playlist_editlist_tab_select(mvp,side,tab);
    }
   }else if(pds_strcmp(strtmp,"EditorSide")==0){
    playlist_editlist_editside_chg(mvp,pds_atol(d));
   }else if(pds_strcmp(strtmp,"PlaySideTab")==0){
    if(!is_inputfile){
     unsigned int v=pds_atol(d),side=v/100,tab=v%100;
     playlist_editlist_tab_select(mvp,side,tab);
     mvp->psip=playlist_editlist_tabp_get(mvp,side);
    }else{
     mvp->psip=mvp->psil;
     playlist_editlist_tab_select(mvp,mvp->psip->sidenum,mvp->psip->tabnum);
    }
    funcbit_enable(playlistload,PLL_RESTORED);
   }else if(pds_strcmp(strtmp,"OldSongName")==0)
    pds_strcpy(su_oldsongname,d);
   else if(pds_strcmp(strtmp,"OldSongNum")==0)
    su_oldsongnum=pds_atol(d);
   else if(pds_strcmp(strtmp,"OldTimePos")==0)
    su_oldtimempos=pds_atol(d);
  }
  mpxplay_diskdrive_textfile_close(fp);
 }

 if((su_startuptype&STARTUP_FLAG_2SIDES) && ((playlistload&PLL_DOOMBOX) || !is_inputfile))
  playlist_jukebox_set(mvp,1);

end_su_ll:
 if((su_startuptype&STARTUP_FLAG_CMOS) && (su_startuptype&STARTUP_FLAG_SAVE) && !(mvp->aui->card_handler->infobits&SNDCARD_IGNORE_STARTUP)){
  mpxplay_timer_addfunc(&mpxplay_control_startup_savetocmos,NULL,MPXPLAY_TIMERTYPE_REPEAT|MPXPLAY_TIMERFLAG_MVPDATA,mpxplay_timer_secs_to_counternum(CMOS_SAVE_REFRESH));
  mpxplay_timer_addfunc(&mpxplay_control_startup_savetocmos,NULL,MPXPLAY_TIMERTYPE_SIGNAL|MPXPLAY_TIMERFLAG_MULTIPLY|MPXPLAY_TIMERTYPE_REPEAT|MPXPLAY_TIMERFLAG_MVPDATA,MPXPLAY_SIGNALTYPE_NEWFILE);
 }
}

void mpxplay_control_startup_getstartpos(struct mainvars *mvp)
{
 char fullname[MAX_PATHNAMELEN];

 if((su_startuptype&STARTUP_FLAG_LOAD) && !(mvp->aui->card_handler->infobits&SNDCARD_IGNORE_STARTUP)){
  if(su_startuptype&STARTUP_FLAG_CMOS){
   mpxplay_control_startup_loadfromcmos_songpos(mvp);
  }else{
   if(freeopts[OPT_INPUTFILE])
    mpxplay_playlist_startfile_fullpath(fullname,freeopts[OPT_INPUTFILE]);
   else if(drivescanletters)
    pds_strcpy(fullname,drivescanletters);
   else
    fullname[0]=0;

   if(!playstartsong && (!fullname[0] || (((su_oldlisttype&PLL_TYPE_LISTS)==(mvp->psip->editloadtype&PLL_TYPE_LISTS)) && (pds_utf8_stricmp(su_orilistname,fullname)==0)) || (pds_utf8_stricmp(su_oldsongname,fullname)==0))){
    struct playlist_side_info *psi=mvp->psip;
    struct playlist_entry_info *pei=NULL;

    if(su_oldsongnum){
     pei=psi->firstsong+su_oldsongnum-1;
     if((pei>psi->lastentry) || (pds_utf8_stricmp(pei->filename,su_oldsongname)!=0))
      pei=NULL;
    }
    if(!pei)
     pei=playlist_search_filename(psi,su_oldsongname,su_oldtimempos,NULL); // !!! searching for the first, not for the closest
    if(!pei)
     return;
    playlist_randlist_delete(pei); // because it's pushed back again at song-start

    playstartsong=pei-psi->firstsong+1;

    if((playlistload&PLL_TYPE_LISTS) || !playlistload || (su_startuptype&(STARTUP_FLAG_RESDIR|STARTUP_FLAG_2SIDES))){
     if(!playstartframe && !playstartpercent && !playstarttime){
      if(pei->infobits&PEIF_INDEXED)
       su_oldtimempos-=pei->pstime;
      playstartmsec=su_oldtimempos;
     }
     if(su_startuptype&STARTUP_FLAG_RESDIR)
      funcbit_enable(playcontrol,PLAYC_STARTNEXT);
    }
   }
  }
 }
}

void mpxplay_control_startup_saveini(void)
{
 struct mainvars *mvp=&mvps;
 struct playlist_entry_info *pei;
 struct playlist_side_info *psi,*psip;
 struct mpxpframe_s *frp0;
 long index_pos,i,side,tabnum;
 void *fp;
 unsigned long su_oldframenum,su_oldlisttype;
 char sout[MAX_STRLEN],su_oldlistname[MAX_STRLEN],orilistname[MAX_PATHNAMELEN];

 if(!(su_startuptype&STARTUP_FLAG_SAVE) || !mvp->aui || !mvp->aui->card_handler || (mvp->aui->card_handler->infobits&SNDCARD_IGNORE_STARTUP))
  return;
 if(su_startuptype&STARTUP_FLAG_CMOS){
  mpxplay_control_startup_savetocmos(mvp);
  return;
 }
 psip=mvp->psip;
 frp0=mvp->frp0;
 pei=((mvp->adone==ADONE_EOF) && (mvp->aktfilenum==psip->lastentry) && (mvp->aktfilenum>=psip->firstsong))? psip->firstsong:
     (mvp->aktfilenum>=psip->firstsong && mvp->aktfilenum<=psip->lastentry)? mvp->aktfilenum:NULL;
 if(pei){
  pds_strcpy(su_oldsongname,pei->filename);
  su_oldsongnum=pei-psip->firstsong+1;
 }else{
  su_oldsongname[0]=0;
  su_oldsongnum=0;
 }
 index_pos=frp0->frameNum-frp0->index_start;
 su_oldframenum=((mvp->adone==ADONE_EOF) || (index_pos<100))? frp0->index_start:(frp0->frameNum-10);
 if(su_oldframenum){
  struct mpxplay_infile_info_s *miis=frp0->infile_infos;
  struct mpxplay_audio_decoder_info_s *adi=miis->audio_decoder_infos;
  unsigned long samplenum,freq;
  if(adi->freq){ // !!! ???
   freq=adi->freq;
   samplenum=mpxplay_infile_get_samplenum_per_frame(freq);
  }else{
   freq=48000;
   samplenum=PCM_OUTSAMPLES;
  }
  su_oldtimempos=(long)(1000.0*((float)su_oldframenum*(float)samplenum+((float)freq/2))/(float)freq);
 }else
  su_oldtimempos=0;

 startup_get_tabsfilename(&sout[0]);
 fp=mpxplay_diskdrive_textfile_open(NULL,sout,(O_WRONLY|O_CREAT|O_TEXT));
 if(!fp)
  return;

 i=MPXPLAY_TEXTCONV_TYPE_MPXNATIVE;
 mpxplay_diskdrive_textfile_config(fp,MPXPLAY_DISKTEXTFILE_CFGFUNCNUM_SET_TEXTCODETYPE_DEST,((void *)&i),NULL);

 psi=(su_startuptype&STARTUP_FLAG_2SIDES)? mvp->psi0:mvp->psip;

 for(tabnum=0;tabnum<mvp->editorside_all_tabs;tabnum++,psi++){
  su_oldlisttype=(psi->editloadtype&PLL_TYPE_SAVED);
  if(drivescanletters && (psi==mvp->psil))
   pds_strcpy(orilistname,drivescanletters);
  else if(psi->savelist_filename[0])
   pds_strcpy(orilistname,psi->savelist_filename);
  else if(!funcbit_test(psi->editloadtype,PLL_RESTORED))
   pds_strcpy(orilistname,psi->sublistnames[psi->sublistlevel]);
  else
   orilistname[0]=0;

  if(su_startuptype&STARTUP_FLAG_2SIDES){
   playlist_savelist_save_editedside(psi);
   su_oldlisttype|=(psi->editloadtype&PLL_RESTORED);
  }

  if(funcbit_test(psi->editloadtype,PLL_RESTORED) && psi->restored_filename[0])
   pds_strcpy(&psi->sublistnames[psi->sublistlevel][0],psi->restored_filename);

  su_oldlistname[0]=0;
  if(playlist_loadsub_sublist_getlevels(psi,su_oldlistname,MPXINI_MAX_CHARSPERLINE-1)){ // sublist
   funcbit_enable(su_oldlisttype,PLL_SUBLISTS);
   if(psi->editsidetype&PLT_DIRECTORY)    // in db
    funcbit_disable(su_oldlisttype,PLL_TYPE_LOAD);
  }else{
   funcbit_disable(su_oldlisttype,PLL_SUBLISTS);
   if(psi->editsidetype&PLT_DIRECTORY){
    pds_strcpy(su_oldlistname,psi->currdir);
    mpxplay_diskdrive_drive_config(psi->mdds,MPXPLAY_DISKDRIV_CFGFUNCNUM_GET_REALLYFULLPATH,su_oldlistname,su_oldlistname);
    funcbit_disable(su_oldlisttype,PLL_TYPE_LISTS);
   }else{
    funcbit_enable(su_oldlisttype,PLL_LOADLIST);
    if(drivescanletters && (psi==mvp->psil) && !(su_startuptype&STARTUP_FLAG_2SIDES)) // drive scan
     pds_strcpy(su_oldlistname,drivescanletters);
    else
     pds_strcpy(su_oldlistname,&psi->sublistnames[psi->sublistlevel][0]);
   }
  }
  sprintf(sout,"OldListType_%d%2.2d=%d",psi->sidenum,psi->tabnum,su_oldlisttype);
  mpxplay_diskdrive_textfile_writeline(fp,sout);
  if(su_startuptype&STARTUP_FLAG_2SIDES){
   sprintf(sout,"EditorHighline_%d%2.2d=%d",psi->sidenum,psi->tabnum,(psi->editorhighline-psi->firstentry));
   mpxplay_diskdrive_textfile_writeline(fp,sout);
   sprintf(sout,"OrderKeys_%d%2.2d=%8.8X",psi->sidenum,psi->tabnum,playlist_sortlist_get_orderkeys_in_hexa(psi));
   mpxplay_diskdrive_textfile_writeline(fp,sout);
   snprintf(sout,sizeof(sout),"OriDirName_%d%2.2d=%s",psi->sidenum,psi->tabnum,psi->currdir);
   mpxplay_diskdrive_textfile_writeline(fp,sout);
  }
  snprintf(sout,sizeof(sout),"OriListName_%d%2.2d=%s",psi->sidenum,psi->tabnum,orilistname);
  mpxplay_diskdrive_textfile_writeline(fp,sout);
  snprintf(sout,sizeof(sout),"OldListName_%d%2.2d=%s",psi->sidenum,psi->tabnum,su_oldlistname);
  mpxplay_diskdrive_textfile_writeline(fp,sout);
  if(!(su_startuptype&STARTUP_FLAG_2SIDES))
   break;
 }
 if(su_startuptype&STARTUP_FLAG_2SIDES){
  for(side=0;side<PLAYLIST_MAX_SIDES;side++){
   sprintf(sout,"EditorHighTab_%d=%d",side,mvp->editorsides_selected_tab[side]);
   mpxplay_diskdrive_textfile_writeline(fp,sout);
  }
  sprintf(sout,"EditorSide=%d",mvp->psie->sidenum);
  mpxplay_diskdrive_textfile_writeline(fp,sout);
  sprintf(sout,"PlaySideTab=%d%2.2d",psip->sidenum,psip->tabnum);
  mpxplay_diskdrive_textfile_writeline(fp,sout);
 }
 snprintf(sout,sizeof(sout),"OldSongName=%s",su_oldsongname);
 mpxplay_diskdrive_textfile_writeline(fp,sout);
 sprintf(sout,"OldSongNum=%d",su_oldsongnum);
 mpxplay_diskdrive_textfile_writeline(fp,sout);
 sprintf(sout,"OldTimePos=%d",su_oldtimempos);
 mpxplay_diskdrive_textfile_writeline(fp,sout);

 mpxplay_diskdrive_textfile_close(fp);
}
