#include "border.h"
#include "imageutils.h"
#include "browser.h"
#include <qlabel.h>
#include <qlayout.h>
#include <qgroupbox.h>
#include <qradiobutton.h>
#include <klocale.h>
#include <kbuttonbox.h>
#include <kglobal.h>
#include <kconfig.h>

KIFBorderDialog::KIFBorderDialog(QWidget *parent, const char *name)
    : QDialog(parent, name, true)
{
    setCaption(i18n("Border Selection"));
    QVBoxLayout *layout = new QVBoxLayout(this, 5);

    QGroupBox *previewBox = new QGroupBox(1, Qt::Horizontal,
                                          i18n("Preview"), this);
    preview = new QLabel(previewBox);

    layout->addWidget(previewBox);

    btnGrp = new QButtonGroup(4, Qt::Vertical, i18n("Border Style"), this);

    (void)new QRadioButton(i18n("Solid"), btnGrp);
    (void)new QRadioButton(i18n("Beveled"), btnGrp);
    (void)new QRadioButton(i18n("Liquid"), btnGrp);
    (void)new QRadioButton(i18n("Round Corners"), btnGrp);
    (void)btnGrp->setButton(Solid);
    connect(btnGrp, SIGNAL(clicked(int)), this, SLOT(slotBorderType(int)));

    layout->addWidget(btnGrp);

    KConfig *config = KGlobal::config();
    QString oldGrp = config->group();
    config->setGroup("Borders");

    QGroupBox *colorBox = new QGroupBox(4, Qt::Horizontal,
                                        i18n("Colors"), this);
    fgLbl = new QLabel(i18n("Foreground"), colorBox);
    fgBtn = new KColorButton(colorBox);
    fgBtn->setColor(config->readColorEntry("Fg", &Qt::lightGray));
    connect(fgBtn, SIGNAL(changed(const QColor &)), this,
            SLOT(slotBorderFg(const QColor &)));
    bgLbl = new QLabel(i18n("Background"), colorBox);
    bgBtn = new KColorButton(colorBox);
    bgBtn->setColor(config->readColorEntry("Bg", &Qt::darkGray));
    connect(bgBtn, SIGNAL(changed(const QColor &)), this,
            SLOT(slotBorderBg(const QColor &)));

    layout->addWidget(colorBox);
    config->setGroup(oldGrp);

    widthInput = new KIntNumInput(1, this);
    widthInput->setRange(1, 24);
    widthInput->setLabel(i18n("Border Width"), AlignVCenter);
    connect(widthInput, SIGNAL(valueChanged(int)), this,
            SLOT(slotBorderWidth(int)));

    layout->addWidget(widthInput);

    layout->addStretch(1);

    KButtonBox *bbox = new KButtonBox(this);
    bbox->addStretch(1);

    connect(bbox->addButton(i18n("OK")), SIGNAL(clicked()), this,
            SLOT(accept()));
    connect(bbox->addButton(i18n("Cancel")), SIGNAL(clicked()), this,
            SLOT(reject()));
    layout->addWidget(bbox);

    slotBorderType(Solid);
}

void KIFBorderDialog::slotBorderType(int type)
{
    if(type == Solid){
        fgBtn->setEnabled(true);
        bgBtn->setEnabled(false);
        fgLbl->setEnabled(true);
        bgLbl->setEnabled(false);
        widthInput->setEnabled(true);
    }
    else if(type == RoundCorner){
        fgBtn->setEnabled(false);
        bgBtn->setEnabled(true);
        fgLbl->setEnabled(false);
        bgLbl->setEnabled(true);
        widthInput->setEnabled(false);
    }
    else{
        fgBtn->setEnabled(true);
        bgBtn->setEnabled(true);
        fgLbl->setEnabled(true);
        bgLbl->setEnabled(true);
        widthInput->setEnabled(true);
    }

    if(type == Bevel){
        fgLbl->setText(i18n("Upper left"));
        bgLbl->setText(i18n("Lower right"));
    }
    else{
        fgLbl->setText(i18n("Foreground"));
        bgLbl->setText(i18n("Background"));
    }

    if(type == Liquid)
        widthInput->setRange(7, 24);
    else
        widthInput->setRange(1, 24);

    updatePreview();
}

void KIFBorderDialog::updatePreview()
{
    QImage src;
    QImage dest;
    BorderType type = (BorderType)btnGrp->id(btnGrp->selected());
    if(type != RoundCorner)
        src.create(64-widthInput->value()*2, 64-widthInput->value()*2, 32);
    else
        src.create(64, 64, 32);
    src.fill(Qt::white.rgb());

    if(type == Solid){
        KIFBorderEffect::solid(src, dest, fgBtn->color(), widthInput->value());
    }
    else if(type == Bevel){
        KIFBorderEffect::bevel(src, dest, fgBtn->color(), bgBtn->color(),
                               widthInput->value());
    }
    else if(type == Liquid){
        KIFBorderEffect::liquid(src, dest, fgBtn->color(), bgBtn->color(),
                                widthInput->value());
    }
    else if(type == RoundCorner){
        KIFBorderEffect::roundCorner(src, dest, bgBtn->color());
    }
    QPixmap pix;
    pix.convertFromImage(dest);
    preview->setPixmap(pix);
}


void KIFBorderDialog::slotBorderWidth(int)
{
    updatePreview();
}

void KIFBorderDialog::slotBorderFg(const QColor &)
{
    updatePreview();
    KConfig *config = KGlobal::config();
    QString oldGrp = config->group();
    config->setGroup("Borders");
    config->writeEntry("Fg", fgBtn->color());
    config->setGroup(oldGrp);
}

void KIFBorderDialog::slotBorderBg(const QColor &)
{
    updatePreview();
    KConfig *config = KGlobal::config();
    QString oldGrp = config->group();
    config->setGroup("Borders");
    config->writeEntry("Bg", fgBtn->color());
    config->setGroup(oldGrp);
}

bool KIFBorderEffect::solid(QImage &src, QImage &dest,
                            const QColor &fg, int borderWidth)
{
    dest.reset();
    dest.create(src.width()+borderWidth*2, src.height()+borderWidth*2, 32);
    unsigned int *output;
    int x, y;
    // top
    for(y=0; y < borderWidth; ++y){
        output = (unsigned int *)dest.scanLine(y);
        for(x=0; x < dest.width(); ++x){
            output[x] = fg.rgb();
        }
    }
    // left and right
    for(; y < dest.height()-borderWidth; ++y){
        output = (unsigned int *)dest.scanLine(y);
        for(x=0; x < borderWidth; ++x)
            output[x] = fg.rgb();
        for(x = dest.width()-1; x > dest.width()-borderWidth-1; --x)
            output[x] = fg.rgb();
    }
    // bottom
    for(; y < dest.height(); ++y){
        output = (unsigned int *)dest.scanLine(y);
        for(x=0; x < dest.width(); ++x){
            output[x] = fg.rgb();
        }
    }
    copyQImage(src, dest, borderWidth, borderWidth);
    return(true);
}

bool KIFBorderEffect::liquid(QImage &src, QImage &dest, const QColor &fg,
                             const QColor &bg, int borderWidth)
{
    dest.reset();
    dest.create(src.width()+borderWidth*2, src.height()+borderWidth*2, 32);
    unsigned int *output;
    int x, y;
    QColor darkColor = fg.dark(130);
    QColor lightColor1 = fg.light(110);
    QColor lightColor2 = fg.light(115);

    dest.fill(fg.rgb());

    // top line
    y=0;
    output = (unsigned int *)dest.scanLine(y);
    for(x=2; x < dest.width()-2; ++x){
        output[x] = darkColor.rgb();
    }
    ++y;
    // second line
    output = (unsigned int *)dest.scanLine(y);
    output[1] = darkColor.rgb();
    output[dest.width()-2] = darkColor.rgb();
    ++y;
    // sides
    for(; y < dest.height()-2; ++y){
        output = (unsigned int *)dest.scanLine(y);
        output[0] = darkColor.rgb();
        output[dest.width()-1] = darkColor.rgb();
    }
    // second to last line
    output = (unsigned int *)dest.scanLine(y);
    output[1] = darkColor.rgb();
    output[dest.width()-2] = darkColor.rgb();
    ++y;
    // last line
    output = (unsigned int *)dest.scanLine(y);
    for(x=2; x < dest.width()-2; ++x){
        output[x] = darkColor.rgb();
    }

    // top fill
    y = 1;
    output = (unsigned int *)dest.scanLine(y);
    for(x=2; x < dest.width()-2; ++x)
        output[x] = lightColor1.rgb();
    ++y;
    output = (unsigned int *)dest.scanLine(y);
    for(x=1; x < dest.width()-1; ++x)
        output[x] = lightColor1.rgb();
    // bottom fill
    y = dest.height()-3;
    output = (unsigned int *)dest.scanLine(y);
    for(x=1; x < dest.width()-1; ++x)
        output[x] = lightColor2.rgb();
    ++y;
    output = (unsigned int *)dest.scanLine(y);
    for(x=2; x < dest.width()-2; ++x)
        output[x] = lightColor2.rgb();

    // fuzzy corners
    int red, green, blue;
    QColor blendColor(darkColor);
    red = (blendColor.red() >> 1) + (bg.red() >> 1);
    green = (blendColor.green() >> 1) + (bg.green() >> 1);
    blue = (blendColor.blue() >> 1) + (bg.blue() >> 1);
    blendColor.setRgb(red, green, blue);
    // top line
    y = 0;
    output = (unsigned int *)dest.scanLine(y);
    output[1] = blendColor.rgb();
    output[dest.width()-2] = blendColor.rgb();
    output[0] = bg.rgb();
    output[dest.width()-1] = bg.rgb();
    ++y;
    // second line
    output = (unsigned int *)dest.scanLine(y);
    output[0] = blendColor.rgb();
    output[dest.width()-1] = blendColor.rgb();
    // second to last line
    y = dest.height()-2;
    output = (unsigned int *)dest.scanLine(y);
    output[0] = blendColor.rgb();
    output[dest.width()-1] = blendColor.rgb();
    ++y;
    // last line
    output = (unsigned int *)dest.scanLine(y);
    output[1] = blendColor.rgb();
    output[dest.width()-2] = blendColor.rgb();
    output[0] = bg.rgb();
    output[dest.width()-1] = bg.rgb();

    // do an inner rect?

    // place image
    copyQImage(src, dest, borderWidth, borderWidth);
    return(true);
}

bool KIFBorderEffect::bevel(QImage &src, QImage &dest,
                            const QColor &topColor, const QColor &btmColor,
                            int borderWidth)
{
    dest.reset();
    dest.create(src.width()+borderWidth*2, src.height()+borderWidth*2, 32);
    unsigned int *output;
    int x, y;
    int wc;
    // top
    for(y=0, wc = dest.width()-1; y < borderWidth; ++y, --wc){
        output = (unsigned int *)dest.scanLine(y);
        for(x=0; x < wc; ++x){
            output[x] = topColor.rgb();
        }
        for(;x < dest.width(); ++x){
            output[x] = btmColor.rgb();
        }
    }
    // left and right
    for(; y < dest.height()-borderWidth; ++y){
        output = (unsigned int *)dest.scanLine(y);
        for(x=0; x < borderWidth; ++x)
            output[x] = topColor.rgb();
        for(x = dest.width()-1; x > dest.width()-borderWidth-1; --x)
            output[x] = btmColor.rgb();
    }
    // bottom
    for(wc = borderWidth; y < dest.height(); ++y, --wc){
        output = (unsigned int *)dest.scanLine(y);
        for(x=0; x < wc; ++x){
            output[x] = topColor.rgb();
        }
        for(; x < dest.width(); ++x){
            output[x] = btmColor.rgb();
        }
    }
    copyQImage(src, dest, borderWidth, borderWidth);
    return(true);
}

bool KIFBorderEffect::roundCorner(QImage &src, QImage &dest,
                                  const QColor &bg)
{
    int total, current;
    unsigned int *data;
    QColor c;
    int h, s, v;
    int r, g, b;
    int bgH, bgS, bgV;
    int alpha;

    dest.reset();
    // round corners adds 1 pixel on top and left, 8 on bottom and right
    //dest.create(src.width()+9, src.height()+9, 32);
    dest.create(src.width(), src.height(), 32);
    dest.fill(bg.rgb());

    // first do the shadowing
    QImage img(PixieBrowser::uicImage("roundcorner-shadow.png"));
    img.detach();
    if(img.depth() < 32)
        img = img.convertDepth(32);
    // convert shadow alpha layer to background color
    data = (unsigned int *)img.bits();
    total = img.width()*img.height();
    bg.hsv(&bgH, &bgS, &bgV);
    for(current=0; current<total; ++current){
        alpha = qAlpha(data[current]);
        c.setRgb(data[current]);
        if(alpha == 0){
            c = bg;
            alpha = 255;
        }
        else if(alpha != 255){
            float srcPercent = ((float)alpha)/255.0;
            float destPercent = 1.0-srcPercent;
            r = (int)((srcPercent*c.red()) + (destPercent*bg.red()));
            g = (int)((srcPercent*c.green()) + (destPercent*bg.green()));
            b = (int)((srcPercent*c.blue()) + (destPercent*bg.blue()));
            c.setRgb(r, g, b);
            alpha = 255;
        }
        else{
            c.hsv(&h, &s, &v);
            c.setHsv(bgH, bgS, v);
        }
        data[current] = qRgba(c.red(), c.green(), c.blue(), alpha);
    }
    // tile shadow to destination

    // top left corner
    tileQImage(dest, 0, 0, 14, 14, img, 0, 0, 14, 14);
    // top right corner
    tileQImage(dest, dest.width()-13, 0, 14, 14,
               img, img.width()-13, 0, 14, 14);
    // bottom left corner
    tileQImage(dest, 0, dest.height()-13, 14, 14,
               img, 0, img.height()-13, 14, 14);
    // bottom right corner
    tileQImage(dest, dest.width()-13, dest.height()-13, 14, 14,
               img, img.width()-13, img.height()-13, 14, 14);
    // top tile
    tileQImage(dest, 13, 0, dest.width()-25, 14,
               img, 14, 0, 4, 14);
    // bottom tile
    tileQImage(dest, 13, dest.height()-13, dest.width()-25, 14,
               img, 14, img.height()-13, 4, 14);
    // left tile
    tileQImage(dest, 0, 13, 14, dest.height()-25,
               img, 0, 14, 14, 4);
    // right tile
    tileQImage(dest, dest.width()-13, 13, 14, dest.height()-25,
               img, img.width()-13, 14, 14, 4);

    // done with shadow, calculate image mask and alpha layer
    img = PixieBrowser::uicImage("roundcorner-picfill.png");
    img.detach();

    QImage blendedSrc = src;
    blendedSrc.detach();

    // top left corner
    copyQImageSecondaryAlpha(blendedSrc, 0, 0, 14, 14, img, 0, 0, 14, 14);
    // top right corner
    copyQImageSecondaryAlpha(blendedSrc, blendedSrc.width()-13, 0, 14, 14,
               img, img.width()-13, 0, 14, 14);
    // bottom left corner
    copyQImageSecondaryAlpha(blendedSrc, 0, blendedSrc.height()-13, 14, 14,
               img, 0, img.height()-13, 14, 14);
    // bottom right corner
    copyQImageSecondaryAlpha(blendedSrc, blendedSrc.width()-13, blendedSrc.height()-13, 14, 14,
               img, img.width()-13, img.height()-13, 14, 14);
    // top tile
    copyQImageSecondaryAlpha(blendedSrc, 13, 0, blendedSrc.width()-25, 14,
               img, 14, 0, 2, 14);
    // bottom tile
    copyQImageSecondaryAlpha(blendedSrc, 13, blendedSrc.height()-13, blendedSrc.width()-25, 14,
               img, 14, img.height()-13, 2, 14);
    // left tile
    copyQImageSecondaryAlpha(blendedSrc, 0, 13, 14, blendedSrc.height()-25,
               img, 0, 14, 14, 2);
    // right tile
    copyQImageSecondaryAlpha(blendedSrc, blendedSrc.width()-13, 13, 14, blendedSrc.height()-25,
               img, img.width()-13, 14, 14, 2);


    // now copy the pic with alpha
    copyQImageWithAlpha(blendedSrc, dest, 0, 0);
    return(true);
}


#include "border.moc"
