/*

 Project Carmack 0.01  (AKA Media Library Prototype 01/02)
 Copyright John Ryland, 2005

*/

using namespace std;

#include <iostream>
#include <list>
#include <map>

#include <assert.h>
#include <math.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/soundcard.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <avformat.h>
#include <avcodec.h>

#include "Types/Frame.hpp"
#include "Types/Thread.hpp"
#include "Types/Module.hpp"


#define WIDTH 160
#define HEIGHT 120




/*
class ModulesThread : public Thread, public DispatchInterface {
public:
    void execute( void* )
    {
        for (;;) {
            CommandStruct *command = buffer.remove();
            command->module->command( command->command, command->arg );
        }
    }
    
    void dispatch( CommandStruct *command )
    {
        buffer.add( command );
    }

private:
    CommandQueue buffer;
};
*/




static void staticDispatch( Address address, Commands command, const void *arg )
{
    moduleMapper()->dispatchCommand( address, command, arg );
}

    


struct FFMpegStreamPacket {
    AVPacket *packet;
};





void ProcessMessages();







Module *a, *b, *c, *d;


void registerModules()
{
    moduleMapper()->addModule( new OSSRenderer );
//    moduleMapper()->addModule( d = new YUVRenderer );
    moduleMapper()->addModule( d = new DirectDrawRenderer );
    moduleMapper()->addModule( new MP3DecodeModule );
//    moduleMapper()->addModule( new FFMpegMuxModule );
    moduleMapper()->addModule( new MpegDecodeModule );
//    moduleMapper()->addModule( new MP3SourceModule );
//    moduleMapper()->addModule( new StreamDemuxModule );
    moduleMapper()->addModule( c = new MpegEncodeModule );
//    moduleMapper()->addModule( b = new Splitter );
    moduleMapper()->addModule( new FFMpegSourceModule );
//    moduleMapper()->addModule( a = new VideoCameraSourceModule );
}

void playFile( const char *filename )
{
    pipelineMgr->addSource( "FRAME_ID_URL_SOURCE" );
    pipelineMgr->addDestination( "FRAME_ID_RENDERED_AUDIO" );
    pipelineMgr->addDestination( "FRAME_ID_RENDERED_VIDEO" );

    int length = strlen(filename) + 1;
    Frame file( "FRAME_ID_URL_SOURCE", memcpy(new char[length], filename, length) );
    file.ref();
    
    //pipelineMgr->start( &file );
    pipelineMgr->execute( &file );
}


void displayCamera()
{
    pipelineMgr->addSource( "FRAME_ID_VIDEO_CAMERA_SOURCE" );
    pipelineMgr->addDestination( "FRAME_ID_RENDERED_VIDEO" );
    pipelineMgr->start( new Frame( "FRAME_ID_VIDEO_CAMERA_SOURCE", 0 ) );
}

void reEncodeFile( const char *filename )
{
    pipelineMgr->addSource( "FRAME_ID_URL_SOURCE" );
    pipelineMgr->addDestination( "FRAME_ID_URL_SINK" );

    int length = strlen(filename) + 1;
    Frame file( "FRAME_ID_URL_SOURCE", memcpy(new char[length], filename, length) );
    file.ref();
    
    pipelineMgr->start( &file );
}

void recordVideo()
{
    pipelineMgr->addSource( "FRAME_ID_VIDEO_CAMERA_SOURCE" );
    pipelineMgr->addDestination( "FRAME_ID_URL_SINK" );
    pipelineMgr->addDestination( "FRAME_ID_RENDERED_VIDEO" );
    pipelineMgr->start( new Frame( "FRAME_ID_VIDEO_CAMERA_SOURCE", 0 ) );
}

int main( int argc, char** argv )
{
    registerModules();
    pipelineMgr = new PipelineManager;
/*    
    Frame f;
    printf("Connecting together: %s -> %s\n", a->name(), b->name() );
    staticDispatch( b, Init, 0 );
    a->connectTo( b, f );
//    b->connectedFrom( a, f );
    
    printf("Connecting together: %s -> %s\n", b->name(), c->name() );
    staticDispatch( c, Init, 0 );
    b->connectTo( c, f );
    
    printf("Connecting together: %s -> %s\n", b->name(), d->name() );
    staticDispatch( d, Init, 0 );
    b->connectTo( d, f );
*/
    playFile( (argc > 1) ? argv[1] : "test.mpg" );
    //reEncodeFile( (argc > 1) ? argv[1] : "test.mpg" );
    //displayCamera();
    //recordVideo();
}

