//
// This File contains the definition of the MGImage-class
//
//   Author: Thomas Bretz
//   Version: V1.0 (1-8-2000)
//
// x11/src/GX11Gui.cxx
//
#include "MGImage.h"

#include <iostream.h>
#include <pthread.h>

ClassImp(MGImage);

MGImage::MGImage(const TGWindow* p, UInt_t w, UInt_t h, UInt_t options, ULong_t back)
    : TGFrame(p, w, h, options, back), fWidth(w), fHeight(h)
{
    // p = pointer to MainFrame (not owner)
    // w = width of frame
    // h = width of frame

    //
    // Set Color Table (Gray scale)
    //
    const int cols = 0x100+4*4*4;

    for (int c=0; c<0x100; c++)
        sprintf(fColors[c], "%02x", c);

    //
    // create space for the pixmap buffer, initialize pointer to data area
    //
    fBuffer = new char*[1+cols+fHeight+1];
    fBody   = &fBuffer[1+cols];

    //
    // fill buffer with header informations
    //
    fBuffer[0] = new char[14];
    sprintf(fBuffer[0], "%3d %3d %3d %1d", fWidth, fHeight, cols, 2);

    for (int k=0; k<0x100; k++)
    {
        const int l = k+1;
        fBuffer[l] = new char[13];
        fBuffer[l][0]  = fColors[k][0];
        fBuffer[l][1]  = fColors[k][1];
        fBuffer[l][2]  = '\t';
        fBuffer[l][3]  = 'c';
        fBuffer[l][4]  = ' ';
        fBuffer[l][5]  = '#';
        fBuffer[l][6]  = fColors[k][0];
        fBuffer[l][7]  = fColors[k][1];
        fBuffer[l][8]  = fColors[k][0];
        fBuffer[l][9]  = fColors[k][1];
        fBuffer[l][10] = fColors[k][0];
        fBuffer[l][11] = fColors[k][1];
        fBuffer[l][12] = '\0';
    }

    for (int b=0; b<4; b++)
        for (int g=0; g<4; g++)
            for (int r=0; r<4; r++)
            {
                const int nr = r+(g<<2)+(b<<4);
                const int l = 0x100+nr+1;

                fBuffer[l] = new char[13];
                fBuffer[l][0]  = 'f'+nr/8+1;
                fBuffer[l][1]  = 'f'+nr%8+1;
                fBuffer[l][2]  = '\t';
                fBuffer[l][3]  = 'c';
                fBuffer[l][4]  = ' ';
                fBuffer[l][5]  = '#';
                fBuffer[l][6]  = fColors[r*85][0];
                fBuffer[l][7]  = fColors[r*85][1];
                fBuffer[l][8]  = fColors[g*85][0];
                fBuffer[l][9]  = fColors[g*85][1];
                fBuffer[l][10] = fColors[b*85][0];
                fBuffer[l][11] = fColors[b*85][1];
                fBuffer[l][12] = '\0';
            }

    //
    // mark end of lines of the data area
    //
    for (UInt_t y=0; y<fHeight; y++)
    {
        fBody[y] = new char[fWidth*2+1];
        fBody[y][fWidth*2] = '\0';
    }
    //
    // mark end of buffer
    //
    fBuffer[1+cols+fHeight] = '\0';

    //
    // get frame id
    //
    fId = GetId();

    //
    // Create Default Graphic Context (XCreateGC)
    //
    fDefGC = gVirtualX->CreateGC(fId, 0); // GetBckgndGC(); //

    //
    // Creat drawing semaphore
    //
    fMuxPixmap = new pthread_mutex_t;
    pthread_mutex_init((pthread_mutex_t*)fMuxPixmap, NULL);

    //
    // create empty (black) pixmap
    //   return (Pixmap_t) XCreatePixmap(fDisplay, (Drawable) id, w, h,
    //          DefaultDepth(fDisplay, DefaultScreen(fDisplay)));
    //
    fPixmap = kNone; //@@@gVirtualX->CreatePixmap(fId, fWidth, fHeight);

    Resize(w, h);
}

void MGImage::Resize(UInt_t w, UInt_t h)
{
    TGFrame::Resize(w+2*GetBorderWidth(), h+2*GetBorderWidth());
    // FIXME: RESIZE THE PIXMAP
}

void MGImage::Resize(TGDimension size)
{
    TGFrame::Resize(size.fWidth+2*GetBorderWidth(), size.fHeight+2*GetBorderWidth());
    // FIXME: RESIZE THE PIXMAP
}

void MGImage::MoveResize(Int_t x, Int_t y, UInt_t w, UInt_t h)
{
   TGFrame::MoveResize(x, y, w+2*GetBorderWidth(), h+2*GetBorderWidth());
   // FIXME: RESIZE THE PIXMAP
}

MGImage::~MGImage()
{
    pthread_mutex_lock((pthread_mutex_t*)fMuxPixmap);

    cout << "Deleting fBuffer..." << endl;

    char **b = fBuffer;
    while (*b)
        delete[] *b++;
    delete[] fBuffer;

    cout << "Deleting Pixmap..." << endl;

    if (fPixmap!=kNone) // @@@
        gVirtualX->DeletePixmap(fPixmap);  // XFreePixmap(fDisplay, (Pixmap) pmap);

    cout << "Deleting GC..." << endl;

    gVirtualX->DeleteGC(fDefGC);       // XFreeGC(fDisplay, (GC) gc);

    pthread_mutex_destroy((pthread_mutex_t*)fMuxPixmap);

    cout << "MGImage destroyed." << endl;
}

/*
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Intrinsic.h>
XImage *fPix=NULL;
*/

void MGImage::DoRedraw()
{
    // Pixmap_t pm = gVirtualX->CreatePixmap(this->GetId(), buffer,
    //                                       768, 576, 0, 0xff, 8);
    TGFrame::DrawBorder();
    pthread_mutex_lock((pthread_mutex_t*)fMuxPixmap);

    // Copy a drawable (i.e. pixmap) to another drawable (pixmap, window).
    // The graphics context gc will be used and the source will be copied
    // from src_x,src_y,src_x+width,src_y+height to dest_x,dest_y.
    // XCopyArea(fDisplay, src, dest, (GC) gc, src_x, src_y, width, height,
    //           dest_x, dest_y);
    if (fPixmap!=kNone) //@@@
    gVirtualX->CopyArea(fPixmap, fId, fDefGC,
                        0, 0, fWidth, fHeight,
                        GetBorderWidth(), GetBorderWidth());
/*
     if (fPix)
    {
        cout << "put" << flush;
        XPutImage((Display*)gVirtualX->GetDisplay(), fId,
                  fDefGC, fPix,
                  0, 0, GetBorderWidth(), GetBorderWidth(),
                  fWidth, fHeight);

    cout << "done " << endl;
    }
*/
    pthread_mutex_unlock((pthread_mutex_t*)fMuxPixmap);
}


//#include <TGClient.h>
void MGImage::DrawImg(const byte *buffer)
{
    if (pthread_mutex_trylock((pthread_mutex_t*)fMuxPixmap))
        return;

    for (UInt_t y=0; y<fHeight; y++)
    {
        for (UInt_t x=0; x<fWidth; x++)
        {
            const byte col = buffer[y*fWidth+x];

            fBody[y][x*2]   = fColors[col][0];
            fBody[y][x*2+1] = fColors[col][1];
        }
    }

/*
    cout << "CreateImage" << flush;
    if (!fPix)
    {
        Display *dsp = (Display*)gVirtualX->GetDisplay();
        Screen  *scr = DefaultScreenOfDisplay(dsp);
        Visual  *vis = DefaultVisualOfScreen(scr);

        cout << vis->visualid << endl;
        cout << vis->c_class << endl;
        cout << vis->bits_per_rgb << endl;
        cout << vis->map_entries << endl;
        Visual visual;
        visual.c_class = StaticGray;

        int n;
        XPixmapFormatValues *fmt = XListPixmapFormats(dsp, &n);

        cout << "N: " << n << endl;
        for (int i=0; i<n; i++)
        {
            cout << fmt[i].dww.epth << " " << fmt[i].bits_per_pixel << " "
                << fmt[i].scanline_pad << endl;
        }

        Colormap colormap = XCreateColormap(dsp, fId, vis, AllocNone);

        for (int i=0; i<vis->map_entries; i++)
        {
            XColor color;
            char data[4];

            color.flags = DoRed | DoGreen | DoBlue;
            color.pixel = i;
            color.red   = (256*i/vis->map_entries) << 8;
            color.green = (256*i/vis->map_entries) << 8;
            color.blue  = (256*i/vis->map_entries) << 8;

            XAllocColor(dsp, colormap, &color);

            cout << color.pixel <<" " << flush;
        }
        fPix = XCreateImage(dsp, vis, 8, ZPixmap, 0,
                            buffer, 768, 576, 32, 0);

        cout << "Colors" << visual.visualid << flush;

    }
    cout << "Done " << (void*)fPix << endl;
    */
    Pixmap_t mask = kNone;
    PictureAttributes_t attr;
    attr.fMask = kNone;
    if (fPixmap!=kNone) // @@@
    gVirtualX->DeletePixmap(fPixmap); // XFreePixmap(fDisplay, (Pixmap) pmap);

    // Create a pixture pixmap from data. The picture attributes
    // are used for input and output. Returns kTRUE in case of success,
    // kFALSE otherwise. If mask does not exist it is set to kNone.
    //
    // XpmAttributes xpmattr;
    //
    // MapPictureAttributes(attr, xpmattr);
    //
    // Int_t res = XpmCreatePixmapFromData(fDisplay, id, data, (Pixmap*)&pict,
    //                                     (Pixmap*)&pict_mask, &xpmattr);
    //
    // MapPictureAttributes(attr, xpmattr, kFALSE);
    // XpmFreeAttributes(&xpmattr);
    //
    // if (res == XpmSuccess || res == XpmColorError)
    //   return kTRUE;
    //
    // if (pict) {
    //    XFreePixmap(fDisplay, (Pixmap)pict);
    //    pict = kNone;
    // }
    // if (pict_mask) {
    //    XFreePixmap(fDisplay, (Pixmap)pict_mask);
    //    pict_mask = kNone;
    // }
    // return kFALSE;
    fPixmap=kNone;
    if (!gVirtualX->CreatePictureFromData(fId, fBuffer, fPixmap,
                                          mask, attr))
    {
        cout << "Warning: Error in CreatePictureFromData" << endl;
        fPixmap=kNone;
    }

    pthread_mutex_unlock((pthread_mutex_t*)fMuxPixmap);
    DoRedraw();
}

void MGImage::DrawColImg(const byte *gbuf, const byte *cbuf)
{
    if (pthread_mutex_trylock((pthread_mutex_t*)fMuxPixmap))
        return;

    for (UInt_t y=0; y<fHeight; y++)
    {
        for (UInt_t x=0; x<fWidth; x++)
        {
            const byte ccol = cbuf[y*fWidth+x];

            if (ccol)
            {
                fBody[y][x*2]   = 'f'+ccol/8+1;
                fBody[y][x*2+1] = 'f'+ccol%8+1;
            }
            else
            {
                const byte gcol = gbuf[y*fWidth+x];
                fBody[y][x*2]   = fColors[gcol][0];
                fBody[y][x*2+1] = fColors[gcol][1];
            }
        }
    }

    Pixmap_t mask = kNone;
    PictureAttributes_t attr;
    attr.fMask = kNone;

    if (fPixmap!=kNone)
        gVirtualX->DeletePixmap(fPixmap);
    fPixmap=kNone;

    if (!gVirtualX->CreatePictureFromData(fId, fBuffer, fPixmap,
                                          mask, attr))
    {
        cout << "Warning: Error in CreatePictureFromData" << endl;
        fPixmap=kNone;
    }

    pthread_mutex_unlock((pthread_mutex_t*)fMuxPixmap);
    DoRedraw();
}

