// rdcueedit.cpp
//
// Cueing Editor for RDLogLine-based Events
//
//   (C) Copyright 2013-2020 Fred Gleason <fredg@paravelsystems.com>
//
//   This program is free software; you can redistribute it and/or modify
//   it under the terms of the GNU General Public License version 2 as
//   published by the Free Software Foundation.
//
//   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 <qpainter.h>
#include <qmessagebox.h>

#include <q3frame.h>

#include "rdconf.h"
#include "rdcueedit.h"

RDCueEdit::RDCueEdit(QWidget *parent)
  : RDWidget(parent)
{
  edit_height=325;
  edit_slider_pressed=false;
  edit_shift_pressed=false;
  edit_right_click_stop=false;
  edit_event_player=NULL;
  edit_start_rml="";
  edit_stop_rml="";

  //
  // Create Palettes
  //
  edit_play_color=
    QPalette(QColor(BUTTON_PLAY_BACKGROUND_COLOR),backgroundColor());
  edit_start_color=palette();
  edit_start_color.setColor(QColorGroup::Foreground,RD_CUEEDITOR_START_MARKER);

  edit_position_label=new QLabel(this);
  edit_position_label->setGeometry(0,0,sizeHint().width()-30,30);
  edit_position_label->setBackgroundColor(QColor(Qt::white));
  edit_position_label->setLineWidth(1);
  edit_position_label->setMidLineWidth(0);
  edit_position_label->setFrameStyle(Q3Frame::Box|Q3Frame::Plain);

  edit_position_bar=new RDMarkerBar(this);
  edit_position_bar->setGeometry(85,8,sizeHint().width()-200,14);

  edit_up_label=new QLabel("00:00:00",this);
  edit_up_label->setGeometry(5,8,70,14);
  edit_up_label->setBackgroundColor(Qt::white);
  edit_up_label->setFont(labelFont());
  edit_up_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);

  edit_down_label=new QLabel("00:00:00",this);
  edit_down_label->setGeometry(sizeHint().width()-110,8,70,14);
  edit_down_label->setBackgroundColor(Qt::white);
  edit_down_label->setFont(labelFont());
  edit_down_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter);

  //
  // Position Slider
  //
  edit_slider=new RDSlider(RDSlider::Right,this);
  edit_slider->setGeometry(60,30,sizeHint().width()-150,50);
  edit_slider->setKnobSize(50,50);
  edit_slider->setKnobColor(QColor(RD_CUEEDITOR_KNOB_COLOR));
  connect(edit_slider,SIGNAL(sliderMoved(int)),
	  this,SLOT(sliderChangedData(int)));
  connect(edit_slider,SIGNAL(sliderPressed()),this,SLOT(sliderPressedData()));
  connect(edit_slider,SIGNAL(sliderReleased()),
	  this,SLOT(sliderReleasedData()));

  //
  // Button Area
  //
  QLabel *label=new QLabel(this);
  label->setGeometry(0,85,sizeHint().width()-30,60);
  label->setBackgroundColor(QColor(Qt::gray));
  label->setLineWidth(1);
  label->setMidLineWidth(0);
  label->setFrameStyle(Q3Frame::Box|Q3Frame::Plain);

  //
  //  Audition Button
  //
  edit_audition_button=
    new RDTransportButton(RDTransportButton::PlayBetween,this);
  edit_audition_button->setGeometry(sizeHint().width()/2-130,90,80,50);
  edit_audition_button->
    setPalette(QPalette(backgroundColor(),QColor(Qt::gray)));
  edit_audition_button->setFont(buttonFont());
  edit_audition_button->
    setDisabled((rda->station()->cueCard()<0)||(rda->station()->cuePort()<0));
  connect(edit_audition_button,SIGNAL(clicked()),
	  this,SLOT(auditionButtonData()));

  //
  //  Pause Button
  //
  edit_pause_button=new RDTransportButton(RDTransportButton::Pause,this);
  edit_pause_button->setGeometry(sizeHint().width()/2-40,90,80,50);
  edit_pause_button->
    setPalette(QPalette(backgroundColor(),QColor(Qt::gray)));
  edit_pause_button->setFont(buttonFont());
  edit_pause_button->
    setDisabled((rda->station()->cueCard()<0)||(rda->station()->cuePort()<0));
  connect(edit_pause_button,SIGNAL(clicked()),this,SLOT(pauseButtonData()));

  //
  //  Stop Button
  //
  edit_stop_button=new RDTransportButton(RDTransportButton::Stop,this);
  edit_stop_button->setGeometry(sizeHint().width()/2+50,90,80,50);
  edit_stop_button->setOnColor(QColor(Qt::red));
  edit_stop_button->
    setPalette(QPalette(backgroundColor(),QColor(Qt::gray)));
  edit_stop_button->setFont(buttonFont());
  edit_stop_button->
    setDisabled((rda->station()->cueCard()<0)||(rda->station()->cuePort()<0));
  connect(edit_stop_button,SIGNAL(clicked()),this,SLOT(stopButtonData()));

  //
  // Start Marker Control
  //
  edit_start_button=new RDPushButton(this);
  edit_start_button->setToggleButton(true);
  edit_start_button->setGeometry(0,155,66,45);
  edit_start_button->setFlashColor(backgroundColor());
  edit_start_button->setFlashPeriod(RD_CUEEDITOR_BUTTON_FLASH_PERIOD);
  edit_start_button->setPalette(QPalette(QColor(RD_CUEEDITOR_START_MARKER),
					   backgroundColor()));
  edit_start_button->setFont(buttonFont());
  edit_start_button->setText(tr("Start"));
  connect(edit_start_button,SIGNAL(clicked()),this,SLOT(startClickedData()));

  //
  // End Marker Control
  //
  edit_end_button=new RDPushButton(this);
  edit_end_button->setToggleButton(true);
  edit_end_button->setGeometry(90,155,66,45);
  edit_end_button->setFlashColor(backgroundColor());
  edit_end_button->setFlashPeriod(RD_CUEEDITOR_BUTTON_FLASH_PERIOD);
  edit_end_button->setPalette(QPalette(QColor(RD_CUEEDITOR_START_MARKER),
				       backgroundColor()));
  edit_end_button->setFont(buttonFont());
  edit_end_button->setText(tr("End"));
  connect(edit_end_button,SIGNAL(clicked()),this,SLOT(endClickedData()));

  //
  // Recue Marker Control
  //
  edit_recue_button=new RDPushButton(this);
  edit_recue_button->setToggleButton(true);
  edit_recue_button->setGeometry(180,155,66,45);
  edit_recue_button->setFlashColor(backgroundColor());
  edit_recue_button->setFlashPeriod(RD_CUEEDITOR_BUTTON_FLASH_PERIOD);
  edit_recue_button->setPalette(QPalette(QColor(RD_CUEEDITOR_START_MARKER),
				       backgroundColor()));
  edit_recue_button->setFont(buttonFont());
  edit_recue_button->setText(tr("&Recue"));
  connect(edit_recue_button,SIGNAL(clicked()),this,SLOT(recue()));

  //
  // Audition Stop Timer
  //
  edit_audition_timer=new QTimer(this);
  connect(edit_audition_timer,SIGNAL(timeout()),this,SLOT(auditionTimerData()));

  //
  // Play Deck
  //
  edit_play_deck=new RDPlayDeck(rda->cae(),RDPLAYDECK_AUDITION_ID,this);
  connect(edit_play_deck,SIGNAL(stateChanged(int,RDPlayDeck::State)),this,
	  SLOT(stateChangedData(int,RDPlayDeck::State)));
  connect(edit_play_deck,SIGNAL(position(int,int)),
	  this,SLOT(positionData(int,int)));
}


RDCueEdit::~RDCueEdit()
{
}


QSize RDCueEdit::sizeHint() const
{
  return QSize(610,215);
} 


QSizePolicy RDCueEdit::sizePolicy() const
{
  return QSizePolicy(QSizePolicy::Fixed,QSizePolicy::Fixed);
}


void RDCueEdit::setRml(RDEventPlayer *player,const QString &start_rml,
		       const QString &stop_rml)
{
  edit_event_player=player;
  edit_start_rml=start_rml;
  edit_stop_rml=stop_rml;
}


bool RDCueEdit::initialize(RDLogLine *logline)
{
  edit_logline=logline;
  edit_position_bar->setLength(edit_logline->forcedLength());
  edit_start_button->setOn(false);
  if(!(edit_logline->status()==RDLogLine::Scheduled) && 
     !(edit_logline->status()==RDLogLine::Paused)) {
    edit_start_button->hide();
    edit_end_button->hide();
  }
  else {
    edit_start_button->show();
    edit_end_button->show();
  }
  edit_slider->setRange(0,edit_logline->forcedLength());
  edit_slider->setValue(edit_logline->playPosition());
  sliderChangedData(edit_logline->playPosition());
  startClickedData();
  edit_stop_button->on();
  edit_position_bar->
    setMarker(RDMarkerBar::Play,edit_logline->playPosition());
  edit_position_bar->
    setMarker(RDMarkerBar::Start,edit_logline->playPosition());
  edit_position_bar->
    setMarker(RDMarkerBar::End,edit_logline->endPoint());
  edit_slider->setValue(edit_logline->playPosition());
  UpdateCounters();
  return true;
}


unsigned RDCueEdit::playPosition(RDMarkerBar::Marker marker) const
{
  return edit_position_bar->marker(marker);
}


void RDCueEdit::stop()
{
  if(edit_play_deck->state()==RDPlayDeck::Playing) {
    edit_play_deck->stop();
  }
}


void RDCueEdit::recue()
{
  edit_position_bar->setMarker(RDMarkerBar::Start,0);
  if(edit_start_button->isOn()) {
    edit_slider->setValue(0);
  }
  UpdateCounters();
}


void RDCueEdit::sliderChangedData(int pos)
{
  if(edit_start_button->isOn()) {
    edit_position_bar->setMarker(RDMarkerBar::Start,pos);
  }
  else {
    if(edit_end_button->isOn()) {
      edit_position_bar->setMarker(RDMarkerBar::End,pos);
    }
    else {
      edit_position_bar->setMarker(RDMarkerBar::Play,pos);
    }
  }
  UpdateCounters();
}


void RDCueEdit::sliderPressedData()
{
  if(edit_play_deck->state()==RDPlayDeck::Playing) {
    edit_play_deck->stop();
    edit_slider_pressed=true;
  }
}


void RDCueEdit::sliderReleasedData()
{
  if(edit_slider_pressed) {
    auditionButtonData();
    edit_slider_pressed=false;
  }
}


void RDCueEdit::auditionButtonData()
{
  int start_pos=edit_slider->value();
  int play_len=-1;

  if(edit_play_deck->state()==RDPlayDeck::Playing) {
    return;
  }
  edit_play_deck->setCard(rda->station()->cueCard());
  edit_play_deck->setPort(rda->station()->cuePort());
  if(!edit_play_deck->setCart(edit_logline,false)) {
    return;
  }
  if(edit_start_button->isOn()) {
    if(edit_play_deck->state()==RDPlayDeck::Stopped) {
      start_pos=edit_position_bar->marker(RDMarkerBar::Start);
    }
    if(edit_play_deck->state()==RDPlayDeck::Paused) {
      start_pos=edit_play_deck->currentPosition();
    }
    play_len=edit_position_bar->marker(RDMarkerBar::End)-start_pos;
  }
  else {
    if(edit_end_button->isOn()) {
      if(edit_play_deck->state()==RDPlayDeck::Stopped) {
	play_len=RD_CUEEDITOR_AUDITION_PREROLL;
	if(play_len>(edit_position_bar->marker(RDMarkerBar::End)-
		     edit_position_bar->marker(RDMarkerBar::Start))) {
	  play_len=edit_position_bar->marker(RDMarkerBar::End)-
	    edit_position_bar->marker(RDMarkerBar::Start);
	}
	start_pos=edit_position_bar->marker(RDMarkerBar::End)-play_len;	  
      }
    }
    else {
      if((edit_play_deck->state()==RDPlayDeck::Stopped)&&
	 (!edit_slider_pressed)) {
	edit_start_pos=edit_slider->value();
      }
    }
  }
  edit_play_deck->play(start_pos);
  if(play_len>=0) {
    edit_audition_timer->start(play_len,true);
  }
  if((!edit_start_rml.isEmpty())&&(edit_event_player!=NULL)) {
    edit_event_player->exec(edit_logline->resolveWildcards(edit_start_rml));
  }
}


void RDCueEdit::pauseButtonData()
{
  if(edit_play_deck->state()==RDPlayDeck::Playing) {
    edit_play_deck->pause();
  }
}


void RDCueEdit::stopButtonData()
{
  switch(edit_play_deck->state()) {
      case RDPlayDeck::Playing:
      case RDPlayDeck::Paused:
	edit_play_deck->stop();
	break;

      default:
	break;
  }
}


void RDCueEdit::stateChangedData(int id,RDPlayDeck::State state)
{
  if(id!=RDPLAYDECK_AUDITION_ID) {
    return;
  }
  switch(state) {
      case RDPlayDeck::Playing:
	Playing(id);
	break;

      case RDPlayDeck::Stopping:
	break;

      case RDPlayDeck::Paused:
	Paused(id);
	break;

      case RDPlayDeck::Stopped:
	Stopped(id);
	break;

      case RDPlayDeck::Finished:
	Stopped(id);
	break;
  }
}


void RDCueEdit::positionData(int id,int msecs)
{
  if(id!=RDPLAYDECK_AUDITION_ID) {
    return;
  }
  edit_position_bar->setMarker(RDMarkerBar::Play,msecs);
  if((!edit_start_button->isOn())&&(!edit_end_button->isOn())) {
    edit_slider->setValue(msecs);
  }
  UpdateCounters();
}


void RDCueEdit::auditionTimerData()
{
  edit_play_deck->stop();
}


void RDCueEdit::startClickedData()
{
  if(edit_end_button->isOn()) {
    edit_end_button->toggle();
    SetEndMode(false);
  }
  SetStartMode(edit_start_button->isOn());
}


void RDCueEdit::endClickedData()
{
  if(edit_start_button->isOn()) {
    edit_start_button->toggle();
    SetStartMode(false);
  }
  SetEndMode(edit_end_button->isOn());
}


void RDCueEdit::SetStartMode(bool state)
{
  if(state) {
    edit_slider->setRange(0,edit_position_bar->marker(RDMarkerBar::End));
    edit_slider->setGeometry(60,30,
			     (int)(50.0+((double)(sizeHint().width()-200)*
					 (double)edit_position_bar->
					 marker(RDMarkerBar::End)/
					 (double)edit_logline->
					 forcedLength())),50);
    edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Start));
    edit_slider->setKnobColor(RD_CUEEDITOR_START_MARKER);
    edit_audition_button->setAccentColor(RD_CUEEDITOR_START_MARKER);
    edit_start_button->setFlashingEnabled(true);
    edit_up_label->setPalette(edit_start_color);
    edit_down_label->setPalette(edit_start_color);
    UpdateCounters();
  }
  else {
    edit_slider->setRange(0,edit_logline->forcedLength());
    edit_slider->setGeometry(60,30,sizeHint().width()-150,50);
    edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Play));
    edit_slider->setKnobColor(RD_CUEEDITOR_PLAY_MARKER); 
    edit_audition_button->setAccentColor(RD_CUEEDITOR_PLAY_MARKER);
    edit_start_button->setFlashingEnabled(false);
    edit_up_label->setPalette(palette());
    edit_down_label->setPalette(palette());
    UpdateCounters();
  }
}


void RDCueEdit::SetEndMode(bool state)
{
  if(state) {
    edit_slider->setRange(edit_position_bar->marker(RDMarkerBar::Start),
			  edit_logline->forcedLength());
    edit_slider->setGeometry((int)(60.0+(double)(sizeHint().width()-200)*
				   (double)edit_position_bar->
				   marker(RDMarkerBar::Start)/
				   (double)edit_logline->forcedLength()),
			     30,(int)(50.0+((double)(sizeHint().width()-200)*
					     ((double)edit_logline->
					      forcedLength()-
					      (double)edit_position_bar->
					      marker(RDMarkerBar::Start))/
					     (double)edit_logline->
					     forcedLength())),50);
    edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::End));
    edit_slider->setKnobColor(RD_CUEEDITOR_START_MARKER);
    edit_audition_button->setAccentColor(RD_CUEEDITOR_START_MARKER);
    edit_end_button->setFlashingEnabled(true);
    edit_up_label->setPalette(edit_start_color);
    edit_down_label->setPalette(edit_start_color);
    UpdateCounters();
  }
  else {
    edit_slider->setRange(0,edit_logline->forcedLength());
    edit_slider->setGeometry(60,30,sizeHint().width()-150,50);
    edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Play));
    edit_slider->setKnobColor(RD_CUEEDITOR_PLAY_MARKER); 
    edit_audition_button->setAccentColor(RD_CUEEDITOR_PLAY_MARKER);
    edit_end_button->setFlashingEnabled(false);
    edit_up_label->setPalette(palette());
    edit_down_label->setPalette(palette());
    UpdateCounters();
  }
}

/*
void RDCueEdit::ShowAudioControls(bool state)
{
  if(state) {
    edit_height=325;
    edit_slider->show();
    edit_up_label->show();
    edit_down_label->show();
    edit_audition_button->show();
    edit_pause_button->show();
    edit_position_bar->show();
    edit_position_label->show();
  }
  else {
    edit_height=170;
    edit_slider->hide();
    edit_up_label->hide();
    edit_down_label->hide();
    edit_audition_button->hide();
    edit_pause_button->hide();
    edit_position_bar->hide();
    edit_position_label->hide();
  }
}
*/

void RDCueEdit::Playing(int id)
{
  edit_audition_button->on();
  edit_pause_button->off();
  edit_stop_button->off();
  edit_right_click_stop=true;
}


void RDCueEdit::Paused(int id)
{
  if(!edit_slider_pressed) {
    edit_audition_button->off();
    edit_pause_button->on();
    edit_stop_button->off();
    ClearChannel();
    edit_right_click_stop=false;
  }
}


void RDCueEdit::Stopped(int id)
{
  if(!edit_slider_pressed) {
    edit_audition_button->off();
    edit_pause_button->off();
    edit_stop_button->on();
    ClearChannel();
    edit_right_click_stop=false;
  }
  if(edit_start_button->isOn()) {
    edit_position_bar->
      setMarker(RDMarkerBar::Play,edit_position_bar->marker(RDMarkerBar::Start));
    edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::Start));
  }
  else {
    if(edit_end_button->isOn()) {
      edit_slider->setValue(edit_position_bar->marker(RDMarkerBar::End));
    }
    else {
      edit_position_bar->setMarker(RDMarkerBar::Play,edit_start_pos);
      edit_slider->setValue(edit_start_pos);
    }
  }
}


void RDCueEdit::UpdateCounters()
{
  if(edit_start_button->isOn()) {
   edit_up_label->
     setText(RDGetTimeLength(edit_position_bar->marker(RDMarkerBar::Start),true));
   edit_down_label->
     setText(RDGetTimeLength(edit_logline->
			    forcedLength()-edit_position_bar->
			    marker(RDMarkerBar::Start),true));
  }
  else {
    if(edit_end_button->isOn()) {
      edit_up_label->
	setText(RDGetTimeLength(edit_position_bar->marker(RDMarkerBar::End),
				true));
      edit_down_label->
	setText(RDGetTimeLength(edit_logline->
				forcedLength()-edit_position_bar->
				marker(RDMarkerBar::End),true));
    }
    else {
      edit_up_label->
	setText(RDGetTimeLength(edit_position_bar->marker(RDMarkerBar::Play),
				true));
      edit_down_label->
	setText(RDGetTimeLength(edit_logline->
				forcedLength()-edit_position_bar->
				marker(RDMarkerBar::Play),true));
    }
  }
}


void RDCueEdit::ClearChannel()
{
  if(rda->cae()->playPortActive(edit_play_deck->card(),edit_play_deck->port(),
				edit_play_deck->stream())) {
    return;
  }
  if((!edit_stop_rml.isEmpty())&&(edit_event_player!=NULL)) {
    edit_event_player->exec(edit_stop_rml);
  }
}


void RDCueEdit::wheelEvent(QWheelEvent *e)
{
  if(edit_audition_button->isShown()) {
    if(edit_play_deck->state()==RDPlayDeck::Playing) {
      edit_play_deck->pause();
    }
    if(edit_shift_pressed) {
      edit_slider->setValue(edit_slider->value()+(e->delta()*10)/12);
      }
    else {
      edit_slider->setValue(edit_slider->value()+(e->delta()*100)/12);
      }
    sliderChangedData(edit_slider->value());
  }
}


void RDCueEdit::mousePressEvent(QMouseEvent *e)
{
  switch(e->button()) {
      case Qt::RightButton:
        if(edit_audition_button->isShown()) {
          if(edit_right_click_stop) {
            stopButtonData();
            }
          else {
 	    auditionButtonData();
            }
          }
        break;

      case Qt::MidButton:
        if(edit_audition_button->isShown()) {
          if(edit_logline->forcedLength()>10000) {
            if(edit_play_deck->state()==RDPlayDeck::Playing) {
              edit_play_deck->pause();
              }
            edit_slider->setValue((edit_logline->forcedLength())-10000);
            sliderChangedData(edit_slider->value());
            }
          auditionButtonData();
          }
        break;

      default:
	QWidget::mousePressEvent(e);
	break;
  }
}


void RDCueEdit::keyPressEvent(QKeyEvent *e)
{
  switch(e->key()) {
      case Qt::Key_Shift:
        edit_shift_pressed=true;
  	break;

      default:
	e->ignore();
	break;
  }
}


void RDCueEdit::keyReleaseEvent(QKeyEvent *e)
{
  switch(e->key()) {
      case Qt::Key_Shift:
        edit_shift_pressed=false;
	QWidget::keyPressEvent(e);
  	break;

      default:
	QWidget::keyPressEvent(e);
	break;
  }
}