#include "SM_CommonFXPCH.h"
#include "SM_Timer.h"
#include "FXMusic.h"


static  SM_DemoEffect::Helper  LoadHelp[] =
{
  {"MP3 filename", "loads music from data/music"},
};

static SM_DemoEffect::Helper CommandsHelp[] =
{
  {"No commands available", "no commands available"},
};


int MusicFX::LoadArgumentsHelp     (Helper*& pHelpers)
{
  pHelpers = LoadHelp;
  return (sizeof(LoadHelp)/sizeof(Helper));
}

int MusicFX::CommandArgumentsHelp  (Helper*& pHelpers)
{
  pHelpers = CommandsHelp;
  return (sizeof(CommandsHelp)/sizeof(Helper));
}

MusicFX::MusicFX(char const* pcName) : SM_DemoEffect(pcName)
{
  m_iLength   = 0;
  m_pcBuffer  = 0; 
  m_iFlags    = 0;
  m_hMP3      = 0;
  m_bPlaying  = false;
}

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

int MusicFX::Init(const char* pcCommand)
{
  char* pcCopy =0;
  char* pcToken;
  int   iReturn=-1;

  Shutdown();
  
  pcCopy=new char[strlen(pcCommand)+1];
  strcpy(pcCopy, pcCommand);

  pcToken=strtok(pcCopy, " \t");
  if (strcmp(pcToken, "MP3")==0)
  {
    pcToken=strtok(0, " \t");

    if ( (iReturn = LoadData(pcToken)) != 0)
    {
      goto FAILED;
    }
    m_iFlags |= E_MP3;

    m_hMP3 = BASS_StreamCreateFile(TRUE, m_pcBuffer, 0, m_iLength, BASS_MP3_SETPOS);
    if (!m_hMP3)
    {
      ShutdownData();
      goto FAILED;
    }
  }
  else if (strcmp(pcToken, "TRACK")==0)
  {
    assert(!"NYI");    
  }

  iReturn  = 0;
  
FAILED:
  if (pcCopy) { delete[] pcCopy; pcCopy=0; }

  return iReturn;    
}

int MusicFX::Shutdown()
{
  ShutdownData();
  
  Stop();

  if (m_hMP3)
  {
    BASS_StreamFree(m_hMP3);
  }

  m_iFlags    = 0;
  m_hMP3      = 0;
  m_bPlaying  = false;

  return (0);
}

int MusicFX::Start(float fTime)
{
  #define DELAY 0.15f;
  fTime = max(0.0f, Timer::GetTime()-fTime+0.3f);

  if (!m_bNoMusic)
  {
    if (m_iFlags & E_MP3)
    {
      assert(m_hMP3);
      assert(!m_bPlaying);

      BASS_Start();    

      DWORD dwOffset,dwLength,dwFreq,dwFlags;

      dwLength=(unsigned long) BASS_StreamGetLength(m_hMP3); // length in bytes

      BASS_ChannelGetAttributes(m_hMP3, &dwFreq, 0 ,0); // sample rate
      dwFlags=BASS_ChannelGetFlags(m_hMP3); // stereo/mono, 8/16 bit flags

      dwOffset=min(dwLength, DWORD(fTime*float((dwFreq*(dwFlags&BASS_SAMPLE_MONO?1:2)*(dwFlags&BASS_SAMPLE_8BITS?1:2)))));
      BASS_ChannelSetPosition(m_hMP3, dwOffset);
      BASS_StreamPlay(m_hMP3, FALSE, 0);
    
      m_bPlaying = true;
    }
  }
  return (0);
}

int MusicFX::Stop()
{
  if (m_iFlags & E_MP3)
  {
    if (m_bPlaying)
    {
      BASS_Stop();
      m_bPlaying=false;    
    }      
  }
  
  return (0);
}

int MusicFX::Reset()
{
  Stop();
  return 0;
}

int MusicFX::Run(float fTime)
{
  return (1);
}

int MusicFX::LoadData(const char* pcMP3Name)
{
  ShutdownData();

  char pcFilename[MAX_PATH];
  strcpy(pcFilename, "data/Music/");
  strcat(pcFilename, pcMP3Name);
  
  MVFSFILE* f;    

  f=MVFS::fopen(pcFilename, "rb");
  if (!f)
  {
    SM_Main::OutputError("Error file not found %s", pcFilename);
    return (-1);
  }

  MVFS::fseek(f, 0, SEEK_END);
  int iLength=MVFS::ftell(f);
  if (iLength==-1)
  {
    return (-1);
  }

  MVFS::fseek(f, 0, SEEK_SET);

  char* pcMP3=new char[iLength];
  if (!pcMP3)
  {
    return (-1);
  }

  if (MVFS::fread(pcMP3, iLength, 1, f)!=1)
  {
    SM_Main::OutputError("Error reading %s", pcFilename);
    MVFS::fclose(f);
    delete[] pcMP3;
    return (-1);
  }

  m_pcBuffer=pcMP3;
  m_iLength=iLength;

  MVFS::fclose(f); 

  return 0;
}

int MusicFX::ShutdownData()
{
  delete[] m_pcBuffer; m_pcBuffer = 0;
  m_iLength = 0;        

  return 0;
}

int MusicFX::Command           (float fTime, const char* pcCommand)
{
  SM_DemoEffect::Command(fTime, pcCommand);
  char* pcCopy =0;
  char* pcToken;
  int   iReturn=-1;
  
  pcCopy=new char[strlen(pcCommand)+1];
  strcpy(pcCopy, pcCommand);

  pcToken=strtok(pcCopy, " \t");

  if (strcmp(pcToken, "PLAY")==0)
  {      
  }
  
  iReturn  = 0;

  goto FAILED;
FAILED:
  if (pcCopy) { delete[] pcCopy; pcCopy=0; }
  return iReturn;
}  

void MusicFX::SetNoMusic(bool bNoMusic)
{
  m_bNoMusic = bNoMusic;  
}


BOOL CALLBACK DuffRecording(void *buffer, DWORD length, DWORD user)
{
	return TRUE; // continue recording
}


float* MusicFX::MP3GetChannelData (float fTime)
{
  static float m_fTime = -1;
  static float m_fData[SM_MUSIC_DATASAMPLES];

  static bool bRecord = false;

  if (!bRecord)
  {
    if (!BASS_RecordInit(-1)) {
				return 0;
			}
			// start recording (44100hz mono 16-bit)
			if (!BASS_RecordStart(44100,BASS_SAMPLE_MONO,&DuffRecording,0)) {
				return 0;
			}

      bRecord = true;
  }

  if (fTime != m_fTime)
  {
    if (BASS_ChannelGetData(
              RECORDCHAN /*m_hMP3*/,
              m_fData, 
              BASS_DATA_FFT2048) == 0xFFFFFFFF)
    {
      DWORD dwError =  BASS_ErrorGetCode(); 

      return 0;
    }
    
    m_fTime = fTime;
  }
  
  return m_fData;
}



bool MusicFX::m_bNoMusic = false;

DEFINE_EFFECT(MusicFX)

MusicFX Track01("TRACK01");
MusicFX Track02("TRACK02");
MusicFX Track03("TRACK03");
MusicFX Track04("TRACK04");
MusicFX MP301  ("MP301");
MusicFX MP302  ("MP302");
MusicFX MP303  ("MP303");
MusicFX MP304  ("MP304");

