/*
    Bt8xx QuickTime driver component
    Copyright (C) 2002 Andreas Thiede ( a.thiede@berlin.de )
    
    Based on : 
    
    macam - webcam app and QuickTime driver component
    Copyright (C) 2002 Matthias Krauss (macam@matthias-krauss.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 "QTPanel.h"
#include "Resolvers.h"
#include <ApplicationServices/ApplicationServices.h>
#include <QuickTime/QuickTimeComponents.k.h>
#include "QTVideoDigitizer.h"
#include "MiscTools.h"
#include <syslog.h>
#import <lib/bt848.h>
#import <lib/settings.h>
#import <lib/tvcards.h>
#import <lib/Tuner.h>
#import <util/str.h>
#import <lib/Preferences.h>

//#define NO_REAL_HW 1

extern FILE * log_file;

extern void log_open();

extern SETTING * BT848_GetSettingByName( const char * name );

extern const TVCARDSETUP  TVCards[];
extern const TVTUNERSETUP Tuners[];
extern const TTVFORMAT    TVFormats[];

enum {
    uppSGPanelGetDitlProcInfo = 0x000003F0,
    uppSGPanelGetTitleProcInfo = 0x000003F0,
    uppSGPanelCanRunProcInfo = 0x000003F0,
    uppSGPanelInstallProcInfo = 0x00002FF0,
    uppSGPanelEventProcInfo = 0x000FEFF0,
    uppSGPanelItemProcInfo = 0x0000AFF0,
    uppSGPanelRemoveProcInfo = 0x00002FF0,
    uppSGPanelSetGrabberProcInfo = 0x000003F0,
    uppSGPanelSetResFileProcInfo = 0x000002F0,
    uppSGPanelGetSettingsProcInfo = 0x00003FF0,
    uppSGPanelSetSettingsProcInfo = 0x00003FF0,
    uppSGPanelValidateInputProcInfo = 0x000003F0,
    uppSGPanelSetEventFilterProcInfo = 0x00000FF0
};

pascal ComponentResult sgpnMainEntry (ComponentParameters *params, Handle storage) 
{	
    ComponentResult err = 0;
    ProcPtr procPtr = 0;
    ProcInfoType procInfo;

    char selectorName[200];

    log_open();

    vdig_lock();
    
    if(ResolveVDSelector(params->what, selectorName)) {
        fprintf( log_file,  "sgpn: call to %s\n",selectorName);
        
    } else {
        fprintf( log_file,  "sgpn: call unknown selector %d\n",params->what);
    }
    fflush( log_file );

    if (sgpnLookupSelector(params->what,&procPtr,&procInfo)) {
	err=CallComponentFunctionWithStorageProcInfo((Handle)storage, params, procPtr,procInfo);
    } else {
        err=badComponentSelector;
    }

    fprintf( log_file,  "sgpn: call resulted in %d\n",(int)err);
    fflush( log_file );

    vdig_unlock();
    
    return err;
}

bool sgpnLookupSelector(short what,ProcPtr* ptr,ProcInfoType* info)
{
    bool ok=true;

    if (what < 0) {
        switch(what) {
            case kComponentRegisterSelect:  *info=uppCallComponentRegisterProcInfo;
                                            *ptr=(ComponentRoutineUPP)sgpnRegister; break;
            case kComponentOpenSelect:      *info=uppCallComponentOpenProcInfo;
                                            *ptr=(ComponentRoutineUPP)sgpnOpen; break;
            case kComponentCloseSelect:     *info=uppCallComponentCloseProcInfo;
                                            *ptr=(ComponentRoutineUPP)sgpnClose; break;
            case kComponentCanDoSelect:     *info=uppCallComponentCanDoProcInfo;
                                            *ptr=(ComponentRoutineUPP)sgpnCanDo; break;
            case kComponentVersionSelect:   *info=uppCallComponentVersionProcInfo;
                                            *ptr=(ComponentRoutineUPP)sgpnVersion; break;
            default: ok=false; break;
        }
    } else {
        switch (what) {
            case kSGPanelSetGrabberSelect:	*info=uppSGPanelSetGrabberProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnSetGrabber; break;
            case kSGPanelCanRunSelect:     	*info=uppSGPanelCanRunProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnCanRun; break;
            case kSGPanelSetResFileSelect:   	*info=uppSGPanelSetResFileProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnSetResFile; break;
            case kSGPanelGetDitlSelect:    	*info=uppSGPanelGetDitlProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnGetDITL; break;
            case kSGPanelInstallSelect:    	*info=uppSGPanelInstallProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnInstall; break;
            case kSGPanelRemoveSelect:    	*info=uppSGPanelRemoveProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnRemove; break;
            case kSGPanelItemSelect:       	*info=uppSGPanelItemProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnItem; break;
            case kSGPanelEventSelect:      	*info=uppSGPanelEventProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnEvent; break;
            case kSGPanelValidateInputSelect:	*info=uppSGPanelValidateInputProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnValidateInput; break;
            case kSGPanelSetSettingsSelect: 	*info=uppSGPanelSetSettingsProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnSetSettings; break;
            case kSGPanelGetSettingsSelect: 	*info=uppSGPanelGetSettingsProcInfo;
                                                *ptr=(ComponentRoutineUPP)sgpnGetSettings; break;
            default: ok=false; break;
        }
        
    }
    return ok;
}

pascal ComponentResult sgpnRegister(sgpnGlobals storage) 
{
    ComponentDescription cd;
    Handle name;
    Handle desc;
    short num,i;
    unsigned long cid;
    Component comp;

    char cname[256];
    Str255 pname;

    cd.componentType='vdig';
    cd.componentSubType='B8XX';
    cd.componentManufacturer='mk  ';
    cd.componentFlags=0;
    cd.componentFlagsMask=0;

    {
        const char * text = "\pVideo input from a Booktree BT848/BT878(A)";
    
        PtrToHand ((Ptr) text, &desc, strlen(text));

        CStr2PStr(cname,pname);

        comp=RegisterComponent(&cd,&vdigMainEntry, registerComponentAfterExisting,desc,desc,NULL);

        //if (comp) SetComponentRefcon(comp,(long)bridge);
    }
    
    DisposeHandle(desc);

    return 0;
}

pascal ComponentResult sgpnOpen(sgpnGlobals storage, ComponentInstance self) 
{
    OSErr err;
   
    storage = (sgpnGlobals)NewHandleClear(sizeof(SGPGlobals));

    if (err = MemError()) return err;

    (**storage).self = self;
    
    SetComponentInstanceStorage(self, (Handle)storage);
    
    return 0;
}

pascal ComponentResult sgpnClose(sgpnGlobals storage, ComponentInstance self)
{
    if (storage) {
        DisposeHandle((Handle)storage);
    }
    return 0;
}

pascal ComponentResult sgpnCanDo(sgpnGlobals storage, short ftnNumber)
{
    ProcPtr procPtr;
    ProcInfoType procInfo;
        
    if (sgpnLookupSelector(ftnNumber,&procPtr,&procInfo)) return 1;
    else return 0;
}

pascal ComponentResult sgpnVersion(sgpnGlobals storage) 
{
    return 0x00010001;
}

//pascal ComponentResult sgpnGetSettings( SeqGrabComponent s, SGChannel c, UserData * ud, long flags );


//Sequence Grabber Panel Component general fuctions

pascal ComponentResult sgpnSetGrabber(sgpnGlobals storage, SeqGrabComponent grabber) 
{
    ComponentResult err=0;

    return err;
}

pascal ComponentResult sgpnCanRun(sgpnGlobals storage, SGChannel channel) 
{
    ComponentResult err=0;

    VideoDigitizerComponent vdig;

    ComponentDescription cd;

    vdig=SGGetVideoDigitizerComponent(channel);

    if (!vdig) return qtParamErr;

    err=GetComponentInfo((Component)vdig,&cd,NULL,NULL,NULL);

    if (err) return err;

    if (cd.componentSubType!='B8XX') return badComponentType;		//Not our video digitizer
    if (cd.componentManufacturer!='mk  ') return badComponentType;	//Not our video digitizer

    return 0;
}


pascal ComponentResult sgpnSetResFile(sgpnGlobals storage, short resRef) 
{
    (**storage).resRef=resRef;
    return 0;
}


pascal ComponentResult sgpnGetDITL(sgpnGlobals storage, Handle* ditl) {
    UseResFile((**storage).resRef);
    if (ditl==NULL) return qtParamErr;
    *ditl=Get1Resource('DITL',258);
    if (*ditl==NULL) return mFulErr;
    return 0;
}

static void SelectMenuItem( MenuRef menu, const char * item )
{
    Str255 pStr;
    
    CToPStr( item, pStr );

    SetMenuTitle( menu, pStr ); 
}

static void SelectItem( ControlRef ctrl, int item )
{
    MenuRef menu = GetControlPopupMenuRef( ctrl);

    item++;

    if( item >= 1 && item <= CountMenuItems( menu ) ) {
        
        SetControlValue( ctrl, item );
    }
}

static void AddItem( MenuRef menu, const char * item )
{
    MenuItemDataRec   data;
    
    Str255 pStr;

    CToPStr( item, pStr );
        
    InsertMenuItem( menu, pStr, CountMenuItems( menu ) );     
}

static void UpdateCardMenu( DialogRef dlg, short itemOffset)
{
    ControlRef cardCtrl;
    MenuRef    cardMenu;
    int        nItems, i;
    
    GetDialogItemAsControl(dlg,itemOffset+2,&cardCtrl);

    cardMenu=GetControlPopupMenuRef( cardCtrl);

    nItems=CountMenuItems( cardMenu );

    if( nItems ) {
    
        DeleteMenuItems( cardMenu, 1, nItems );
    }
    
    for( i = 0; i < TVCARD_LASTONE; i++ ) {
        
        AddItem( cardMenu, TVCards[i].szName );

    }
    
    SelectItem( cardCtrl, PreferedCard() );
}

static void UpdateTunerMenu( DialogRef dlg, short itemOffset)
{
    ControlRef tunerCtrl;
    MenuRef    tunerMenu;
    int        nItems, i;
    
    GetDialogItemAsControl(dlg,itemOffset+3,&tunerCtrl);

    tunerMenu=GetControlPopupMenuRef( tunerCtrl);

    nItems=CountMenuItems( tunerMenu );

    if( nItems ) {
    
        DeleteMenuItems( tunerMenu, 1, nItems );
    }
    
    for( i = 0; i < TUNER_LASTONE; i++ ) {
        
        AddItem( tunerMenu, Tuners[i].szName );
    }
    
    SelectItem( tunerCtrl, PreferedTuner() );
}

static void UpdateFormatMenu( DialogRef dlg, short itemOffset)
{
    ControlRef formatCtrl;
    MenuRef    formatMenu;
    int        nItems, i;
    
    GetDialogItemAsControl(dlg,itemOffset+4,&formatCtrl);

    formatMenu=GetControlPopupMenuRef( formatCtrl);

    nItems=CountMenuItems( formatMenu );

    if( nItems ) {
    
        DeleteMenuItems( formatMenu, 1, nItems );
    }
    
    for( i = 0; i < FORMAT_LASTONE; i++ ) {
        
        AddItem( formatMenu, TVFormats[i].szDesc );        
    }
    
    SelectItem( formatCtrl, PreferedTVType() );
}

static void UpdateAudioSourceMenu( DialogRef dlg, short itemOffset)
{
    ControlRef audioCtrl;
    MenuRef    audioMenu;
    int        nItems, i;
    
    GetDialogItemAsControl(dlg,itemOffset+5,&audioCtrl);

    audioMenu=GetControlPopupMenuRef( audioCtrl);

    nItems=CountMenuItems( audioMenu );

    if( nItems ) {
    
        DeleteMenuItems( audioMenu, 1, nItems );
    }
    
    AddItem( audioMenu, "Tuner" );
    AddItem( audioMenu, "Radio" );
    AddItem( audioMenu, "External" );
    AddItem( audioMenu, "Internal" );
    AddItem( audioMenu, "Mute" );
    AddItem( audioMenu, "Stereo" );

    SelectItem( audioCtrl, PreferedAudioSource() );

}

static void UpdateVideoSourceMenu( DialogRef dlg, short itemOffset)
{
    ControlRef videoCtrl;
    MenuRef    videoMenu;
    int        nItems, i;
    
    GetDialogItemAsControl(dlg,itemOffset+6,&videoCtrl);

    videoMenu=GetControlPopupMenuRef( videoCtrl);

    nItems=CountMenuItems( videoMenu );

    if( nItems ) {
    
        DeleteMenuItems( videoMenu, 1, nItems );
    }
    
    AddItem( videoMenu, "Tuner" );
    AddItem( videoMenu, "Composite" );
    AddItem( videoMenu, "SVideo" );
    AddItem( videoMenu, "Other 1" );
    AddItem( videoMenu, "Other 2" );
    AddItem( videoMenu, "Composite via SVideo " );

    SelectItem( videoCtrl, PreferedVideoSource() );
}

static void UpdateCountryMenu( DialogRef dlg, short itemOffset)
{
    ControlRef countryCtrl;
    MenuRef    countryMenu;
    int        nItems, i;
    int        maxCountries = sizeof(Countries) / sizeof( TCountries);

    GetDialogItemAsControl(dlg,itemOffset+7,&countryCtrl);

    countryMenu=GetControlPopupMenuRef( countryCtrl);

    nItems=CountMenuItems( countryMenu );

    if( nItems ) {
    
        DeleteMenuItems( countryMenu, 1, nItems );
    }
    
    for( i = 0; i < maxCountries; i++ ) {

        if( Countries[i].Name[0] != 0 ) {

            AddItem( countryMenu, Countries[i].Name );                    
        }
    }

    SelectItem( countryCtrl, PreferedCountry() );
}

static void UpdateChannelMenu( DialogRef dlg, short itemOffset)
{
    ControlRef channelCtrl;
    MenuRef    channelMenu;

    GetDialogItemAsControl(dlg,itemOffset+8,&channelCtrl);

    channelMenu=GetControlPopupMenuRef( channelCtrl);

    SelectItem( channelCtrl, PreferedChannel() );
}

pascal ComponentResult sgpnInstall(sgpnGlobals storage, SGChannel channel, DialogRef dlg, short itemOffset) 
{

    UpdateCardMenu( dlg, itemOffset);
    UpdateTunerMenu( dlg, itemOffset);
    UpdateFormatMenu( dlg, itemOffset);
    UpdateVideoSourceMenu( dlg, itemOffset);
    UpdateAudioSourceMenu( dlg, itemOffset);
    UpdateCountryMenu( dlg, itemOffset);
    UpdateChannelMenu( dlg, itemOffset);

    return noErr;
}

pascal ComponentResult sgpnRemove(sgpnGlobals storage, SGChannel channel, DialogRef dlg, short itemOffset) 
{
    ComponentResult err=0;
    return err;
}

//Sequence Grabber Panel Component event handling functions

pascal ComponentResult sgpnItem(sgpnGlobals storage, SGChannel channel, DialogRef dlg, short itemOffset, short itemNum) 
{
    ComponentResult err=0;

    ControlRef     ctrl;
    int            val;

    GetDialogItemAsControl(dlg,itemNum,&ctrl);

    val =  GetControlValue(ctrl) - 1;
    
    fprintf( log_file,  "sgpnItem(%d) offset(%d) value(%d)\n", itemNum, itemOffset, val );

    switch (itemNum-itemOffset) {
    case 2: // card

        SetPreferedCard( val );
        
        break;

    case 3: // tuner

        SetPreferedTuner( val );
        
        break;

    case 4: // tvformat

        SetPreferedTVType( val );
        
        break;

    case 5: // audio source

        SetPreferedAudioSource( val );
        
        break;

    case 6: // video source

        SetPreferedVideoSource( val );
        
        break;

    case 7: // country

        SetPreferedCountry( val );
        
        break;

    case 8: // country

        SetPreferedChannel( val );
        
        break;
#if 0
        case 10:						//save defaults button
            [bridge saveAsDefaults];
            break;
#endif
        default:
            break;
    }

    return err;
}


pascal ComponentResult sgpnEvent(sgpnGlobals storage, SGChannel channel, DialogRef dlg, short itemOffset, const EventRecord* evt,
                                 short* itemHit, Boolean* handled) 
{
    if (handled) *handled=false;	//We don't have special event handling
    return 0;
}


pascal ComponentResult sgpnValidateInput(sgpnGlobals storage, Boolean* ok) 
{
    if (ok) *ok=true;
    return 0;
}

//Sequence Grabber Panel Component settings fuctions

pascal ComponentResult sgpnGetSettings(sgpnGlobals storage, UserData* ud, long flags) 
{
    ComponentResult err=0;

    return err;
}

pascal ComponentResult sgpnSetSettings(sgpnGlobals storage, SGChannel c, UserData ud, long flags) 
{
    ComponentResult err=0;

    return err;
}
