/*
 Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.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.

 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include <IO/Input/TeleTextInput.hpp>
#include <IO/Manager/IOManager.hpp>
#include <IO/Manager/IOBuffer.hpp>
#include <IO/osx/TVHardware.hpp>

#import <lib/bt848.h>
#import <lib/Bt8xxLib.h>
#import <lib/bt848.h>
#import <lib/i2c.h>
#import <lib/Tuner.h>

#import <ctype.h>
#import <unistd.h>
#import <aletv_export.h>

#import <util/Loader.h>

extern "C" int  MapVBIMem  ( void ** at , unsigned int * size );
extern "C" int BT848_Wait4VBI();
extern "C" void vbi_decodeline( unsigned char* outputBuffer );

extern TVTUNERID TunerType;
extern TVCARDID CardType;

char vbi_header[64];
char vbi_xpacket[64];

int debug = 0;

TeleTextInput::TeleTextInput( const string & aName, IODeviceID anID )
 : IOInput( aName, anID ), mWorkThread( aName, true )
{
    init();
}

TeleTextInput::~TeleTextInput()
{
    finit();
}

void * teleTextThreadEntry( void * _this )
{
    ((TeleTextInput*) _this )->grab();
    
    return 0;
}

void TeleTextInput::grab()
{    
    static unsigned char outputBuffer[2048*4*20];
    
    while( mWorkThread.serviceCancellation() != IOThread::ioStop ) {

        BT848_Wait4VBI();
        
        memcpy( outputBuffer, mVBIBuffer, mVBIBufferSize );
        
        vbi_decodeline( ( unsigned char*) outputBuffer );        
    }
}

bool TeleTextInput::start() 
{ 
    if( mInited && ! mStarted && isAttached() && TVHardware::start( IODescription::ioIn, getDeviceID(), this ) ) {

        mWorkThread.start( teleTextThreadEntry, this );
    
        mStarted = true;
    }
    return mStarted;
}

bool TeleTextInput::stop() 
{ 
    if( mStarted && TVHardware::stop( IODescription::ioIn, getDeviceID(), this ) ) {

        mWorkThread.stop();
        
        mStarted = false;
    }
    
    return mStarted;
}

size_t TeleTextInput::frameSize()
{
    return mVBIBufferSize;
}

void TeleTextInput::vbiCallback( TeleTextInput * _this, vt_event * event )
{
    ((TeleTextInput*) _this )->handleVBIEvent( event );
}

void TeleTextInput::handleVBIEvent( vt_event * ev )
{
    unsigned char *p;
    struct vt_page *vtp;
    
    debug = 0;
    
    switch (ev->type) {
    case EV_HEADER:
        p = (u8*) ev->p1;
        if (debug > 1)
            fprintf(stderr,"vbi header: %.32s \r", p+8);
        memcpy(vbi_header,p+8,32);
        vbi_header[32] = 0;
        break;
    case EV_PAGE:
        vtp = (vt_page*) ev->p1;
        if ( 1 /*debug > 1*/)
            fprintf( stdout,"vbi page: %03x.%02x \n", vtp->pgno, vtp->subno);

#if 0
        if ( 1 /*vtp->pgno == _vbi_page*/) {
            if (debug)
                fprintf(stderr,"got vtx page %03x\n",vtp->pgno);
            if (vtx_message) {
                tt = vtx_to_tt(vtp);
                tt = tt_pick_subtitle(tt);
                if (debug)
                    dump_tt(tt);
                if (vtx_message)
                    vtx_message(tt->len ? tt : NULL);
            }
        }
#endif        
        if( vtp != 0 ) {
            TeleTextInput::VTPage * page = (TeleTextInput::VTPage*) malloc( sizeof( TeleTextInput::VTPage ));
            
            memcpy( &page->page, vtp, sizeof(  vt_page ) );
            page->channel = 0;
            
            IOBuffer * buffer = IOBuffer::initWithBuffer( (const char*) page, 
                                                          sizeof(TeleTextInput::VTPage), getNextBlockNumber() );
        
            if( buffer ) {
        
                push( buffer );
            
                buffer->release();
            }
        }        

        break;
    case EV_XPACKET:
        p = (u8*)ev->p1;
        if (debug > 1)
            fprintf(stderr,"vbi xpacket: %x %x %x %x - %.20s\n",
                    p[0],p[1],p[3],p[5],p+20);
        if (0 != memcmp(vbi_xpacket,p+20,20)) {
            memcpy(vbi_xpacket,p+20,20);
            vbi_xpacket[20] = 0;
            if (debug)
                fprintf(stderr,"vbi station: %s\n",vbi_xpacket);
        }
        break;
    default:
        if (debug)
            fprintf(stderr,"vbi unknown: type=%d\n",ev->type);
        break;
    }
}

void TeleTextInput::init()
{
    if( TVHardware::init( IODescription::ioIn, getDeviceID(), this ) != true ) { 	

        printf( "TeleTextInput::init failed to initialize %s\n", getName().c_str());

    }
    else  {

        mInited = true;
    
        vbi_add_handler( vbiCallback, this );        
        mCurrentChannel  = 23;
        mVBIBuffer     = 0;
        mVBIBufferSize = 0;    
    
        int rc = MapVBIMem( (void**) &mVBIBuffer, &mVBIBufferSize );
    
        printf( "MapMem() == %d vbiBuf at %p with size %d\n", rc, (void*) mVBIBuffer, mVBIBufferSize );

#if 0
        Load_Country_Settings();
    
        Load_Country_Specific_Settings(0);
        
        if( getenv( "CARD") )
            CardType = (TVCARDID) atoi( getenv("CARD") );
        else
            CardType = (TVCARDID) 10;
        
        if( getenv( "TUNER") )
            TunerType = (TVTUNERID) atoi( getenv("TUNER") );
        else
            TunerType = (TVTUNERID) 4;

        Tuner_Init();
#endif
    }
}

void TeleTextInput::finit()
{
    if( TVHardware::finit( IODescription::ioIn, getDeviceID()) != true ) { 	
        printf( "TeleTextInput::finit failed to finitialize %s\n", getName().c_str());
    }
    
    stop();
    
    IOManager::instance().unregisterNode ( this );
}
