/**************************************************************************

    This file is part of cdplay, a cdplayer for fvwm95.
    Copyright (C) 1997 Rodolphe Suescun.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    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.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

**************************************************************************/

#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/ucdrom.h>
#include <stdlib.h>
#include <fcntl.h>

#include "OCd.h"


void OCd::Open()
{
  int i;
  struct cdrom_tochdr tochdr;
  struct cdrom_tocentry tocentry;

  cdfile = open(devpath, O_RDONLY);
  status = OMEDIUM_STOPPED;
  ioctl(cdfile, CDROMREADTOCHDR, &tochdr);
  current_track = 1;

  for (i=tochdr.cdth_trk0-1; i<=(nb_tracks=tochdr.cdth_trk1); i++) {
    tocentry.cdte_track  = (i==tochdr.cdth_trk1) ? CDROM_LEADOUT : i+1;
    tocentry.cdte_format = CDROM_MSF;
    ioctl(cdfile, CDROMREADTOCENTRY, &tocentry);
    track_db[i+1].info1 =((tocentry.cdte_addr.msf.minute * 60) +
                          (tocentry.cdte_addr.msf.second)) * 75 +
                           tocentry.cdte_addr.msf.frame;
    track_db[i].info2 =((tocentry.cdte_addr.msf.minute * 60) +
                        (tocentry.cdte_addr.msf.second)) * 75 +
                         tocentry.cdte_addr.msf.frame;
  }

  for (i=1; i<=nb_tracks; i++) {
    track_db[i].length = track_db[i].info2 - track_db[i].info1;
    sprintf(track_db[i].name, "Track %i", i);
  }

  ResetPlayList();
  current_index = 0;
}

void OCd::Close()
{
  ioctl(cdfile, CDROMEJECT);
  close(cdfile);
  status = OMEDIUM_TRAY_OPEN;
}

void OCd::ReadInfo()
{
  struct cdrom_subchnl subchnl;
  struct cdrom_volctrl volctrl;

  ioctl(cdfile, CDROMVOLREAD, &volctrl);
  volume = volctrl.channel0;

  if (status != OMEDIUM_TRAY_OPEN ) {
    subchnl.cdsc_format = CDROM_MSF;
    if (ioctl(cdfile, CDROMSUBCHNL, &subchnl) == -1) {
      status = OMEDIUM_ERROR;
    } else {
      switch (subchnl.cdsc_audiostatus) {
        case CDROM_AUDIO_ERROR:
        case CDROM_AUDIO_INVALID:
          status = OMEDIUM_ERROR;
          break;

        case CDROM_AUDIO_PLAY:
          status = OMEDIUM_PLAYING;
          current_track = subchnl.cdsc_trk;
          reltime = subchnl.cdsc_reladdr.msf.minute * 4500 +
                    subchnl.cdsc_reladdr.msf.second * 75 +
                    subchnl.cdsc_reladdr.msf.frame;
          break;

        case CDROM_AUDIO_PAUSED:
          status = OMEDIUM_PAUSED;
          current_track = subchnl.cdsc_trk;
          reltime = subchnl.cdsc_reladdr.msf.minute * 4500 +
                    subchnl.cdsc_reladdr.msf.second * 75 +
                    subchnl.cdsc_reladdr.msf.frame;
          break;

        case CDROM_AUDIO_NO_STATUS:
        case CDROM_AUDIO_COMPLETED:
          if ((status == OMEDIUM_PLAYING) || (status == OMEDIUM_COMPLETED))
            status = OMEDIUM_COMPLETED;
          else
            status = OMEDIUM_STOPPED;
          break;
      }
    }
  }
}

void OCd::SetVolume(int vol)
{
  struct cdrom_volctrl volctrl;

  volctrl.channel0 = vol;
  volctrl.channel1 = vol;
  ioctl(cdfile, CDROMVOLCTRL, &volctrl);
}

void OCd::_Play(int track, int time) 
{
  struct cdrom_msf msf;
  int beg_time;

  current_track = track;
  if (time < 0) {
    beg_time = track_db[track].info2 + time;
    reltime = track_db[track].length + time;
  } else {
    beg_time = track_db[track].info1 + time;
    reltime = time;
  }

  msf.cdmsf_min0 = beg_time / 4500;
  msf.cdmsf_sec0 = (beg_time / 75) % 60;
  msf.cdmsf_frame0 = beg_time % 75;
  
  msf.cdmsf_min1 = track_db[track].info2 / 4500;
  msf.cdmsf_sec1 = (track_db[track].info2 / 75) % 60;
  msf.cdmsf_frame1 = track_db[track].info2 % 75;
  ioctl(cdfile, CDROMPLAYMSF, &msf);
  status = OMEDIUM_PLAYING;
}

void OCd::Stop()
{
  ioctl(cdfile, CDROMSTOP);
  status = OMEDIUM_STOPPED;
  reltime = 0;
}

void OCd::Pause()
{
  if (status == OMEDIUM_PAUSED) {
    ioctl(cdfile, CDROMRESUME);
    status = OMEDIUM_PLAYING;
  } else if (status == OMEDIUM_PLAYING) {
    ioctl(cdfile, CDROMPAUSE);
    status = OMEDIUM_PAUSED;
  } else {
    Play();
    ioctl(cdfile, CDROMPAUSE);
    status = OMEDIUM_PAUSED;
  }
}
