#include "screengrab.h"
#include "dialogs.h"
#include "ifapp.h"
#include "imageutils.h"
#include "attributedialog.h"

#include <qcheckbox.h>
#include <qlayout.h>
#include <qlabel.h>
#include <qtimer.h>
#include <qpushbutton.h>
#include <qfileinfo.h>

#include <kbuttonbox.h>
#include <klocale.h>
#include <kimageio.h>
#include <kfiledialog.h>
#include <knotifyclient.h>
#include <knuminput.h>
#include <kdebug.h>
#include <krecentdocument.h>
#include <kmessagebox.h>

#include <X11/X.h>
#include <X11/Xlib.h>
#include <unistd.h>

QPixmap getWindow(Window window, bool nobdrs)
{
    XWindowAttributes win_info;
    int absx, absy, x, y;
    int width, height;
    int dwidth, dheight;
    int bw;
    Window dummywin;
    Display *dpy = QApplication::desktop()->x11Display();
    QPixmap pix;
    XImage *image;

    qWarning("Getting target window information");
    if(!XGetWindowAttributes(dpy, window, &win_info)){
        qWarning("Can't get target window attributes.");
        return(pix);
    }
    if(!XTranslateCoordinates (dpy, window, RootWindow(dpy, DefaultScreen(dpy)), 0, 0,
                               &absx, &absy, &dummywin)){
        qWarning("Unable to translate window coordinates (%d,%d)", absx, absy);
        return(pix);
    }
    win_info.x = absx;
    win_info.y = absy;
    width = win_info.width;
    height = win_info.height;
    bw = 0;
    if(!nobdrs){
        absx -= win_info.border_width;
        absy -= win_info.border_width;
        bw = win_info.border_width;
        width += (2 * bw);
        height += (2 * bw);
    }
    dwidth = QApplication::desktop()->width();
    dheight = QApplication::desktop()->height();
    /* clip to window */
    if (absx < 0)
        width += absx, absx = 0;
    if (absy < 0)
        height += absy, absy = 0;
    if (absx + width > dwidth)
        width = dwidth - absx;
    if (absy + height > dheight)
        height = dheight - absy;

    x = absx - win_info.x;
    y = absy - win_info.y;

    image = XGetImage(dpy, window, x, y, width, height, AllPlanes, ZPixmap);
    if(!image){
        qWarning("Unable to get image at %dx%d+%d+%d", width, height, x, y);
        return(pix);
    }
    GC gc = qt_xget_temp_gc(qt_xscreen(), false);
    pix.resize(width, height);
    XPutImage(dpy, pix.handle(), gc, image, 0, 0, 0, 0, width, height);
    XFree(image);
    return(pix);
}


KIFScreenGrab::KIFScreenGrab(QWidget *parent, const char *name)
    : QSemiModal(parent, name, false)
{
    QVBoxLayout *layout = new QVBoxLayout(this, 4);
    QLabel *lbl = new QLabel(i18n("This dialog will grab either your desktop or\n\
a single application window. If you grab a\n\
single window your mouse cursor will change\n\
into crosshairs and simply select the window\n\
with your mouse."), this);
    layout->addWidget(lbl);
    desktopCB = new QCheckBox(i18n("Grab the entire desktop."), this);
    desktopCB->setChecked(true);
    layout->addWidget(desktopCB);
    hideCB = new QCheckBox(i18n("Hide all pixie windows."), this);
    hideCB->setChecked(true);
    layout->addWidget(hideCB);
    lbl = new QLabel(i18n("Delay (in secs):"), this);
    layout->addWidget(lbl);
    delay = new KIntNumInput(this);
    delay->setRange(0, 60);
    layout->addWidget(delay);
    layout->addStretch(1);
    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(slotCancel()));
    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(slotCheckIfDelay()));
    layout->addWidget(bbox);
    setCaption(i18n("Screenshot"));
    inSelect = false;

    show();

    inLoop = true;
    while(inLoop)
        kapp->processEvents();
    delete this;
};

void KIFScreenGrab::slotCheckIfDelay()
{
    // do hiding first
    move(-4000, -4000);
    if(hideCB->isChecked()){
        if(desktopCB->isChecked()){
            //hide();
            kifapp()->hideWindows();
            kifapp()->processEvents();
            QApplication::syncX();
        }
        else{
            //hide();
            kifapp()->hideWindows();
            kifapp()->processEvents();
            QApplication::syncX();
        }
    }
    if(delay->value()){
        QTimer::singleShot(delay->value()*1000, this,
                           SLOT(slotStartGrab()));
        kifapp()->processEvents();
    }
    else
        slotStartGrab();
}

void KIFScreenGrab::slotStartGrab()
{
    QPixmap pixmap;

    if(desktopCB->isChecked()){
        QApplication::syncX();
        sleep(1);
        pixmap = QPixmap::grabWindow(QApplication::desktop()->winId());
    }
    else{
        Display *disp = QApplication::desktop()->x11Display();
        Window rootWin, childWin;
        int rootX, rootY, winX, winY;
        unsigned int mask;

        winSelected = false;
        inSelect = true;
        grabMouse(crossCursor);

        QApplication::syncX();

        while(!winSelected)
            kifapp()->processEvents();
        releaseMouse();
        inSelect = false;
        XQueryPointer(disp, DefaultRootWindow(disp), &rootWin, &childWin,
                      &rootX, &rootY, &winX, &winY, &mask);

        QApplication::flushX();
        if(!childWin){
            kdDebug() << "Pixie: no child window selected, using root" << endl;
            pixmap = QPixmap::grabWindow(QApplication::desktop()->winId());
        }
        else{
            pixmap = getWindow(childWin, false);
        }

    }
    KNotifyClient::beep();

    if(hideCB->isChecked()){
        kifapp()->showWindows();
        QApplication::syncX();
    }
    if(pixmap.isNull()){
        KMessageBox::sorry(NULL, i18n("Unable to take snapshot!"),
                           i18n("Screenshot Error"));
        inLoop = false;
        return;
    }
    QImage image = pixmap.convertToImage();

    KFileDialog dlg(QDir::currentDirPath(), QString::null,
                    NULL, "screenshotfiledialog", true);
    dlg.setOperationMode(KFileDialog::Saving);
    dlg.setCaption(i18n("Save Screenshot as"));

    KIFScreenGrabPreview *preview = new KIFScreenGrabPreview(&image);
    dlg.setPreviewWidget(preview);
                                   
    int result = dlg.exec();

    QString filename = dlg.selectedFile();
    if(result == QDialog::Rejected || filename.isEmpty()){
        inLoop = false;
        return;
    }

    const char *format = formatForFilename(filename);
    QString formatStr;
    bool saved = false;
    while(!format){
        QString extStr = QFileInfo(filename).extension(false);
        FormatDialog formatDlg(!extStr.isEmpty() ? extStr : filename);
        if(formatDlg.exec() != QDialog::Rejected){
            formatStr = formatDlg.format();
            format = formatStr.latin1();
        }
        else{
            inLoop = false;
            return;
        }
    }
    while(!saved){
        int quality;
        QString commentStr;
        if(formatUsesComment(format)){
            KIFAttributeDialog attrDlg(true, this);
            if(attrDlg.exec() != QDialog::Rejected){
                quality = attrDlg.quality();
                commentStr = attrDlg.comment();
                saved = saveImage(image, filename, format, quality,
                                  commentStr);
            }
            else{
                inLoop = false;
                return;
            }
        }
        else
            saved = saveImage(image, filename, format);

        if(!saved){
            if(KMessageBox::warningContinueCancel(NULL,
                                                  i18n("Cannot save screenshot."),
                                                  i18n("Pixie Screenshot Error!"),
                                                  i18n("Continue"),
                                                  QString::null, true) ==
               KMessageBox::Cancel){
                qWarning("Screenshot save canceled");
                inLoop = false;
                return;
            }
        }
    }
    KRecentDocument::add(filename);
    inLoop = false;
}

void KIFScreenGrab::slotCancel()
{
    inLoop = false;
}

void KIFScreenGrab::mousePressEvent(QMouseEvent *ev)
{
    kdDebug() << "In mousePressEvent" << endl;
    if(inSelect)
        winSelected = true;
    else
        QSemiModal::mousePressEvent(ev);
}

KIFScreenGrabPreview::KIFScreenGrabPreview(const QImage *image,
                                           QWidget *parent,
                                           const char *name)
    : KPreviewWidgetBase(parent, name)
{
    setMinimumSize(200, 200);
    setMaximumWidth(200);
    img = image;
    pix = new QPixmap;
    if(image->width() > 200 || image->height() > 200){
        QImage scaledImg;
        if(image->width() > image->height()){
            float percent = (((float)200)/image->width());
            int h = (int)(image->height()*percent);
            scaledImg = image->smoothScale(200, h);
        }
        else{
            float percent = (((float)200)/image->height());
            int w = (int)(image->width()*percent);
            scaledImg = image->smoothScale(w, 200);
        }
        pix->convertFromImage(scaledImg);
    }
    else
        pix->convertFromImage(*image);
}

void KIFScreenGrabPreview::paintEvent(QPaintEvent *)
{
    bitBlt(this, 0, 0, pix, 0, 0, pix->width(), pix->height());
}

// do nothing on next two calls - always show the screenshot
void KIFScreenGrabPreview::showPreview(const KURL &)
{
    ;
}

void KIFScreenGrabPreview::clearPreview()
{
    ;
}





