/*
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */


#include <QtGui>
#include <QList>
#include <QSize>

#include "UBKeyboardPalette.h"
#include "core/UBSettings.h"


#include "core/memcheck.h"

/*

            UBKeyboardPalette

*/
UBKeyboardPalette::UBKeyboardPalette(QWidget *parent)
        : UBFloatingPalette(Qt::TopRightCorner, parent)
{
    setCustomPosition(true);
    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    setFocusPolicy(Qt::NoFocus);
    capsLock = false;
    languagePopupActive = false;
    keyboardActive = false;
    btnWidth = btnHeight = 16;

    buttons = new UBKeyButton*[47];
    for (int i=0; i<47; i++)
    {
        buttons[i] = new UBKeyButton(this);
    }

    locales = UBPlatformUtils::getKeyboardLayouts(this->nLocalesCount);

    createCtrlButtons();

    nCurrentLocale = 0;
    setInput(locales[nCurrentLocale]);

    setContentsMargins(radius() + 15, 4, radius() + 15, 4);

    connect(this, SIGNAL(keyboardActivated(bool)), this, SLOT(onActivated(bool)));
}

QList<UBKeyboardPalette*> UBKeyboardPalette::instances;
UBKeyboardPalette* UBKeyboardPalette::create(QWidget *parent)
{
    if (!UBPlatformUtils::hasVirtualKeyboard())
        return NULL;

    UBKeyboardPalette* instance = new UBKeyboardPalette(parent);
    instances.append(instance);

    instance->setKeyButtonSize(UBSettings::settings()->boardKeyboardPaletteKeyBtnSize->get().toString());
    instance->setAutoMinimize(UBSettings::settings()->boardKeyboardPaletteAutoMinimize->get().toBool());
    instance->setVisible(false);
    connect(UBSettings::settings()->boardKeyboardPaletteAutoMinimize , SIGNAL(changed(QVariant)), instance, SLOT(keyboardPaletteAutoMinimizeChanged(QVariant)));
    connect(UBSettings::settings()->boardKeyboardPaletteKeyBtnSize, SIGNAL(changed(QVariant)), instance, SLOT(keyboardPaletteButtonSizeChanged(QVariant)));


    foreach(UBKeyboardPalette* inst, instances)
    {
        connect(inst, SIGNAL(moved(const QPoint&)), instance, SLOT(syncPosition(const QPoint&)));
        connect(instance, SIGNAL(moved(const QPoint&)), inst, SLOT(syncPosition(const QPoint&)));

        connect(inst, SIGNAL(localeChanged(int)), instance, SLOT(syncLocale(int)));
        connect(instance, SIGNAL(localeChanged(int)), inst, SLOT(syncLocale(int)));

    }

    return instance;
}

void UBKeyboardPalette::syncPosition(const QPoint & pos)
{
    move(pos);
}

void UBKeyboardPalette::syncLocale(int nLocale)
{
    nCurrentLocale = nLocale;
    setInput(locales[nCurrentLocale]);
}

void UBKeyboardPalette::keyboardPaletteAutoMinimizeChanged(QVariant b)
{
    setAutoMinimize(b.toBool());
}
void UBKeyboardPalette::keyboardPaletteButtonSizeChanged(QVariant size)
{
    setKeyButtonSize(size.toString());
}

void UBKeyboardPalette::setInput(const UBKeyboardLocale* locale)
{
    if (locale!=NULL)
    {
        for (int i=0; i<47; i++)
            buttons[i]->setKeyBt((*locale)[i]);
    }
    else
    {
        this->hide();
    }
}

UBKeyboardPalette::~UBKeyboardPalette()
{
    for (int i=0; i<47; i++)
        delete buttons[i];
    delete [] buttons;

    for (int i=0; i<8; i++)
        delete ctrlButtons[i];
    delete [] ctrlButtons;

    if (locales!=NULL)
    {
        for (int i=0; i<nLocalesCount; i++)
            delete locales[i];
        delete [] locales;
    }
}

QSize  UBKeyboardPalette::sizeHint () const
{
    if ((autoMinimize && keyboardActive) || !autoMinimize)
    {
        int w = contentsMargins().left() + contentsMargins().right() + 13 + 14.5 * btnWidth;
        int h = contentsMargins().top() + contentsMargins().bottom() + 5 * btnHeight + 4;
        return QSize(w, h);
    }
    else
    {
        int MIN_WITH = 4,
                       MIN_HEIGTH = 4;
        int w = contentsMargins().left() + contentsMargins().right() + 13 + 14.5 * MIN_WITH;
        int h = contentsMargins().top() + contentsMargins().bottom() + 5 * MIN_HEIGTH + 4;
        return QSize(w, h);
    }
}

const QString* UBKeyboardPalette::getLocaleName()
{
    if (locales==NULL)
        return NULL;
    return &(locales[nCurrentLocale]->name);
}

void UBKeyboardPalette::setLocale(int nLocale)
{
    if (locales!=NULL)
    {
        nCurrentLocale = nLocale;

        setInput(locales[nCurrentLocale]);
        onLocaleChanged(locales[nCurrentLocale]);
        update();
    }
    emit localeChanged(nLocale);
}

void UBKeyboardPalette::setKeyButtonSize(const QString& strSize)
{
    QStringList strs = strSize.split('x');

    if (strs.size()==2)
    {
        btnWidth = strs[0].toInt();
        btnHeight = strs[1].toInt();
        adjustSizeAndPosition();
    }

}

void UBKeyboardPalette::setAutoMinimize(bool autoMinimize)
{
    this->autoMinimize = autoMinimize;
    adjustSizeAndPosition();
}


void UBKeyboardPalette::enterEvent ( QEvent * )
{
    if (keyboardActive)
        return;

    keyboardActive = true;

    adjustSizeAndPosition();

    emit keyboardActivated(true);
}

void UBKeyboardPalette::leaveEvent ( QEvent * )
{
    if (languagePopupActive || !keyboardActive || mIsMoving)
        return;

    keyboardActive = false;

    adjustSizeAndPosition();

    emit keyboardActivated(false);
}

void  UBKeyboardPalette::moveEvent ( QMoveEvent * event )
{
    UBFloatingPalette::moveEvent(event);
    emit moved(event->pos());
}

void UBKeyboardPalette::adjustSizeAndPosition(bool pUp)
{
    QSize rSize = sizeHint();
    if (rSize != size())
    {
        int dx = (rSize.width() - size().width()) /2;
        int dy = rSize.height() - size().height();

        this->move(x()-dx, y() - dy);
        this->resize(rSize.width(), rSize.height());
    }
    UBFloatingPalette::adjustSizeAndPosition(pUp);
}

void  UBKeyboardPalette::paintEvent( QPaintEvent* event)
{
    UBFloatingPalette::paintEvent(event);

    QRect r = this->geometry();

    int lleft, ltop, lright, lbottom;
    getContentsMargins ( &lleft, &ltop, &lright, &lbottom ) ;

    int btw = (r.width() - lleft - lright - 13) / 14.5;
    int bth = (r.height() - ltop - lbottom -4) / 5;

    lleft = (r.width() - (btw * 14.5 + 13))/2;
    ltop = (r.height() - (bth * 5 + 4)) / 2;

    int off = lleft;;
    for (int i = 0; i<13; i++)
    {
        QRect cr(off, ltop, btw, bth);
        buttons[i]->setGeometry(cr);
        off += btw + 1;
    }
    ctrlButtons[0]->setGeometry(off, ltop, btw * 1.5, bth);
    off += btw * 1.5;
    lright = off;

    ltop += bth + 1;
    int lwidth = 12 * btw + 12 + btw * 1.3;
    off = (r.width() - lwidth) / 2;
    ctrlButtons[1]->setGeometry(off, ltop, btw * 1.3, bth);
    off += btw * 1.3 + 1;
    for (int i=0; i<12; i++)
    {
        QRect cr(off, ltop, btw, bth);
        buttons[13 + i]->setGeometry(cr);
        off += btw + 1;
    }

    ltop += bth + 1;
    lwidth = 12 * btw + 12 + btw * 2;
    off = (r.width() - lwidth) / 2;
    for (int i=0; i<12; i++)
    {
        QRect cr(off, ltop, btw, bth);
        buttons[13 + 12 + i]->setGeometry(cr);
        off += btw + 1;
    }
    ctrlButtons[2]->setGeometry(off, ltop, btw * 2, bth);

    ltop += bth + 1;
    lwidth = 12 * btw + 11;
    off = (r.width() - lwidth) / 2;
    ctrlButtons[3]->setGeometry(off, ltop, btw, bth);
    off+=btw+1;
    for (int i=0; i<10; i++)
    {
        QRect cr(off, ltop, btw, bth);
        buttons[13 + 12 + 12 + i]->setGeometry(cr);
        off += btw + 1;
    }
    ctrlButtons[4]->setGeometry(r.x() + off, ltop, btw, bth);

    ltop += bth + 1;
    lwidth = 11 * btw + 2;
    off = (r.width() - lwidth) / 2;
    ctrlButtons[5]->setGeometry(off, ltop, btw, bth);
    ctrlButtons[6]->setGeometry(off + btw + 1, ltop, btw*9, bth);
    ctrlButtons[7]->setGeometry(off + btw*10 + 2, ltop, btw, bth);
}


/*

            UBKeyboardButton
*/

UBKeyboardButton::UBKeyboardButton(UBKeyboardPalette* parent)
        :QWidget(parent),
        keyboard(parent),
        bFocused(false),
        bPressed(false)
{
    setCursor(Qt::PointingHandCursor);
}

UBKeyboardButton::~UBKeyboardButton()
{}

void UBKeyboardButton::paintEvent(QPaintEvent*)
{
    QPainter painter(this);

    if (bPressed)
        painter.setBrush(QBrush(QColor(0, 0xcc, 0)));
    else if (bFocused)
        painter.setBrush(QBrush(QColor(0xcc, 0, 0)));

    painter.drawRoundedRect(0, 0, width()-1, height()-1, 3, 3);

    this->paintContent(painter);
}

void  UBKeyboardButton::enterEvent ( QEvent*)
{
    bFocused = true;
    update();
}

void  UBKeyboardButton::leaveEvent ( QEvent*)
{
    bFocused = false;
    update();
}

void  UBKeyboardButton::mousePressEvent ( QMouseEvent * event)
{
    event->accept();
    bPressed = true;
    update();
    this->onPress();
}

void  UBKeyboardButton::mouseReleaseEvent ( QMouseEvent * )
{
    bPressed = false;
    update();
    this->onRelease();
}

UBKeyButton::UBKeyButton(UBKeyboardPalette* parent)
        :UBKeyboardButton(parent),
        keybt(0)
{}

UBKeyButton::~UBKeyButton()
{}

void UBKeyButton::onPress()
{
    if (keybt!=NULL)
        sendUnicodeSymbol(keybt->code1, keybt->code2, capsLock());
}

void UBKeyButton::onRelease()
{}

void UBKeyButton::paintContent(QPainter& painter)
{

    if (keybt)
    {
        QString text(QChar(capsLock() ? keybt->symbol2 : keybt->symbol1));
        QRect textRect(rect().x()+2, rect().y()+2, rect().width()-4, rect().height()-4);
        painter.drawText(textRect, Qt::AlignCenter, text);
    }
}


UBCntrlButton::UBCntrlButton(UBKeyboardPalette* parent, const QString& _label, int _code )
        :UBKeyboardButton(parent),
        label(_label),
        code(_code)
{}

UBCntrlButton::~UBCntrlButton()
{}

void UBCntrlButton::onPress()
{
    sendControlSymbol(code);
}

void UBCntrlButton::onRelease()
{}

void UBCntrlButton::paintContent(QPainter& painter)
{
    painter.drawText(rect(), Qt::AlignCenter, label);
}

UBCapsLockButton::UBCapsLockButton(UBKeyboardPalette* parent)
        :UBKeyboardButton(parent)
{}

UBCapsLockButton::~UBCapsLockButton()
{}

void UBCapsLockButton::onPress()
{
    keyboard->capsLock = !keyboard->capsLock;
    keyboard->update();
}

void UBCapsLockButton::onRelease()
{}

void UBCapsLockButton::paintContent(QPainter& painter)
{
    painter.drawText(rect(), Qt::AlignCenter, "^");
}


UBLocaleButton::UBLocaleButton(UBKeyboardPalette* parent)
        :UBKeyboardButton(parent)
{
    localeMenu = new QMenu(this);

    for (int i=0; i<parent->nLocalesCount; i++)
    {
        QAction* action = (parent->locales[i]->icon!=NULL) ?
                          localeMenu->addAction(*parent->locales[i]->icon, parent->locales[i]->fullName)
                          : localeMenu->addAction(parent->locales[i]->fullName);
        action->setData(QVariant(i));
    }
}

UBLocaleButton::~UBLocaleButton()
{
    delete localeMenu;
}

void UBLocaleButton::onPress()
{
}

void UBLocaleButton::onRelease()
{
    keyboard->languagePopupActive = true;
    QAction* action = localeMenu->exec(mapToGlobal(QPoint(0,0)));
    keyboard->languagePopupActive = false;
    if (action!=NULL)
    {
        int nLocale = action->data().toInt();
        keyboard->setLocale(nLocale);
    }
}

void UBLocaleButton::paintContent(QPainter& painter)
{
    const QString* localeName = keyboard->getLocaleName();
    if (localeName!=NULL)
        painter.drawText(rect(), Qt::AlignCenter, *localeName);
}
