//**************************************************************************
//*                     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: startup (restore the playing at the last position)

#include "newfunc\newfunc.h"
#include "control.h"
#include "cntfuncs.h"
#include "playlist\playlist.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 CMOS_SAVE_REFRESH 2 // in secs

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

static unsigned int su_startupenabled,su_oldlisttype;
static char su_oldlistname[MPXINI_MAX_CHARSPERLINE],*su_oldsongname;
static unsigned long su_oldframenum;

static mpxini_var_s startup_vars[]={
 {"StartupEnabled",&su_startupenabled,ARG_NUM},
 {"OldListType"   ,&su_oldlisttype,   ARG_NUM|ARG_SAVE},
 {"OldListname"   ,&su_oldlistname[0],ARG_CHAR|ARG_SAVE},
 {"OldSongname"   ,&su_oldsongname,   ARG_CHAR|ARG_POINTER|ARG_SAVE},
 {"OldFrameNum"   ,&su_oldframenum,   ARG_NUM|ARG_SAVE},
 {NULL,NULL,0}
};

static void shortdelay(val)
{
 while(--val){}
}

void mpxplay_control_startup_savetocmos(struct mainvars *mvp)
{
 struct frame *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); // 8+6=14 bits
 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 (lower) bits filenum
 outp(0x70,3);
 shortdelay(1); // ???
 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
 MPXPLAY_INTSOUNDDECODER_ALLOW;
}

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

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

static void mpxplay_control_startup_loadfromcmos_songpos(struct mainvars *mvp)
{
 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);
  playstartsong=c1|((c2&0x3f)<<8);
  if((playlistload&PLL_LISTS_ALL) && playstartsong<=((psip->lastentry-psip->firstsong)+1)){
   if(!playstartframe && !playstartpercent && !playstarttime)
    playstartpercent=c3&0x7f;
   playcontrol|=PLAYC_STARTNEXT;
  }
 }
}

//-------------------------------------------------------------------------

void mpxplay_control_startup_loadini(mpxini_line_t *mpxini_lines,struct mpxini_part_t *mpxini_partp)
{
 mpxplay_control_general_loadini(mpxini_lines,mpxini_partp,startup_vars);
}

void mpxplay_control_startup_loadlastlist(void)
{
 struct playlist_side_info *psi=mvps.psil;
 char fullname[300];
 if(su_startupenabled&STARTUP_FLAG_LOAD){
  //restore fastlist from mpxplay.ini
  if(playlistload&PLL_FASTLIST){
   char *filename;
   if(su_startupenabled&STARTUP_FLAG_CMOS){
    mpxplay_control_startup_loadfromcmos_listnum();
    filename=NULL;
   }else
    filename=&su_oldlistname[0];
   mpxplay_control_fastlist_searchfilename(filename);
   goto su_lll_end;
  }
  //restore playlist/directory from mpxplay.ini (OldListname) (if no command line playlist/dirscan has given)
  if((su_startupenabled&STARTUP_FLAG_RESDIR) && !(su_startupenabled&STARTUP_FLAG_CMOS) && !(playlistload&PLL_LISTS_ALL) && !playlist_loadsub_getinputfile(psi) && !drivescanletters){
   if(su_oldlisttype&PLL_LISTS_ALL){ // reload last playlist
    if(su_oldlisttype&PLL_SUBLISTS)
     playlist_loadsub_sublist_setlevels(psi,su_oldlistname);
    else
     if(su_oldlisttype&PLL_FASTLIST)
      mpxplay_control_fastlist_searchfilename(su_oldlistname);
     else
      playlist_loadsub_setnewinputfile(psi,su_oldlistname);
   }else{                            // restore (change to) last directory
    int drive=pds_getdrivenum_from_path(su_oldlistname);
    if(drive>=0)
     pds_setdrive(drive);
    pds_chdir(su_oldlistname);
   }
  }
  //restore sublist(s) from mpxplay.ini
  if((su_oldlisttype&PLL_SUBLISTS) && !(su_startupenabled&STARTUP_FLAG_RESDIR)){
   if(playlist_loadsub_sublist_setlevels(psi,su_oldlistname)){ // overwrites su_oldlistname (cuts the string at the end of the first listname), but this is good/required
    pds_fullpath(fullname,freeopts[OPT_INPUTFILE]);
    if(pds_stricmp(su_oldlistname,fullname)!=0) // compare rootlistname with inputfilename
     playlist_loadsub_sublist_clear(psi);
   }
  }
 }

su_lll_end:
 if((su_startupenabled&STARTUP_FLAG_CMOS) && (su_startupenabled&STARTUP_FLAG_SAVE) && !(mvps.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(mainvars *mvp)
{
 char *s,fullname[300];

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

   if(!playstartsong && (su_oldlisttype==playlistload) && (!s || pds_stricmp(su_oldlistname,fullname)==0)){
    struct playlist_side_info *psi=mvp->psip;
    struct playlist_entry_info *pei;
    unsigned long samplenum=PCM_OUTSAMPLES,freq=44100;
    long timempos;

    pei=playlist_search_filename(psi,su_oldsongname,-1,NULL);
    if(!pei)
     return;

    if(pei->infobits&PEIF_INDEXED){ // then get freq for the correct indexed songpos-restoring
     if(mpxplay_infile_get_header_by_ext(mvp->frp0+2,su_oldsongname)){
      freq=(mvp->frp0+2)->infile_infos->audio_decoder_infos->freq;
      if(freq){
       samplenum=mpxplay_infile_get_samplenum_per_frame(freq);
       timempos=(long)(1000.0*(float)su_oldframenum*(float)samplenum/(float)freq);
       mpxplay_infile_close(mvp->frp0+2);
       pei=playlist_search_filename(psi,su_oldsongname,timempos,NULL);
       if(!pei)
        return;
      }
     }
    }
    playstartsong=pei-psi->firstsong+1;
    if((playlistload&PLL_LISTS_ALL) || !playlistload || (su_startupenabled&STARTUP_FLAG_RESDIR)){
     if(!playstartframe && !playstartpercent && !playstarttime){
      if((pei->infobits&PEIF_INDEXED) && pei->pstime)
       su_oldframenum-=(long)((float)pei->pstime*(float)freq/(float)samplenum/1000.0);
      playstartframe=su_oldframenum;
     }
     if((playlistload&PLL_LISTS_ALL) || (su_startupenabled&STARTUP_FLAG_RESDIR))
      playcontrol|=PLAYC_STARTNEXT;
    }
   }
  }
 }
}

void mpxplay_control_startup_saveini(mpxini_line_t *mpxini_lines,struct mpxini_part_t *mpxini_partp,FILE *configfile)
{
 struct mainvars *mvp=&mvps;
 char sout[MPXINI_MAX_CHARSPERLINE];

 if((su_startupenabled&STARTUP_FLAG_SAVE) && !(mvp->aui->card_handler->infobits&SNDCARD_IGNORE_STARTUP)){
  if(su_startupenabled&STARTUP_FLAG_CMOS)
   mpxplay_control_startup_savetocmos(mvp);
  else{
   struct playlist_side_info *psip=mvp->psip;
   struct playlist_side_info *psil=mvp->psil;
   struct frame *frp0;
   mpxini_var_s *varp;
   long index_pos;

   fseek(configfile,mpxini_partp->filepos,SEEK_SET); // !!!

   if(psip->editsidetype&PLT_DIRECTORY){
    pds_strcpy(su_oldlistname,psip->currdir);
    su_oldlisttype=0;
   }else{
    if(!playlist_loadsub_sublist_getlevels(psil,su_oldlistname,MPXINI_MAX_CHARSPERLINE-1)){
     if(playlist_loadsub_getinputfile(psil))
      pds_strcpy(su_oldlistname,playlist_loadsub_getinputfile(psil));
     else
      if(drivescanletters)
       pds_strcpy(su_oldlistname,drivescanletters);
      else
       su_oldlistname[0]=0;
    }
    su_oldlisttype=playlistload;
   }

   frp0=mvp->frp0;
   su_oldsongname=((mvp->adone==ADONE_EOF) && (mvp->aktfilenum==psip->lastentry))? psip->firstsong->filename:
                   (mvp->aktfilenum>=psip->firstsong && mvp->aktfilenum<=psip->lastentry)? mvp->aktfilenum->filename:NULL;
   index_pos=frp0->frameNum-frp0->index_start;
   su_oldframenum=((mvp->adone==ADONE_EOF) || (index_pos<100))? frp0->index_start:(frp0->frameNum-10);

   varp=startup_vars;
   while(varp->name){
    if(varp->type&ARG_CHAR){
     if(varp->type&ARG_POINTER)
      sprintf(sout,"%-16s=%s\n",varp->name,(**((char **)varp->c))? (*((char **)varp->c)):"");
     else
      sprintf(sout,"%-16s=%s\n",varp->name,(*((char *)varp->c))? ((char *)varp->c):"");
    }else
     sprintf(sout,"%-16s=%-5d\n",varp->name,*((unsigned int *)varp->c)); // allways decimal-number in startup_vars
    fputs(sout,configfile);
    varp++;
   }

   pds_memset(sout,32,64);
   sout[0]=';';
   sout[64]=0;
   fputs(sout,configfile);
   pds_chsize(configfile->_handle,pds_tell(configfile->_handle)); // !!!
  }
 }
}
