/*
 *
 *    soniK digital audio editor
 *    Copyright (C) 2003-2006  Robert Walker <rob@tenfoot.org.uk>
 *
 *    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 */
#include "recorddialog.h"

#include "part.h"
#include "sonik_util.h"
#include "formatdialog.h"

#include <kled.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kdebug.h>

#include <qradiobutton.h>
#include <qpushbutton.h>
#include <qtoolbutton.h>
#include <qlabel.h>

using Sonik::RecordDialog;

namespace
{
  static const char* kRecordIcon = "sonik_record";
  static const char* kStopIcon = "player_stop";
  static const uint32_t kFlashPeriod = 20;
}

RecordDialog::RecordDialog(Part& part,
                           QWidget *parent, const char *name,
                           bool modal, WFlags fl)
  : RecordDialogBase(parent, name, modal, fl),
    mPart(part),
    mAction(kInsertEnd),
    mFormat(mPart.data().format()),
    mState(Idle),
    mFlashCount(kFlashPeriod),
    mPosition(0)
{
  connect(actionReplaceFile,      SIGNAL(clicked()),
          this,                   SLOT(actionChanged()));
  connect(actionInsertStart,      SIGNAL(clicked()),
          this,                   SLOT(actionChanged()));
  connect(actionInsertCursor,     SIGNAL(clicked()),
          this,                   SLOT(actionChanged()));
  connect(actionInsertEnd,        SIGNAL(clicked()),
          this,                   SLOT(actionChanged()));
  connect(actionOverwriteCursor,  SIGNAL(clicked()),
          this,                   SLOT(actionChanged()));
  connect(actionReplaceSelection, SIGNAL(clicked()),
          this,                   SLOT(actionChanged()));

  connect(recordButton, SIGNAL(clicked()), this, SLOT(recordClicked()));

  connect(&mPart, SIGNAL(recording()),
          this,   SLOT(recording()));
  connect(&mPart, SIGNAL(stopped()),
          this,   SLOT(stopped()));
  connect(&mPart, SIGNAL(timeFormatChanged(Sonik::TimeFormat)),
          this,   SLOT(timeFormatChanged(Sonik::TimeFormat)));

  setFormatLabel();
  formatButton->setEnabled((mPart.data().length() == 0));

  recordButton->setPixmap(SmallIcon(kRecordIcon, mPart.instance()));

  actionReplaceSelection->setEnabled(mPart.selectionLength() != 0);

  // default to replace selection iff selection set
  if (mPart.selectionLength() > 0)
    actionReplaceSelection->setChecked(true);
  else
    actionInsertEnd->setChecked(true);

  actionChanged();
}

RecordDialog::~RecordDialog()
{
}

Sonik::InsertPosition RecordDialog::action() const
{
  return mAction;
}

const Sonik::Format& RecordDialog::format() const
{
  return mFormat;
}

void RecordDialog::position(off_t pos)
{
  updatePosition(pos);

  if (mState == Recording || mState == Stopping)
  {
    if (mFlashCount-- == 0)
    {
      recordLed->toggle();
      mFlashCount = kFlashPeriod;
    }
  }
}

void RecordDialog::timeFormatChanged(Sonik::TimeFormat /* fmt */)
{
  updatePosition(mPosition);
}

void RecordDialog::selectionChanged(off_t start, size_t length)
{
  if (mState != Idle)
    // ignore while recording
    return;

  if (mAction == kReplaceSelection ||
      mAction == kInsertCursor ||
      mAction == kOverwriteCursor)
  {
    updatePosition(start);
  }

  // only enable replace selection iff there is a selection
  actionReplaceSelection->setEnabled(length != 0);
  if (length == 0 && actionReplaceSelection->isChecked())
  {
    actionInsertCursor->setChecked(true);
  }
}

void RecordDialog::actionChanged()
{
  bool enableFormat = (mPart.data().length() == 0);

  if (actionReplaceFile->isChecked())
  {
    mAction = kReplaceAll;
    formatButton->setEnabled(true);
    updatePosition(0);
  }
  else if (actionInsertStart->isChecked())
  {
    mAction = kInsertStart;
    formatButton->setEnabled(enableFormat);
    updatePosition(0);
  }
  else if (actionInsertCursor->isChecked())
  {
    mAction = kInsertCursor;
    formatButton->setEnabled(enableFormat);
    updatePosition(mPart.selectionStart());
  }
  else if (actionInsertEnd->isChecked())
  {
    mAction = kInsertEnd;
    formatButton->setEnabled(enableFormat);
    updatePosition(mPart.data().length());
  }
  else if (actionOverwriteCursor->isChecked())
  {
    mAction = kOverwriteCursor;
    formatButton->setEnabled(enableFormat);
    updatePosition(mPart.selectionStart());
  }
  else if (actionReplaceSelection->isChecked())
  {
    mAction = kReplaceSelection;
    formatButton->setEnabled(enableFormat);
    updatePosition(mPart.selectionStart());
  }
}

void RecordDialog::recordClicked()
{
  // Tell part to start recording - local state is updated by signal on success
  if (mState == Idle || mState == PreRecord)
  {
    mState = PreRecord;
    emit record();
  }
  else if (mState == Recording)
  {
    mState = Stopping;
    emit stop();
  }
}

void RecordDialog::formatClicked()
{
  FormatDialog formatDlg(mFormat, this);

  if (formatDlg.exec())
  {
    mFormat = formatDlg.format();

    setFormatLabel();
  }
}

void RecordDialog::recording()
{
  mState = Recording;

  kdDebug(60606) << "RecordDialog::recording: "
                 << "\n";

  recordButton->setPixmap(SmallIcon(kStopIcon, mPart.instance()));
  recordLed->setState(KLed::On);
  mFlashCount = kFlashPeriod;

  doneButton->setText(i18n("&Done"));
  doneButton->setEnabled(false);
  formatButton->setEnabled(false);
}

void RecordDialog::stopped()
{
  mState = Idle;

  kdDebug(60606) << "RecordDialog::stopped: "
                 << "\n";

  recordButton->setPixmap(SmallIcon(kRecordIcon, mPart.instance()));
  recordLed->setState(KLed::Off);
  mFlashCount = kFlashPeriod;

  doneButton->setEnabled(true);
  actionChanged(); // update format button state
}

void RecordDialog::hideEvent(QHideEvent* event)
{
  if (!event->spontaneous())
  {
     emit finished();
  }
}

void RecordDialog::setFormatLabel()
{
  const QString fmt = i18n("Format: %1 Hz, %2 bit, %3");
  QString channelText;

  if (mFormat.channels == 1)
    channelText = i18n("Mono");
  else if (mFormat.channels == 2)
    channelText = i18n("Stereo");
  else
    channelText = i18n("%1 channels").arg(mFormat.channels);

  formatLabel->setText(
    fmt.arg(mFormat.sampleRate).arg(mFormat.bits).arg(channelText));
}

void RecordDialog::updatePosition(off_t pos)
{
  mPosition = pos;
  recordTime->setText(Sonik::toString(mPosition,
                                      mPart.data().sampleRate(),
                                      mPart.timeFormat()));
}

// TODO: Re-instate "Record to new file", but only show if shell supports it
