#include "LtrdLogPanel.h"

#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
#include <QTableView>
#include <QMenu>
#include <QAction>
#include <QEvent>
#include <QHeaderView>
#include <QScrollBar>
#include <QSettings>

#include "LQTableWidget/LQTableWidget.h"
#include "LQTableWidget/LQTableCopyAction.h"

LtrdLogPanel::LtrdLogPanel(QWidget *parent) :
    QDockWidget(parent)  {

    this->setObjectName("LtrSrvLogPanel");

    m_model = new LtrdLogModel(this);


    m_logbox = new QTableView();
    m_logbox->horizontalHeader()->setVisible(false);
    m_logbox->verticalHeader()->setVisible(false);
    m_logbox->horizontalHeader()->setStretchLastSection(true);
    m_logbox->setEditTriggers(QAbstractItemView::NoEditTriggers);
    m_logbox->setSelectionBehavior(QAbstractItemView::SelectRows);
    m_logbox->setMinimumWidth(320);


    m_logbox->setStyleSheet("QTableView::item { padding: 3px;}");


    m_logbox->setModel(m_model);




    m_logbox->setColumnWidth(0, 175);
    m_logbox->setColumnWidth(1, 135);

    connect(m_model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int , int )),
            SLOT(checkScroll()));

    connect(m_model, SIGNAL(rowsInserted(const QModelIndex &, int , int )),
            SLOT(onInserted(QModelIndex,int,int)));


    checkScroll();

    QFont font = m_logbox->font();
    font.setFamily("Monospace");
    font.setStyleHint(QFont::TypeWriter);
    m_logbox->setFont(font);


    m_actClear = new QAction(m_logbox);
    m_actClear->setIcon(QIcon(":/icons/clear.png"));
    connect(m_actClear, SIGNAL(triggered()), SLOT(clear()));
    m_actClear->setShortcut(tr("Ctrl+D"));
    m_logbox->addAction(m_actClear);

    //warn_icon.load(QCoreApplication::applicationDirPath() + "/icons/warning.jpg");
    //err_icon.load(QCoreApplication::applicationDirPath() + "/icons/error.jpg");

    m_logbox->setContextMenuPolicy(Qt::CustomContextMenu);
    connect(m_logbox, SIGNAL(customContextMenuRequested(QPoint)), SLOT(showContextMenu(QPoint)));

    m_contextMenu = new QMenu(this);


    m_actCopy = new LQTableCopyAction(m_logbox);
    m_actCopy->setIcon(QIcon(":/icons/copy.png"));
    m_logbox->addAction(m_actCopy);
    m_contextMenu->addAction(m_actCopy);

    m_actSelectAll= new QAction(this);
    m_actSelectAll->setIcon(QIcon(":/icons/select_all.png"));
    m_actSelectAll->setShortcut(QKeySequence::SelectAll);
    m_logbox->addAction(m_actSelectAll);
    m_contextMenu->addAction(m_actSelectAll);
    connect(m_actSelectAll, SIGNAL(triggered()), m_logbox, SLOT(selectAll()));


    m_contextMenu->addAction(m_actClear);








    m_levelMenu = new QMenu();



    for (int i=0; i< m_model->logLevelCnt(); i++) {
        LtrdLogModel::logLvlCfg cfg = m_model->logLevelConfig(i);
        QAction* act = new QAction(cfg.name(), this);
        act->setCheckable(true);
        if (cfg.level()==m_model->curLogLevel())
            act->setChecked(true);
        m_logLvlActMap[act] = i;
        m_levelMenu->addAction(act);
        connect(act, SIGNAL(triggered()), SLOT(lvlActTriggered()));
    }

    m_contextMenu->addMenu(m_levelMenu);

    m_actResize = new QAction(this);
    connect(m_actResize, SIGNAL(triggered()), this, SLOT(resizeRows()));
    m_contextMenu->addAction(m_actResize);


    retranslateUi();


    this->setWidget(m_logbox);

    QSettings set;
    set.beginGroup("LtrSrvLogPanel");
    setLogLevel((en_LTR_LogLevel)set.value("loglvl", LTR_LOGLVL_INFO).toInt());
    set.endGroup();

    connect(this, SIGNAL(visibilityChanged(bool)), this,
            SLOT(resizeRows()));
}

LtrdLogPanel::~LtrdLogPanel() {
    QSettings set;
    set.beginGroup("LtrSrvLogPanel");
    set.setValue("loglvl", m_model->curLogLevel());
    set.endGroup();
}

QStringList LtrdLogPanel::logLevelNames() {
    QStringList ret;
    for (int i=0; i < m_model->logLevelCnt(); i++) {
        ret.append(m_model->logLevelConfig(i).name());
    }
    return ret;
}

void LtrdLogPanel::setConnection(LtrdConnection *con) {
    m_model->setConnection(con);
}



void LtrdLogPanel::clear() {
    m_model->clear();
}

void LtrdLogPanel::setLogLevel(en_LTR_LogLevel lvl) {
    m_model->setLogLevel(lvl);
    foreach (QAction* act, m_logLvlActMap.keys()) {
        if (m_model->logLevelConfig(m_logLvlActMap[act]).level()==lvl)
            act->setChecked(true);
        else
            act->setChecked(false);
    }
}

void LtrdLogPanel::resizeRows() {
    m_logbox->resizeRowsToContents();
    m_logbox->repaint();
}

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

    QDockWidget::changeEvent(event);
}

void LtrdLogPanel::showContextMenu(QPoint point) {
    m_contextMenu->popup(m_logbox->mapToGlobal(point));
}

void LtrdLogPanel::lvlActTriggered() {
    QAction* trig_act = qobject_cast<QAction*>(sender());
    if (trig_act)
        setLogLevel(m_model->logLevelConfig(m_logLvlActMap[trig_act]).level());
}




void LtrdLogPanel::retranslateUi() {
    setWindowTitle( tr("%1 log").arg(LTR_SERVICE_NAME));
    m_levelMenu->setTitle(tr("Show log level"));
    m_actClear->setText(tr("Clear"));
    m_actSelectAll->setText(tr("Select &All"));
    m_actResize->setText(tr("Recalculate rows size"));
    m_actCopy->retranslate();
    foreach (QAction *act, m_logLvlActMap.keys()) {
        act->setText(m_model->logLevelConfig(m_logLvlActMap[act]).name());
    }
}

void LtrdLogPanel::checkScroll() {
    QScrollBar* bar = m_logbox->verticalScrollBar();
    bool at_end = bar->value() == bar->maximum();

    if (at_end) {
       connect(m_model, SIGNAL(rowsInserted(const QModelIndex &, int , int )),
               m_logbox, SLOT(scrollToBottom()));
    } else {
       disconnect(m_model, SIGNAL(rowsInserted(const QModelIndex &, int , int )),
                  m_logbox, SLOT(scrollToBottom()));
    }


}

void LtrdLogPanel::onInserted(const QModelIndex &, int first, int last) {
    /* ограничиваем кол-во обновляемых строк. если пришло много сообщений,
     * обновляем размер только у последних */
    static const int update_size_rec_lim = 250;
    if ((last - first)  > update_size_rec_lim)
        first = last - update_size_rec_lim;
    for (int i=first; i <= last; i++) {
        m_logbox->resizeRowToContents(i);
    }
}
