#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commctrl.h>
#include "resource.h"
#include "afxres.h"
#include "cdplay.h"
#include <mmsystem.h>

DWORD dwrc;

MCI_OPEN_PARMS   MCIOpen;
MCI_SET_PARMS    MCISet;
MCI_STATUS_PARMS MCIStatus;
MCI_PLAY_PARMS   MCIPlay;

BOOL bMediaPresent = FALSE;
BOOL bPaused       = FALSE;
UINT nMode = 0;
extern UINT nCurTrack;
extern UINT nTrackCnt;
extern HWND hTrackBar;

HWND hwndCurTrack = NULL;

// -----------------------------------------------------
// Функция CdInit
// -----------------------------------------------------
BOOL CdInit(void)
{
  // Открываем устройство чтения компакт-дисков
  MCIOpen.lpstrDeviceType = (LPSTR)MCI_DEVTYPE_CD_AUDIO;
  dwrc = mciSendCommand(0, MCI_OPEN,
    MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, (DWORD)&MCIOpen);
  if(dwrc)
  {
    mciwioError(dwrc);
    return FALSE;
  }

  // Устанавливаем формат времени
  MCISet.dwTimeFormat = MCI_FORMAT_TMSF;
  dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_SET,
    MCI_SET_TIME_FORMAT, (DWORD)&MCISet);
  if(dwrc)
  {
    mciwioError(dwrc);
    return FALSE;
  }
  return TRUE;
}

// -----------------------------------------------------
// Функция CdClose
// -----------------------------------------------------
void CdClose(void)
{
  // Закрываем устройство чтения компакт-дисков
  dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_CLOSE, 0, 0);
  if(dwrc)
    mciwioError(dwrc);
}

//-----------------------------------------------------
// mciwioError
// Обработка ошибок
//-----------------------------------------------------
void mciwioError(DWORD dwrc)
{
  BYTE szBuf[MAXERRORLENGTH];

  if(mciGetErrorString(dwrc, (LPSTR)szBuf, MAXERRORLENGTH))
    MessageBox(NULL, szBuf,
      "MCIWAVE Error", MB_ICONEXCLAMATION);
  else
    MessageBox(NULL, "Неизвестная ошибка",
      "MCIWAVE Error", MB_ICONEXCLAMATION);
}

// -----------------------------------------------------
// Функция CdUpdateState
// -----------------------------------------------------
BOOL CdUpdateState(HWND hdlg)
{
  BOOL fNeedUpdate = FALSE;
  UINT nCurMode;

  // Определяем текущее состояние проигрывателя CD
  MCIStatus.dwItem = MCI_STATUS_MODE;
  mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
    MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus);

  // Проверяем, готово ли устройство чтения к работе 
  if((MCIStatus.dwReturn == MCI_MODE_NOT_READY) ||
     (MCIStatus.dwReturn == MCI_MODE_OPEN))
  {
    // Устройство не готово
    nCurMode = CD_EMPTY;
  }
  else if((MCIStatus.dwReturn == MCI_MODE_STOP) &&
    bPaused)
  {
    // Устройство остановлено 
    nCurMode = CD_PAUSED;
  }
  else if(MCIStatus.dwReturn == MCI_MODE_PLAY)
  {  
    // Устройство находится в режиме проигрывания
    nCurMode = CD_PLAYING;
  }
  else
  {
    // Устройство готово
    nCurMode = CD_READY;
  }

  // Если с момента последней проверки произошло
  // изменение режима, записываем код нового режима
  if(nMode != nCurMode)
  {
    fNeedUpdate = TRUE;
    nMode = nCurMode;
    
    // Если устройство находится в режиме проигрывания,
    // запускаем видеоклип. В противном случае
    // останавливаем видеоклип в его текущей позиции
    if(nCurMode == CD_PLAYING)
      Animate_Play(GetDlgItem(hdlg, IDC_ANIMATE), 0, -1, -1);
    else
      Animate_Stop(GetDlgItem(hdlg, IDC_ANIMATE));
  }

  // Проверяем, вставлен ли компакт-диск
  MCIStatus.dwItem = MCI_STATUS_MEDIA_PRESENT;
    mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
    MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus);

  // Если компакт-диск вставлен, определяем
  // количество звуковых дорожек
  if((!bMediaPresent) && MCIStatus.dwReturn)
  {
    bMediaPresent = TRUE;
    bPaused = FALSE;
    nCurTrack = 0;

    MCIStatus.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
    mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
      MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus);

    nTrackCnt = MCIStatus.dwReturn;

    // Устанавливаем диапазон изменения значений
    // для органа управления Trackbar
    SendMessage(hTrackBar, TBM_SETRANGE, TRUE, 
      MAKELPARAM(1, nTrackCnt));
  }

  // Если компакт-диск не вставлен, сбрасываем
  // номер текущей дорожки в поле диалоговой панели
  else if((bMediaPresent) && !MCIStatus.dwReturn)
  {
    bMediaPresent = FALSE;
    bPaused = FALSE;
  }

  // Если приложение находится в режиме проигрывания,
  // определяем номер текущей дорожки
  if(nCurMode == CD_PLAYING)
  {
    // Определяем текущую позицию
    MCIStatus.dwItem = MCI_STATUS_POSITION;
    mciSendCommand(MCIOpen.wDeviceID, MCI_STATUS,
      MCI_STATUS_ITEM | MCI_WAIT, (DWORD)&MCIStatus);

    // Если номер дорожки изменился, отображаем новое
    // значение в соответствующем поле диалоговой панели 
    if(nCurTrack != (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn))
    {
      nCurTrack = (UINT)MCI_TMSF_TRACK(MCIStatus.dwReturn);
      fNeedUpdate = TRUE;
    }
  }
  return fNeedUpdate;
}

//-----------------------------------------------------
// CdPlay
// Запуск проигрывания дорожки
//-----------------------------------------------------
void CdPlay(HWND hwnd, UINT nTrack)
{
  if(bMediaPresent)
  {
    bPaused = FALSE;

    MCIPlay.dwCallback = (DWORD)hwnd;
    MCIPlay.dwFrom = MCI_MAKE_TMSF(nTrack, 0, 0, 0);

    dwrc = mciSendCommand(MCIOpen.wDeviceID, MCI_PLAY,
      MCI_FROM | MCI_NOTIFY, (DWORD)&MCIPlay);
    if(dwrc)
      mciwioError(dwrc);
  }
}

//-----------------------------------------------------
// CdStop
// Останов проигрывания дорожки
//-----------------------------------------------------
void CdStop(void)
{
  if(bMediaPresent)
  {
    bPaused = FALSE;
    nCurTrack = 0;
    mciSendCommand(MCIOpen.wDeviceID, MCI_STOP, 0, 0);
  }
}

//-----------------------------------------------------
// CdPause
// Временный останов проигрывания дорожки
//-----------------------------------------------------
void CdPause(void)
{
  if(bMediaPresent)
  {
    if(!bPaused)
    {
      bPaused = TRUE;
      mciSendCommand(MCIOpen.wDeviceID, MCI_PAUSE, 0, 0);
    }
  }
}

//-----------------------------------------------------
// CdResume
// Возобновление проигрывания после временного останова
//-----------------------------------------------------
void CdResume(HWND hwnd)
{
  if(bMediaPresent)
  {
    if(bPaused)
    {
      bPaused = FALSE;
      MCIPlay.dwCallback = (DWORD)hwnd;
      mciSendCommand(MCIOpen.wDeviceID, MCI_PLAY,
        MCI_NOTIFY, (DWORD)&MCIPlay);
    }
  }
}

//-----------------------------------------------------
// CdPlayNext
// Проигрывание следующей дорожки
//-----------------------------------------------------
void CdPlayNext(HWND hwnd)
{
  UINT nNewTrack;
  
  if(bMediaPresent)
  {
    // Если текущая дорожка - последняя,
    // начинаем проигрывание с первой дорожки.
    // Если нет - проигрываем следующую дорожку
    if(nCurTrack == nTrackCnt)
      nNewTrack = 1;
    else
      nNewTrack = nCurTrack + 1;

    CdPlay(hwnd, nNewTrack);
  }
}

//-----------------------------------------------------
// CdPlayPrev
// Проигрывание предыдущей дорожки
//-----------------------------------------------------
void CdPlayPrev(HWND hwnd)
{
  UINT nNewTrack;
  if(bMediaPresent)
  {
    // Если текущая дорожка - первая,
    // проигрываем последнюю дорожку
    if(nCurTrack <= 1)
      nNewTrack = nTrackCnt;
    else
      nNewTrack = nCurTrack - 1;

    CdPlay(hwnd, nNewTrack);
  }
}

//-----------------------------------------------------
// CdEject 
// Выталкивание компакт-диска
//-----------------------------------------------------
void CdEject(void)
{
  mciSendCommand(MCIOpen.wDeviceID, MCI_SET,
    MCI_SET_DOOR_OPEN, 0);
}
