/***************************************************************************
                          krecord.cpp  -  description
                             -------------------
    begin                : Mon Jun 17 2002
    copyright            : (C) 2002 by Arnold Krille
    email                : arnold@arnoldarts.de
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "krecord.h"

#include "akbytestreamsender.h"
#include "session.h"
#include "vumeter.h"

#include "recordfile.h"
#include "startupwindow.h"

#include <arts/kaudiorecordstream.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <kdebug.h>
#include <kapplication.h>

KRecord::KRecord(QWidget *parent, const char *name )
	: KMainWindow(parent,name)
	, m_pCurrentRecordFile( 0 )
{
	kdDebug()<<"KRecord::KRecord( QWidget *"<<parent<<", const char* "<<name<<" )"<<endl; // (DEBUG)

	config = kapp->config();
	config->setGroup("StartUpWindow");
	bool _startupwindow = config->readBoolEntry( "RunOnStart", true );
	if( _startupwindow )
	{
		StartUpWindow *swin = new StartUpWindow( 0, "KRec::StartUpWindow" );
		connect( swin, SIGNAL( sShowOnStart(bool) ), this, SLOT( startUpWindow(bool) ) );
		swin->show();
	}

//	this->setFixedSize( 300, 200 );
//	this->setMaximumSize( 750, 550 );
//	this->setMinimumSize( 300, 200 );

	recording = playing = false;

	_canplay=false;
	_canrecord=false;
	b_arts = b_comp = true;

kdDebug()<<"KRecord::KRecord() Mainwidget"<<endl; // (DEBUG)
	_pListView = new KListView( this, "MainListView" );
	_pListView->setMinimumSize( 350, 200 );
	this->setCentralWidget( _pListView );
	_pListView->setResizeMode( QListView::LastColumn );
	_pListView->setColumnWidthMode( _pListView->addColumn( i18n("Sessions/Files"), _pListView->width()-20 ), QListView::Maximum );
	_pListView->setRootIsDecorated( true );
	_pListView->setAlternateBackground( QColor(255,100,100) );

	connect( _pListView, SIGNAL(contextMenu (KListView*,QListViewItem*,const QPoint&)), this, SLOT(showContextMenu(KListView*,QListViewItem*,const QPoint&)) );

	server = new KArtsServer( this );
	dispatcher = new KArtsDispatcher( this );
	m_recStream = new KAudioRecordStream( server, "KRec::In", server );
	m_recStream->usePolling( false );

	kdDebug()<<"KRecord::KRecord() aRts-Objects"<<endl; // (DEBUG)
	//kdDebug()<<"KRecord::KRecord() Arts::Synth_AMAN_PLAY"<<endl; // (DEBUG)
	aman_play = Arts::DynamicCast( server->server().createObject("Arts::Synth_AMAN_PLAY") );
	if(aman_play.isNull()) kdFatal()<<"Couldn't create Object 'Synth_AMAN_PLAY' !!!"<<endl;
	aman_play.title("KRec::Out");

	effects = m_recStream->effectStack();
	if( effects.isNull() )
		kdFatal() << "Couldn't get Object 'StereoEffectStack' !!!" << endl;

	//kdDebug()<<"KRecord::KRecord() Arts::StereoVolumeControl"<<endl; // (DEBUG
	volumecontrol = Arts::DynamicCast( server->server().createObject("Arts::StereoVolumeControl") );
	if(volumecontrol.isNull()) kdFatal()<<"Couldn't create Object 'StereoVolumeControl' !!!"<<endl;

	// StereoCompressor
	comp = Arts::DynamicCast( server->server().createObject("Arts::Synth_STEREO_COMPRESSOR") );
	if(comp.isNull()) {
		b_comp = false;
		//kdFatal()<<"Couldn't create Object 'Synth_STEREO_COMPRESSOR' !!!"<<endl;
	}

	//kdDebug()<<"KRecord::KRecord() Arts::ByteStreamToAudio"<<endl; // (DEBUG)
	bs2a = Arts::DynamicCast( server->server().createObject("Arts::ByteStreamToAudio") );
	if(bs2a.isNull()) kdFatal()<<"Couldn't create Object 'ByteStreamToAudio' !!!"<<endl;

	//kdDebug()<<"KRecord::KRecord() AKByteStreamSender"<<endl; // (DEBUG)
	aksender = new AKByteStreamSender( 0, server->server().minStreamBufferTime(), this );
	sender = ByteSoundProducerV2::_from_base( aksender );
	connect( aksender, SIGNAL(sCanPlay(bool)), this, SLOT(canPlay(bool)) );
	connect( aksender, SIGNAL(sPlayIsRunning()), this, SLOT(playIsRunning()) );
	connect( aksender, SIGNAL(sPlayStops()), this, SLOT(playStops()) );

kdDebug()<<"KRecord::KRecord() Arts::Connects"<<endl; // (DEBUG)
	Arts::connect( bs2a, "left", aman_play, "left" );
	Arts::connect( bs2a, "right", aman_play, "right" );
	Arts::connect( sender, "outdata", bs2a, "indata" );

kdDebug()<<"KRecord::KRecord() Starts"<<endl; // (DEBUG)
	aman_play.start();
	volumecontrol.start();
	if( b_comp ) comp.start();
	bs2a.start();
	vc_id = effects.insertBottom( volumecontrol, "VolumeControl" );
	if( b_comp ) comp_id = effects.insertTop( comp, "Compressor" );

kdDebug()<<"KRecord::KRecord() Actions"<<endl; // (DEBUG)
#ifdef __GNUC__
#	warning TODO(for all ;-): Fix shutdown problem
#endif
	// Try enabling the first line and disabling the second ;-)
	// KRec then won't quit properly. It will hang after the the mainwindow is deleted. Seems like some QObjects still alive or so...
	// I don't know why this is that way but perhaps you can tell me.
	// PS: Stefan Asserhäll send me a patch wich should solve the problem but it doesn't.
	//  I applied it also, since it had some other advantages..
	// PSS: Could be that his patch works except for my setup... Could someone test it?
	//
	// =/\= Arnold Krille =/\=
	//
	//(void*) KStdAction::quit( this, SLOT(close()), actionCollection() );
	(void*) KStdAction::quit( kapp, SLOT(quit()), actionCollection() );

	aNewSession = new KAction( i18n("&New Session..."), "folder_new", KShortcut( CTRL+Key_N ), this, SLOT(newSession()), actionCollection(), "new_session" );
	aNewFile = new KAction( i18n("&New File..."), "filenew", KShortcut( Key_N ), this, SLOT(newFile()), actionCollection(), "new_file" );

	aRecord = new KAction( i18n("&Record"), "krec_record", KShortcut( Key_R ), this, SLOT(startRec()), actionCollection(), "play_record" );
	aPlay = new KAction( i18n("&Play"), "player_play", KShortcut( Key_P ), this, SLOT(startPlay()), actionCollection(), "play_play" );
	aStop = new KAction( i18n("&Stop"), "player_stop", KShortcut( Key_S ), this, SLOT(stopRec()), actionCollection(), "play_stop" );
	aThru = new KToggleAction( i18n("Play Through"), "kmix", KShortcut( CTRL+Key_P ), actionCollection(), "play_thru" );
	connect( aThru, SIGNAL(toggled(bool)), this, SLOT(playthru(bool)) );
	aStartUpWindow = new KToggleAction( i18n("Show Startup-Window"), "wizard", KShortcut(), actionCollection(), "settings_startup" );
	aStartUpWindow->setChecked( _startupwindow );
	connect( aStartUpWindow, SIGNAL(toggled(bool)), this, SLOT( startUpWindow(bool) ) );

	KMainWindow::createGUI();

kdDebug()<<"KRecord::KRecord() ToolBar::VU-Meter/Level-Slider/LCDNumber"<<endl;
	vutimer = new QTimer( this, "vutimer" );
	vu = new VUMeter( toolBar("play"), "VU-Meter" );
	slider = new QSlider( 0, 200, 10, 0, Qt::Horizontal, toolBar("play"), "Slider" );
	lcd = new QLCDNumber( 3, toolBar("play"), "LCD" );
	connect( vutimer, SIGNAL(timeout()), this, SLOT(updateVU()) );
	connect( slider, SIGNAL(valueChanged(int)), this, SLOT(changedVolume(int)) );
	connect( slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)) );
	slider->setValue( 100 );

	toolBar( "play" )->insertWidget( 10, 100, vu );
	toolBar( "play" )->setItemAutoSized( 10, true );
	toolBar( "play" )->insertWidget( 11, 100, slider );
	toolBar( "play" )->alignItemRight( 11, true );
	toolBar( "play" )->insertWidget( 12, 50, lcd );
	toolBar( "play" )->alignItemRight( 12, true );

	if( b_comp )
	{
		Arts::GenericGuiFactory factory;
		Arts::Widget aw = factory.createGui( comp );
		w = new KArtsWidget( aw, toolBar("compressor") );
		w->setName( "kde toolbar widget" );

		toolBar( "compressor" )->insertWidget( 1, 400, w );
		toolBar( "compressor" )->setBarPos( KToolBar::Bottom );
	}
	else
	{
		toolBar( "compressor" )->close();
		KMessageBox::detailedSorry( this,
			i18n( "Your system is missing the Synth_STEREO_COMPRESSOR aRts module.\nYou will be able to use KRec but without the great functions of the compressor." ),
			i18n( "Possible reasons are:\n- You installed KRec on its own without the rest of kdemultimedia.\n- You installed everything correctly, but did not restart the aRts daemon\n and therefore it is not aware of the new effects.\n- This is a bug." ),
			i18n( "Unable to Find Compressor" ) );
	}

	vutimer->start( 10 );

	checkActions();
}

KRecord::~KRecord(){
kdDebug()<<"KRecord::~KRecord()"<<endl; // (DEBUG)
	if( b_comp ) delete w;
	vutimer->stop();
	stopRec();
	aman_play.stop();
	effects.remove( vc_id );
	if( b_comp ) effects.remove( comp_id );
	//effects.stop(); /// The effectrack is stopped when the m_recStream gets deleted.
	volumecontrol.stop();
	if( b_comp ) comp.stop();
	bs2a.stop();
	//sender.stop(); /// The sender shouldn't be running...

	aman_play = Arts::Synth_AMAN_PLAY::null();
	effects = Arts::StereoEffectStack::null();
	volumecontrol = Arts::StereoVolumeControl::null();
	if( b_comp ) comp = Arts::Synth_STEREO_COMPRESSOR::null();
	bs2a = Arts::ByteStreamToAudio::null();
	sender = Arts::ByteSoundProducerV2::null();

	/// this doesn't need to be deleted since they have KMainWindow as parent and get deleted by QObject, I think.
	//m_recStream->stop();
	//delete m_recStream;
	//delete server;
	//delete dispatcher;
	//delete w;
kdDebug()<<"~KRecord() - Bye"<<endl;
}

void KRecord::startRec(){
	if(!recording){
		//kdDebug()<<"KRecord::startRec()"<<endl; // (DEBUG)
		m_recStream->start( 44100, 16, 2 );
		recording = true;
	}
	//else kdDebug()<<"Recording already running. "<<endl; // (DEBUG)
	checkActions();
}

void KRecord::startPlay(){
	if(!playing){
		//kdDebug()<<"KRecord::startPlay()"<<endl; // (DEBUG)
		sender.start();
	}
}

void KRecord::stopRec(){
	if(recording){
		//kdDebug()<<endl<<"KRecord::stopRec()"<<endl; // (DEBUG)
		m_recStream->stop();
		recording = false;
	}
	//else kdDebug()<<"Already stopped. "<<endl; // (DEBUG)
	checkActions();
}

void KRecord::newSession(){
	//kdDebug()<<"KRecord::newSession()"<<endl; // (DEBUG)
	QString filename = KFileDialog::getSaveFileName( "", "*.raw", this, "New Session" );
	if( ! filename.isNull() )
	{
		Session *newSession = new Session( filename, _pListView, this );
		connect( newSession, SIGNAL( sNewRecFile( RecordFile * ) ), this, SLOT( setRecFile( RecordFile * ) ) );
		connect( newSession, SIGNAL(sNewPlayFile(RecordFile*)), aksender, SLOT(file(RecordFile*)) );
		checkActions();
	}
}

void KRecord::newFile(){
	//kdDebug()<<"KRecord::newFile()"<<endl; // (DEBUG)
	QString filename = KFileDialog::getSaveFileName( "", "*.raw", this, "New File" );
	if( ! filename.isNull() )
	{
		RecordFile *newRecFile = new RecordFile( _pListView, filename, this );
		connect( newRecFile, SIGNAL( sNewRecFile( RecordFile * ) ), this, SLOT( setRecFile( RecordFile * ) ) );
		connect( newRecFile, SIGNAL(sNewPlayFile(RecordFile*)), aksender, SLOT(file(RecordFile*)) );
		checkActions();
	}
}

void KRecord::checkActions(){
	if( recording )
	{
		actionCollection()->action("play_record")->setEnabled(false);
		actionCollection()->action("play_stop")->setEnabled(true);
	}
	else
	{
		actionCollection()->action("play_record")->setEnabled(true);
		actionCollection()->action("play_stop")->setEnabled(false);
	}
	if( playing || !_canplay )
		actionCollection()->action("play_play")->setEnabled(false);
	else
		actionCollection()->action("play_play")->setEnabled(true);
}

void KRecord::showContextMenu (KListView*, QListViewItem* item, const QPoint& qpoint){
	if( ! item )
		return;
	switch( item->rtti() )
	{
		case 1001:
			static_cast<RecordFile*>(item)->menu()->popup( qpoint );
			break;
		case 1002:
			static_cast<Session*>(item)->menu()->popup( qpoint );
			break;
		default:
			kdWarning() << "unknown ListView Item in " << k_funcinfo << endl;
			break;
	}

}

void KRecord::updateVU(){
	vu->newSValue( volumecontrol.currentVolumeLeft(), volumecontrol.currentVolumeRight() );
}

void KRecord::playthru( bool yes ){
	if(yes)
	{
		Arts::connect(effects,"outleft",aman_play,"left");
		Arts::connect(effects,"outright",aman_play,"right");
	}
	else
	{
		Arts::disconnect(effects,"outleft",aman_play,"left");
		Arts::disconnect(effects,"outright",aman_play,"right");
	}
}

void KRecord::setRecFile( RecordFile * recFile )
{
	kdDebug() << k_funcinfo << endl;
	// only do something if a different RecordFile was selected
	if( m_pCurrentRecordFile != recFile )
	{
		if( recFile && ! recFile->openrec() )
			recFile->openFileRec();
		if( m_pCurrentRecordFile )
		{
			disconnect( m_recStream, SIGNAL( data( QByteArray & ) ), m_pCurrentRecordFile, SLOT( receiveData( QByteArray & ) ) );
			m_pCurrentRecordFile->closeFile( true );
		}
		if( ! recFile || ( recFile && recFile->openrec() ) )
		{
			m_pCurrentRecordFile = recFile;
			if( m_pCurrentRecordFile )
			{
				connect( m_recStream, SIGNAL( data( QByteArray & ) ), m_pCurrentRecordFile, SLOT( receiveData( QByteArray & ) ) );
				canRecord( true );
			}
		}
		// XXX: else what? What happens if I set a RecordFile and openFileRec() wasn't succesfull?
	}
}

void KRecord::startUpWindow( bool on ){
	config->setGroup( "StartUpWindow" );
	config->writeEntry("RunOnStart", on);
	config->sync();
	aStartUpWindow->setChecked( on );
}

#include "krecord.moc"

// vim:sw=4:ts=4
