#include "IpEntriesPanel.h"

#include <QVariant>
#include <QTextCodec>
#include <QVBoxLayout>
#include <QToolBar>
#include <QTableView>
#include <QHeaderView>
#include <QAction>
#include <QIcon>
#include <QEvent>


#include "../SizeHintWidget.h"
#include "LtrIpEntriesModel.h"
#include "AddIpEntryDialog.h"

#if 0
#include <QStyledItemDelegate>
#include <QBrush>
#include <QPainter>
#include <QPen>

class BackgroundDelegate : public QStyledItemDelegate
{
public:
    explicit BackgroundDelegate(QObject *parent = 0)
        : QStyledItemDelegate(parent)
    {
    }
    void paint(QPainter *painter, const QStyleOptionViewItem &option,
               const QModelIndex &index) const
    {
        // Fill the background before calling the base class paint
        // otherwise selected cells would have a white background
        QVariant background = index.data(Qt::BackgroundRole);
        if (background.canConvert<QBrush>())
            painter->fillRect(option.rect, background.value<QBrush>());

        QStyledItemDelegate::paint(painter, option, index);

        // To draw a border on selected cells
        if(option.state & QStyle::State_Selected)
        {
            painter->save();
            QPen pen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
            int w = pen.width()/2;
            painter->setPen(pen);
            painter->drawRect(option.rect.adjusted(w,w,-w,-w));
            painter->restore();
        }
    }
};
#endif

IpEntriesPanel::IpEntriesPanel(QWidget *parent) :
    QDockWidget(parent), mainWgt(parent), m_con(0), m_model(0) {
    this->setObjectName("ipEntriesPanel");    

    QVBoxLayout *lout = new QVBoxLayout();
    QToolBar  *bar = new QToolBar();
    m_ipTable = new QTableView();    


    lout->addWidget(m_ipTable);
    lout->addWidget(bar);
    SizeHintWidget *wgt = new SizeHintWidget(QSize(450, 150));
    wgt->setLayout(lout);
    this->setWidget(wgt);
    wgt->setMinimumWidth(150);

    m_ipTable->verticalHeader()->setDefaultSectionSize(18);
    m_ipTable->verticalHeader()->setVisible(false);
    m_ipTable->horizontalHeader()->setStretchLastSection(true);
    m_ipTable->setSelectionBehavior(QAbstractItemView::SelectRows);

    m_actAdd = new QAction(QIcon(":/icons/add.png"), "", this);
    m_actRemove = new QAction(QIcon(":/icons/remove.png"), "", this);
    m_actConnect = new QAction(QIcon(":/icons/connect.png"), "", this);
    m_actDisconnect = new QAction(QIcon(":/icons/disconnect.png"), "", this);
    m_actConnectAuto = new QAction(QIcon(":/icons/connect_auto.png"), "", this);
    m_actDisconnectAll = new QAction(QIcon(":/icons/disconnect_all.png"), "", this);


    checkActEnable();

    connect(m_actAdd, SIGNAL(triggered()), SLOT(addIpEntry()));
    connect(m_actRemove, SIGNAL(triggered()), SLOT(remIpEntry()));
    connect(m_actConnect, SIGNAL(triggered()), SLOT(ipConnect()));
    connect(m_actDisconnect, SIGNAL(triggered()), SLOT(ipDisconnect()));
    connect(m_actConnectAuto, SIGNAL(triggered()), SLOT(ipConnoctAuto()));
    connect(m_actDisconnectAll, SIGNAL(triggered()), SLOT(ipDisconnectAll()));

    bar->addAction(m_actAdd);
    bar->addAction(m_actRemove);
    bar->addAction(m_actConnect);
    bar->addAction(m_actDisconnect);
    bar->addAction(m_actConnectAuto);
    bar->addAction(m_actDisconnectAll);


    m_ipTable->addAction(m_actAdd);
    m_ipTable->addAction(m_actRemove);
    m_ipTable->addAction(m_actConnect);
    m_ipTable->addAction(m_actDisconnect);
    m_ipTable->addAction(m_actConnectAuto);
    m_ipTable->addAction(m_actDisconnectAll);
    m_ipTable->setContextMenuPolicy(Qt::ActionsContextMenu);
    m_ipTable->setSelectionMode(QAbstractItemView::SingleSelection);

#if 0
    m_ipTable->setItemDelegate(new BackgroundDelegate(this));
    m_ipTable->setStyleSheet("selection-background-color: transparent;");
#endif

    connect(m_ipTable, SIGNAL(doubleClicked(QModelIndex)), SLOT(ipDoubleClicked(QModelIndex)));

    retranslateUi();
}

void IpEntriesPanel::retranslateUi() {
    setWindowTitle(tr("Crate IP entries"));

    m_actAdd->setText(tr("Add IP address"));
    m_actAdd->setStatusTip(tr("Add new IP-entry"));
    m_actRemove->setText(tr("Remove IP address"));
    m_actRemove->setStatusTip(tr("Remove selected IP-entry"));
    m_actConnect->setText(tr("Connect to crate"));
    m_actConnect->setStatusTip(tr("Setup crate connection with address from IP-entry"));
    m_actDisconnect->setText(tr("Disconnect"));
    m_actDisconnect->setStatusTip(tr("Close crate connection with address form IP-entry"));
    m_actConnectAuto->setText(tr("Autoconnect with crates"));
    m_actConnectAuto->setStatusTip(tr("Connect to all crates with address from IP-entries marked 'auto'"));
    m_actDisconnectAll->setText(tr("Disconnect all crates"));
    m_actDisconnectAll->setStatusTip(tr("Close all opened TCP/IP crate connections"));
}

void IpEntriesPanel::setConnection(LtrdConnection *con) {
    LtrIpEntriesModel* old_model = m_model;
    if (m_con) {

        disconnect(this, SIGNAL(reqAddIp(qint32,qint32,bool)), m_con, SLOT(ipEntryAdd(qint32,qint32,bool)));
        disconnect(this, SIGNAL(reqRemIp(qint32,bool)), m_con, SLOT(ipEntryRem(qint32,bool)));
        disconnect(this, SIGNAL(reqConnect(qint32)), m_con, SLOT(ipConnect(qint32)));
        disconnect(this, SIGNAL(reqDisconnect(qint32)), m_con, SLOT(ipDisconnect(qint32)));
        disconnect(this, SIGNAL(reqConnectAuto()), m_con, SLOT(ipConnectAuto()));
        disconnect(this, SIGNAL(reqDisconnectAll()), m_con, SLOT(ipDisconnectAll()));
        disconnect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this,
                   SLOT(ipEntryDataChanged(QModelIndex)));
        disconnect(m_model, SIGNAL(rowsInserted(const QModelIndex &,int,int)), this, SLOT(checkActEnable()));
        disconnect(m_model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), this,
                SLOT(checkActEnable()));
    }

    m_con = con;
    if (con) {
        m_model = new LtrIpEntriesModel(con);
        m_model->initView(m_ipTable);



      //  m_ipTable->setColumnWidth(1, 100);
     //   m_ipTable->setColumnWidth(2, 100);


        connect(m_ipTable->selectionModel(),SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),
                SLOT(selectionChanged(QModelIndex, QModelIndex)));
        connect(m_model, SIGNAL(rowsInserted(const QModelIndex &,int,int)), SLOT(checkActEnable()));
        connect(m_model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)),
                SLOT(checkActEnable()));

        connect(this, SIGNAL(reqAddIp(qint32,qint32,bool)), con, SLOT(ipEntryAdd(qint32,qint32,bool)));
        connect(this, SIGNAL(reqRemIp(qint32,bool)), con, SLOT(ipEntryRem(qint32,bool)));
        connect(this, SIGNAL(reqConnect(qint32)), con, SLOT(ipConnect(qint32)));
        connect(this, SIGNAL(reqDisconnect(qint32)), con, SLOT(ipDisconnect(qint32)));
        connect(this, SIGNAL(reqConnectAuto()), con, SLOT(ipConnectAuto()));
        connect(this, SIGNAL(reqDisconnectAll()), con, SLOT(ipDisconnectAll()));
        connect(m_model, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
                SLOT(ipEntryDataChanged(QModelIndex)));
        connect(con, SIGNAL(statusChanged(LtrdConnection::connStatus)),
                SLOT(srvStatusChanged(LtrdConnection::connStatus)));
    } else {
        m_model = 0;
        m_ipTable->setModel(m_model);
    }

    checkActEnable();

    if (old_model) {
        delete old_model;
    }

}

void IpEntriesPanel::closeEvent(QCloseEvent *event) {
    this->hide();
}

void IpEntriesPanel::changeEvent(QEvent *event) {
    switch (event->type()) {
        case QEvent::LanguageChange:
            retranslateUi();
            break;
    }

    QDockWidget::changeEvent(event);
}



void IpEntriesPanel::addIpEntry() {
    AddIpEntryDialog dialog(mainWgt);
    if (dialog.exec()==QDialog::Accepted) {
        quint32 flags = 0;
        if (dialog.autocon())
            flags |= LTR_CRATE_IP_FLAG_AUTOCONNECT;
        if (dialog.reconnect())
            flags |= LTR_CRATE_IP_FLAG_RECONNECT;
        emit reqAddIp(dialog.addr().toIPv4Address(), flags, dialog.permanent());
        if (dialog.needConnect())
            emit reqConnect(dialog.addr().toIPv4Address());
    }
}

void IpEntriesPanel::remIpEntry() {
    if (m_ipTable->currentIndex().isValid()) {
        TLTR_CRATE_IP_ENTRY ip = m_model->ipEntry(m_ipTable->currentIndex().row());
        emit reqRemIp(ip.ip_addr, true);
    }
}

void IpEntriesPanel::ipConnect() {
    if (m_ipTable->currentIndex().isValid()) {
        TLTR_CRATE_IP_ENTRY ip = m_model->ipEntry(m_ipTable->currentIndex().row());
        emit reqConnect(ip.ip_addr);
    }
}

void IpEntriesPanel::ipDisconnect(void) {
    if (m_ipTable->currentIndex().isValid()) {
        TLTR_CRATE_IP_ENTRY ip = m_model->ipEntry(m_ipTable->currentIndex().row());
        emit reqDisconnect(ip.ip_addr);
    }
}

void IpEntriesPanel::ipConnoctAuto() {
    emit reqConnectAuto();
}

void IpEntriesPanel::ipDisconnectAll() {
    emit reqDisconnectAll();
}

void IpEntriesPanel::selectionChanged(QModelIndex current, QModelIndex old) {
    checkActEnable();
}

void IpEntriesPanel::selectionClear() {
    checkActEnable();
}

void IpEntriesPanel::ipEntryDataChanged(QModelIndex ind) {
    checkActEnable();
}

void IpEntriesPanel::ipDoubleClicked(QModelIndex ind) {
    /* первые два столбца для флагов игнорируем, чтобы не превести к непреднамеренному
       двойному нажатию при смене флагов */
    if (ind.column() >= 2) {
        TLTR_CRATE_IP_ENTRY ip = m_model->ipEntry(m_ipTable->currentIndex().row());
        if ((ip.status==LTR_CRATE_IP_STATUS_OFFLINE) ||
            (ip.status==LTR_CRATE_IP_STATUS_ERROR)) {
            emit reqConnect(ip.ip_addr);
        } else {
            emit reqDisconnect(ip.ip_addr);
        }
    }
}


void IpEntriesPanel::checkActEnable() {
    if (m_con && (m_con->status() == LtrdConnection::STATUS_ONLINE)) {
        int size = m_model->ipEntryCount();
        bool fnd_con=false, fnd_disc=false;
        for (int i=0; (!fnd_con || !fnd_disc) && (i < size); i++) {
            TLTR_CRATE_IP_ENTRY entry = m_model->ipEntry(i);
            if (entry.ip_addr) {
                if ((entry.flags & LTR_CRATE_IP_FLAG_AUTOCONNECT) &&
                        (entry.status != LTR_CRATE_IP_STATUS_ONLINE)) {
                    fnd_con = true;
                }

                if ((entry.status == LTR_CRATE_IP_STATUS_ONLINE) ||
                        (entry.status== LTR_CRATE_IP_STATUS_CONNECTING)) {
                    fnd_disc = true;
                }
            }
        }

        m_actConnectAuto->setEnabled(fnd_con);
        m_actDisconnectAll->setEnabled(fnd_disc);

        if (m_ipTable->currentIndex().isValid()) {
            TLTR_CRATE_IP_ENTRY ip = m_model->ipEntry(m_ipTable->currentIndex().row());
            m_actConnect->setEnabled((ip.status == LTR_CRATE_IP_STATUS_OFFLINE) ||
                                 (ip.status == LTR_CRATE_IP_STATUS_ERROR));
            m_actDisconnect->setEnabled(ip.status != LTR_CRATE_IP_STATUS_OFFLINE);

            m_actRemove->setEnabled((ip.status == LTR_CRATE_IP_STATUS_OFFLINE) ||
                                    (ip.status == LTR_CRATE_IP_STATUS_ERROR));
        } else {
            m_actConnect->setEnabled(false);
            m_actDisconnect->setEnabled(false);
            m_actRemove->setEnabled(false);
        }
        m_actAdd->setEnabled(true);
    } else {
        m_actAdd->setEnabled(false);
        m_actRemove->setEnabled(false);
        m_actConnect->setEnabled(false);
        m_actDisconnect->setEnabled(false);
        m_actConnectAuto->setEnabled(false);
        m_actDisconnectAll->setEnabled(false);
    }
}

void IpEntriesPanel::srvStatusChanged(LtrdConnection::connStatus status) {
    checkActEnable();
}
