
#include "pvr350osd.h"
#include <errno.h>
#include <assert.h>
#include <sys/ioctl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "format.h"

extern "C" {
#include "videodev.h"
#include "videodev2.h"

#include "ivtv-ext-api.h"
}
#if VDRVERSNUM >= 10307
cPvr350Osd::cPvr350Osd(int Left, int Top,int fbfd, unsigned char *osdbuf)
    :cOsd(Left, Top) 
{
    fd = fbfd;
    osd = osdbuf; 
}

cPvr350Osd::~cPvr350Osd()
{  
    cBitmap *Bitmap;
    for ( int i = 0; ( Bitmap = GetBitmap(i)) != NULL; i++ ) {
        Hide(Bitmap);
    }
    struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
    memset(&prep, 0, sizeof(prep));
    
    prep.source = osd;
    prep.dest_offset = 0;
    prep.count = 720 * 576 * 4;
    
    ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);

#ifdef SET_VIDEO_WINDOW
    if ( vidWin.bpp != 0 ) {
	    ResetVideoSize();
    }
#endif
}

/* We can handle any number of windows */
eOsdError cPvr350Osd::CanHandleAreas(const tArea *Areas, int NumAreas)
{
    eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);

    return Result;
}


void cPvr350Osd::Flush(void)
{
    cBitmap *Bitmap;

    for ( int i = 0; ( Bitmap = GetBitmap(i)) != NULL; i++ ) {
        int  x1 = 0, y1 = 0, x2 = 0, y2 = 0;
        if ( Bitmap->Dirty(x1,y2,x2,y2) ) {
            for ( int yp = y1; yp <= y2; yp++ ) {
                for ( int xp = x1; xp <= x2; xp++  ) {
                    tColor c = Bitmap->Color(*Bitmap->Data(xp,yp));

                    osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) ] = ( c >> 0 ) & 0xFF;
                    osd[((yp + Top() + Bitmap->Y0()) * 720 * 4) + ((xp +  Bitmap->X0() + Left()) * 4) + 1] = ( c >> 8 ) & 0xFF;
                    osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) + 2] = ( c >> 16 ) & 0xFF;
                    osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) + 3] = ( c >> 24 ) & 0xFF;              
                }
            }
        }
    }
    struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
    memset(&prep, 0, sizeof(prep));

    prep.source = osd;
    prep.dest_offset = 0;
    prep.count = 720 * 576 * 4;
        
    ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);
#ifdef SET_VIDEO_WINDOW
    if (vidWin.bpp != 0 ) {
	    SetVideoSize(vidWin.x1,vidWin.y1,vidWin.x2 - vidWin.x1,vidWin.y2 - vidWin.y1);
    } else {
	    ResetVideoSize();
    }
#endif
}

void cPvr350Osd::Hide(cBitmap *Bitmap)
{
    for ( int yp = 0; yp < Bitmap->Height(); yp++ ) {
        for ( int xp = 0; xp < Bitmap->Width(); xp++ ) {
            tColor c = 0;

            osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) ] = ( c >> 24 ) & 0xFF;
            osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) + 1] = ( c >> 16 ) & 0xFF;
            osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) + 2] = ( c >> 8 ) & 0xFF;
            osd[((yp + Top() + Bitmap->Y0()) * 720 *4) + ((xp +  Bitmap->X0() + Left()) * 4) + 3] = ( c >> 0 ) & 0xFF;              
        }
    }
}


// --- cDvbOsdProvider -------------------------------------------------------

cPvr350OsdProvider::cPvr350OsdProvider(int fd, unsigned char *buf)
{
    osdBuf = buf;
    osdfd  = fd;
}

cOsd *cPvr350OsdProvider::CreateOsd(int Left, int Top)
{
  return new cPvr350Osd(Left, Top, osdfd, osdBuf);
}

#else

cPvr350Osd::cPvr350Osd(int fbfd, unsigned char *osdbuf, int X, int Y)
    :cOsdBase(X, Y) 
{
    memset(m_ShownWindows, 0, sizeof(m_ShownWindows));
    fd = fbfd;
    osd = osdbuf;  
}

cPvr350Osd::~cPvr350Osd()
{  
    memset(osd,0,720 * 576 * 4);
    for (int i = 0; i < NumWindows(); i++)
         CloseWindow(GetWindowNr(i));
}

bool cPvr350Osd::OpenWindow(cWindow *Window)
{
    m_ShownWindows[Window->Handle()] = true;
    if (Window->ClearWithBackground()) {
        for ( int yp = 0; yp < Window->Height(); yp++ ) {
            for ( int xp = 0; xp < Window->Width(); xp++ ) {
                eDvbColor c = clrBackground;

                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) ] = ( c >> 16 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 1] = ( c >> 8 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 2] = ( c >> 0 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 3] = ( c >> 24 ) & 0xFF;              
            }
        }
        struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
        memset(&prep, 0, sizeof(prep));

        prep.source = osd;
        prep.dest_offset = 0;
        prep.count = 720 * 576 * 4;
        
        ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);
    }

    return true;
}

void cPvr350Osd::CommitWindow(cWindow *Window)
{
    int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
     
    if ( Window == NULL ) 
           return;

    if (!m_ShownWindows[Window->Handle()])
        return;


    if (Window->Dirty(x1, y1, x2, y2)) {

        for ( int yp = y1; yp <= y2; yp++ ) {
            for ( int xp = x1; xp <= x2; xp++  ) {
                eDvbColor c = Window->GetColor(*Window->Data(xp,yp));

                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) ] = ( c >> 16 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 * 4) + ((xp +  Window->X0() + X0()) * 4) + 1] = ( c >> 8 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 2] = ( c >> 0 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 3] = ( c >> 24 ) & 0xFF;              

            }
        }
        struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
        memset(&prep, 0, sizeof(prep));

        prep.source = osd;
        prep.dest_offset = 0;
        prep.count = 720 * 576 * 4;
        
        ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);

    }
}

void cPvr350Osd::ShowWindow(cWindow *Window)
{
    for ( int yp = 0; yp < Window->Height(); yp++ ) {
        for ( int xp = 0; xp < Window->Width(); xp++ ) {
            eDvbColor c = Window->GetColor(*Window->Data(xp,yp));

            osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) ] = ( c >> 16 ) & 0xFF;
            osd[((yp + Y0() + Window->Y0()) * 720 * 4) + ((xp +  Window->X0() + X0()) * 4) + 1] = ( c >> 8 ) & 0xFF;
            osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 2] = ( c >> 0 ) & 0xFF;
            osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 3] = ( c >> 24 ) & 0xFF;              
        }
    }
    struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
    memset(&prep, 0, sizeof(prep));

    prep.source = osd;
    prep.dest_offset = 0;
    prep.count = 720 * 576 * 4;
        
    ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);
}

void cPvr350Osd::HideWindow(cWindow *Window, bool Hide)
{ 
    m_ShownWindows[Window->Handle()] = !Hide;

    if ( Hide ) {
        for ( int yp = 0; yp < Window->Height(); yp++ ) {
            for ( int xp = 0; xp < Window->Width(); xp++ ) {
                uint32_t c = 0;
            
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) ] = ( c >> 16 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 * 4) + ((xp +  Window->X0() + X0()) * 4) + 1] = ( c >> 8 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 2] = ( c >> 0 ) & 0xFF;
                osd[((yp + Y0() + Window->Y0()) * 720 *4) + ((xp +  Window->X0() + X0()) * 4) + 3] = ( c >> 24 ) & 0xFF;              
            }
        }
        struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
        memset(&prep, 0, sizeof(prep));
        
        prep.source = osd;
        prep.dest_offset = 0;
        prep.count = 720 * 576 * 4;
        
        ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);
    }   
}



void cPvr350Osd::CloseWindow(cWindow *Window)
{
    HideWindow(Window, true);
    m_ShownWindows[Window->Handle()] = false;
}

void cPvr350Osd::MoveWindow(cWindow *Window, int X, int Y)
{    
    CloseWindow(Window);
    m_ShownWindows[Window->Handle()] = true;
    for ( int yp = 0; yp < Window->Height(); yp++ ) {
        for ( int xp = 0; xp < Window->Width(); xp++ ) {
            eDvbColor c = Window->GetColor(*Window->Data(xp,yp));

            osd[((yp + Y0() + Y) * 720 *4) + ((xp +  X + X0()) * 4) ] = ( c >> 16 ) & 0xFF;
            osd[((yp + Y0() + Y) * 720 * 4) + ((xp +  X + X0()) * 4) + 1] = ( c >> 8 ) & 0xFF;
            osd[((yp + Y0() + Y) * 720 *4) + ((xp +  X + X0()) * 4) + 2] = ( c >> 0 ) & 0xFF;
            osd[((yp + Y0() + Y) * 720 *4) + ((xp +  X + X0()) * 4) + 3] = ( c >> 24 ) & 0xFF;              
        }
    }

    struct ivtvfb_ioctl_dma_host_to_ivtv_args prep;
    memset(&prep, 0, sizeof(prep));

    prep.source = osd;
    prep.dest_offset = 0;
    prep.count = 720 * 576 * 4;
        
    ioctl(fd, IVTVFB_IOCTL_PREP_FRAME, &prep);
}
#endif
