#ifndef WIN32

#include "dcinotifycontrol.h"
#include "dctransferview.h"
#include "dcconfig.h"
#include "dcgui.h"

#include <QDir>
#include <QFile>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QTextStream>
#include <QPushButton>
#include <QMessageBox>
#include <QTreeWidgetItemIterator>
#include <QWidget>

//#include <QtDebug>

#include <dclib/cfilemanager.h>

DCInotifyControl *g_pInotifyControl;


DCInotifyControl::DCInotifyControl(QWidget *parent): QDialog(parent)
{
	setupUi(this);

        eis_path = QDir::homePath() + "/.eiskaltdc";
        active_item = NULL;

        InitDocument();

        LoadDirs();

        if ((!dirs.empty())){

            inotify = new DCInotify();

            if (!inotify->init_inotify()){
                m_bIsInitialized = false;
                return;
            }
            inotify->setRecursive(g_pConfig->GetInotifyRecursive());
            inotify->setInterval(g_pConfig->GetInotifyInterval());
            connect(inotify, SIGNAL(fs_event(InotifyObject*)), this, SLOT(slotFSEvent(InotifyObject*)));

            for (int i = 0; i < dirs.size(); i++)
                inotify->addDirectory(dirs.at(i));

            inotify->start();

            m_bIsInitialized = true;

            timer = new QTimer(this);
            timer->setSingleShot(true);
            connect(timer, SIGNAL(timeout()), this, SLOT(slotTimerDone()));
            timer->start(g_pConfig->GetInotifyInterval()*1000/2);

            //qDebug() << "Timer initialized for " << g_pConfig->GetInotifyInterval()*1000/2 << " msecs";

            collector = new QTimer(this);
            connect(collector, SIGNAL(timeout()), this, SLOT(slotCollectorStart()));
            collector->setSingleShot(true);

            slotTimerIntervalChanged(g_pConfig->GetInotifyInterval());

        }

        g_pInotifyControl = this;

        pending = false;

}

DCInotifyControl::~DCInotifyControl()
{
    timer->stop();
    collector->stop();
    if (inotify){
        inotify->terminate();
        inotify->wait(1000);
        delete inotify;
    }

    QFile file(eis_path + "/inotify");

    if (file.open(QIODevice::WriteOnly) && (!dirs.empty())){
        QTextStream stream(&file);

        for (int i = 0; i < dirs.size(); i++)
            stream << dirs.at(i) << "\n";

        dirs.clear();
    }

    file.close();

    if (!events.empty()){
        for (int i = 0; i < events.size(); i++)
            delete events.at(i);
    }

    QTreeWidgetItemIterator it(treeWidget_SHARE, QTreeWidgetItemIterator::NotHidden);

    while(*it){
        if (*it)
            delete *it;
        ++it;
    }

    treeWidget_SHARE->clear();

}

void DCInotifyControl::slotAccept()
{
    hide();
}

void DCInotifyControl::InitDocument()
{
    InotifyMessageType i_type = g_pConfig->GetInotifyMessageType();

    if (IS_INOTIFY_CHG(i_type))
        checkBox_ME->setChecked(true);
    else
        checkBox_ME->setChecked(false);

    if (IS_INOTIFY_CRT(i_type))
        checkBox_CE->setChecked(true);
    else
        checkBox_CE->setChecked(false);

    if (IS_INOTIFY_DEL(i_type))
        checkBox_DE->setChecked(true);
    else
        checkBox_DE->setChecked(false);

    if (IS_INOTIFY_LOG(i_type)){
        checkBox_ME->setEnabled(false);
        checkBox_CE->setEnabled(false);
        checkBox_DE->setEnabled(false);

        radioButton_ASK->setEnabled(false);
        radioButton_NONE->setEnabled(false);
        radioButton_RS->setEnabled(false);

        checkBox_LOGONLY->setChecked(true);
    }

    spinBox_TIMER->setValue(g_pConfig->GetInotifyInterval());

    switch (g_pConfig->GetInotifyAction()){
        case eInotifyAsk:
            radioButton_ASK->setChecked(true);
            break;
        case eInotifyNone:
            radioButton_NONE->setChecked(true);
            break;
        case eInotifyRS:
            radioButton_RS->setChecked(true);
            break;
    }

    checkBox_RECURSIVE->setChecked(true);

    connect(radioButton_ASK, SIGNAL(clicked()), this, SLOT(slotInotifyActionChange()));
    connect(radioButton_NONE, SIGNAL(clicked()), this, SLOT(slotInotifyActionChange()));
    connect(radioButton_RS, SIGNAL(clicked()), this, SLOT(slotInotifyActionChange()));

    connect(checkBox_ME, SIGNAL(clicked()), this, SLOT(slotInotifyFilterChange()));
    connect(checkBox_CE, SIGNAL(clicked()), this, SLOT(slotInotifyFilterChange()));
    connect(checkBox_DE, SIGNAL(clicked()), this, SLOT(slotInotifyFilterChange()));

    connect(checkBox_LOGONLY, SIGNAL(clicked()), this, SLOT(slotLogOnly()));

    connect(spinBox_TIMER, SIGNAL(valueChanged(int)), this, SLOT(slotTimerIntervalChanged(int)));

    connect(treeWidget_SHARE, SIGNAL(itemClicked(QTreeWidgetItem*,int)), this, SLOT(slotTreeWidgetItemClicked(QTreeWidgetItem*,int)));

    connect(pushButton_RESTORE, SIGNAL(clicked()), this, SLOT(slotRestoreShareList()));
    connect(pushButton_REMOVE, SIGNAL(clicked()), this, SLOT(slotRemoveSelectedItem()));
    connect(pushButton_APPLY, SIGNAL(clicked()), this, SLOT(slotApply()));
    connect(pushButton_QUIT, SIGNAL(clicked()), this, SLOT(slotAccept()));

    connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentTabChanged(int)));

}

void DCInotifyControl::LoadDirs()
{
    QFile file(eis_path + "/inotify");
    CList<DCConfigShareFolder> list;
    DCConfigShareFolder * csf;

    g_pConfig->GetSharedFolders(&list);

    if (!file.exists()){

        csf = 0;

        while( (csf=list.Next(csf)) != 0 )
        {
                QTreeWidgetItem * item = new QTreeWidgetItem( treeWidget_SHARE );
                item->setText( 0, csf->m_sPath.Data() );
                item->setText( 1, csf->m_sAlias.Data() );

                dirs << QString(csf->m_sPath.Data());

               // qDebug() << "Loaded: " << QString(csf->m_sPath.Data());
        }

    }
    else{

        if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
            return;

        QTextStream in(&file);

        while (!in.atEnd()){
            QString folder = in.readLine();
            folder.replace(QString("\n"), QString(""));
            csf = NULL;

            while( (csf=list.Next(csf)) != 0 )
            {
                QString share_folder = csf->m_sPath.Data();

                if (folder == share_folder){
                    dirs << QString(csf->m_sPath.Data());

                    QTreeWidgetItem * item = new QTreeWidgetItem( treeWidget_SHARE );

                    item->setText( 0, csf->m_sPath.Data() );
                    item->setText( 1, csf->m_sAlias.Data() );

                    //qDebug() << "Loaded: " << QString(csf->m_sPath.Data());
                }
            }
        }

        file.close();
    }
}

inline bool DCInotifyControl::isInitialized() const
{ return m_bIsInitialized; }

void DCInotifyControl::slotFSEvent(InotifyObject *obj)
{
    mutex.lock();

        events << obj;

    mutex.unlock();
}

void DCInotifyControl::slotTimerDone()
{
    mutex.lock();

    if (events.empty()){
        //qDebug() << "Event quique empty.";
        timer->start(g_pConfig->GetInotifyInterval()*1000/2);
        //qDebug() << "Timer interval set for " << (g_pConfig->GetInotifyInterval()*1000/2) << " msecs";
        collector->start(10000);
    }
    else{
        //qDebug() << "Event quique not empty.";
        InotifyObject *obj = NULL;
        InotifyMessageType i_type = g_pConfig->GetInotifyMessageType();

        for (int i = 0; i < events.size(); i++){
            //qDebug() << events.size() << " elements in quique.";
            obj = events.at(i);

            if (obj){

                if (!IS_INOTIFY_CHG(i_type) && ((obj->event_type == eICHANGE)||(obj->event_type == eIMOVE)))
                    continue;
                if (!IS_INOTIFY_CRT(i_type) && (obj->event_type == eICREATE))
                    continue;
                if (!IS_INOTIFY_DEL(i_type) && (obj->event_type == eIDELETE))
                    continue;

                QTreeWidgetItem *item = new QTreeWidgetItem(treeWidget_LOG);

                QString it_text = "[";

                switch (obj->event_obj){
                    case eIDIRECTORY:
                        it_text += tr("Directory ");
                        break;
                    case eIFILE:
                        it_text += tr("File ");
                        break;
                }

                switch (obj->event_type){
                    case eICHANGE:
                        it_text += tr("changed");
                        break;
                    case eICREATE:
                        it_text += tr("created");
                        break;
                    case eIDELETE:
                        it_text += tr("deleted");
                        break;
                    case eIMOVE:
                        it_text += tr("moved");
                        break;
                }

                it_text += "]: " + obj->name;

                item->setText(0, it_text);

                if (!IS_INOTIFY_LOG(i_type)){
                    if (obj->event_type == eICREATE){
                        //qDebug() << "eICREATE: " << obj->name;
                        if (deleted.contains(obj->name))
                            deleted.remove(obj->name);
                        if (moved.contains(obj->name))
                            moved.remove(obj->name);
                        if (changed.contains(obj->name))
                            changed.remove(obj->name);

                        created[obj->name] = obj->event_obj;
                    }
                    else if (obj->event_type == eIDELETE){
                        //qDebug() << "eIDELETE: " << obj->name;
                        if (created.contains(obj->name))
                            created.remove(obj->name);
                        if (moved.contains(obj->name))
                            moved.remove(obj->name);
                        if (changed.contains(obj->name))
                            changed.remove(obj->name);

                        deleted[obj->name] = obj->event_obj;
                    }
                    else if (obj->event_type == eICHANGE){
                        //qDebug() << "eICHANGE: " << obj->name;
                        if (created.contains(obj->name))
                            created.remove(obj->name);
                        changed[obj->name] = obj->event_obj;
                    }
                    else if (obj->event_type == eIMOVE){
                        //qDebug() << "eIMOVE: " << obj->name;
                        if (created.contains(obj->name))
                            created.remove(obj->name);
                        if (changed.contains(obj->name))
                            changed.remove(obj->name);
                        if (deleted.contains(obj->name))
                            deleted.remove(obj->name);

                        if (obj->event_obj == eIDIRECTORY){

                            QDir t_dir(obj->name);

                            if (t_dir.exists())
                                 moved[obj->name] = obj->event_obj;
                        }
                        else{

                            if (QFile::exists(obj->name))
                                moved[obj->name] = obj->event_obj;
                        }
                    }

                    //qDebug()<< "Created: " <<  created;
                    //qDebug()<< "Deleted: " << deleted;
                    //qDebug()<< "Changed: " << changed;
                    //qDebug()<< "Moved: " << moved;

                }
            }
        }

        for (int i = 0; i < events.size(); i++){
            obj = events.at(i);

            if (obj){
                delete obj;
            }
        }

        events.clear();

        timer->start(g_pConfig->GetInotifyInterval()*1000/2);
        //qDebug() << "Timer interval set for " << (g_pConfig->GetInotifyInterval()*1000/2) << " msecs";
        collector->start(5000);
    }

    mutex.unlock();
}

void DCInotifyControl::slotInotifyActionChange()
{
    if (radioButton_ASK->isChecked())
        g_pConfig->SetInotifyAction(eInotifyAsk);
    else if (radioButton_NONE->isChecked())
        g_pConfig->SetInotifyAction(eInotifyNone);
    else
        g_pConfig->SetInotifyAction(eInotifyRS);
}

void DCInotifyControl::slotInotifyFilterChange()
{
    InotifyMessageType i_type = g_pConfig->GetInotifyMessageType();

    if (checkBox_DE->isChecked())
        SET_INOTIFY_DEL(i_type);
    else
        USET_INOTIFY_DEL(i_type);

    if (checkBox_CE->isChecked())
        SET_INOTIFY_CRT(i_type);
    else
        USET_INOTIFY_CRT(i_type);

    if (checkBox_ME->isChecked())
        SET_INOTIFY_CHG(i_type);
    else
        USET_INOTIFY_CHG(i_type);

    g_pConfig->SetInotifyMessageType(i_type);
}

void DCInotifyControl::slotLogOnly()
{
    InotifyMessageType i_type = g_pConfig->GetInotifyMessageType();

    if (checkBox_LOGONLY->isChecked()){
        checkBox_ME->setEnabled(false);
        checkBox_CE->setEnabled(false);
        checkBox_DE->setEnabled(false);

        radioButton_ASK->setEnabled(false);
        radioButton_NONE->setEnabled(false);
        radioButton_RS->setEnabled(false);

        SET_INOTIFY_LOG(i_type);
    }
    else{
        checkBox_ME->setEnabled(true);
        checkBox_CE->setEnabled(true);
        checkBox_DE->setEnabled(true);

        radioButton_ASK->setEnabled(true);
        radioButton_NONE->setEnabled(true);
        radioButton_RS->setEnabled(true);

        USET_INOTIFY_LOG(i_type);
    }

    g_pConfig->SetInotifyMessageType(i_type);
}

void DCInotifyControl::slotTimerIntervalChanged(int m)
{
    g_pConfig->SetInotifyInterval(m);

    inotify->setInterval(g_pConfig->GetInotifyInterval());
}

void DCInotifyControl::slotCollectorStart()
{
    bool dirty = false;
    eInotifyAction act = g_pConfig->GetInotifyAction();

    if (!created.empty()){

        dirty = true;
        created.clear();

    }
    if (!deleted.empty()){

        dirty = true;
        deleted.clear();

    }
    if (!moved.empty()){

        dirty = true;
        moved.clear();

    }
    if (!changed.empty()){
        QStringList transfers;
        QMapIterator<QString, eIEVENT_OBJ> it(changed);

        g_pTransferView->GetDownloadFileList(transfers);

        /*if (!transfers.empty()){
            for (int i = 0; i < transfers.size(); i++)
                qDebug() << transfers.at(i);
        }*/

        while (it.hasNext()){
            it.next();

            if (transfers.contains(it.key())){
                //qDebug() << "Changed file in transfer";
                continue;
            }
            else{
                QFile file(it.key());
                //qDebug() << "changed_files: " << changed_files;

                if (changed_files.contains(it.key())){
                    //qDebug() << "File in changed_files";
                    if (changed_files[it.key()] != file.size()){
                        //qDebug() << "changed_files[it.key()] != file.size()";
                        changed_files[it.key()] = file.size();
                        continue;
                    }
                    else{
                        //qDebug() << it.key() << " stablizated.";
                        changed_files.remove(it.key());
                        changed.remove(it.key());
                        if (changed.empty())
                            dirty = true;
                    }
                }
                else{
                    changed_files[it.key()] = file.size();
                    continue;
                }

            }
        }
    }

   if (dirty && (act == eInotifyAsk) || pending){

        if (!g_pMainWin->isVisible()){
            pending = true;
            return;
        }

        QMessageBox msg_box;
        QPushButton *rs_btn, *none_btn;

        rs_btn = msg_box.addButton( tr("Recreate share"), QMessageBox::YesRole);
        none_btn = msg_box.addButton( tr("None"), QMessageBox::YesRole );

        msg_box.setText( tr("Files in shared folders were changed. What you want to do now?") );

        msg_box.setWindowModality(Qt::WindowModal);

        msg_box.exec();

        if (msg_box.clickedButton() == rs_btn)
            CFileManager::Instance()->CreateShareList();

        pending = false;
    }
    else if (dirty && (act == eInotifyRS))
        CFileManager::Instance()->CreateShareList();



    slotInotifyActionChange();
}

void DCInotifyControl::slotTreeWidgetItemClicked(QTreeWidgetItem *item, int column)
{
   // qDebug() << item;
    active_item = item;
}

void DCInotifyControl::slotRemoveSelectedItem()
{
    if (active_item){
        treeWidget_SHARE->removeItemWidget(active_item, 0);
        treeWidget_SHARE->removeItemWidget(active_item, 1);

        delete active_item;

        active_item = NULL;
    }
}

void DCInotifyControl::slotRestoreShareList()
{
    QTreeWidgetItemIterator it(treeWidget_SHARE, QTreeWidgetItemIterator::NotHidden);

    while(*it){
        if (*it)
            delete *it;
        ++it;
    }

    treeWidget_SHARE->clear();

    CList<DCConfigShareFolder> list;
    DCConfigShareFolder * csf;

    g_pConfig->GetSharedFolders(&list);

    csf = 0;

    while( (csf=list.Next(csf)) != 0 ){
                QTreeWidgetItem * item = new QTreeWidgetItem( treeWidget_SHARE );
                item->setText( 0, csf->m_sPath.Data() );
                item->setText( 1, csf->m_sAlias.Data() );
    }
}

void DCInotifyControl::slotApply()
{
    QList<QString> new_dirs;
    QTreeWidgetItemIterator it(treeWidget_SHARE, QTreeWidgetItemIterator::NotHidden);

    while(*it){
        new_dirs << (*it)->text(0);
        ++it;
    }

    bool b = false;

    if (new_dirs.size() != dirs.size())
        b = true;
    else{
        if (new_dirs.empty())
            return;

        for (int i = 0; i < new_dirs.size(); i++){
            if (!dirs.contains(new_dirs.at(i))){
                b = true;

                dirs.clear();
            }
        }
    }

    if (new_dirs.empty()){
        dirs.clear();

        ReinitInotify();

        return;
    }

    dirs.clear();

    for (int i = 0; i < new_dirs.size(); i++)
        dirs << new_dirs.at(i);

    ReinitInotify();

    new_dirs.clear();

}

void DCInotifyControl::ReinitInotify()
{
    if (inotify){
            inotify->terminate();
            inotify->wait(1000);
            disconnect(inotify, SIGNAL(fs_event(InotifyObject*)), this, SLOT(slotFSEvent(InotifyObject*)));
            delete inotify;
            inotify = NULL;
            if (timer)
                timer->stop();
            if (collector)
                collector->stop();
    }

    if (!dirs.empty()){

        if (timer)
            timer->stop();
        if (collector)
            collector->stop();

        if (!events.empty()){
            for (int i = 0; i < events.size(); i++)
                delete events.at(i);
        }

        created.clear();
        deleted.clear();
        moved.clear();
        changed.clear();
        changed_files.clear();

        inotify = new DCInotify();

        if (!inotify->init_inotify()){
            m_bIsInitialized = false;
            return;
        }

        inotify->setRecursive(g_pConfig->GetInotifyRecursive());
        inotify->setInterval(g_pConfig->GetInotifyInterval());
        connect(inotify, SIGNAL(fs_event(InotifyObject*)), this, SLOT(slotFSEvent(InotifyObject*)));

        for (int i = 0; i < dirs.size(); i++)
            inotify->addDirectory(dirs.at(i));

        inotify->start();

        m_bIsInitialized = true;

        if (!timer){
            timer = new QTimer(this);
            connect(timer, SIGNAL(timeout()), this, SLOT(slotTimerDone()));
        }

        timer->setSingleShot(true);
        timer->start(g_pConfig->GetInotifyInterval()*1000/2);

        if (!collector){
            collector = new QTimer(this);
            connect(collector, SIGNAL(timeout()), this, SLOT(slotCollectorStart()));
        }

        collector->setSingleShot(true);
    }
    else{
        //qDebug() << "Inotify disabled.";

        m_bIsInitialized = false;
    }

}

void DCInotifyControl::closeEvent(QCloseEvent *e)
{
    if (!shutdown){
        e->ignore();
        hide();
    }
    else
        e->accept();
}

void DCInotifyControl::Shutdown()
{
    shutdown = true;
    setAttribute(Qt::WA_DeleteOnClose);

    g_pInotifyControl = NULL;

    close();
}

void DCInotifyControl::slotCurrentTabChanged(int tab){
    QWidget *par = tabWidget->currentWidget();

    pushButton_QUIT->setParent(par);

    pushButton_QUIT->show();
}

#endif
