/********************************************************************************************
 *                                                                                          *
 * Copyright (C) 2017 Armin Felder, Dennis Beier                                            *
 * This file is part of RocketChatMobileEngine <https://git.fairkom.net/chat/fairchat>.     *
 *                                                                                          *
 * RocketChatMobileEngine 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.                                                      *
 *                                                                                          *
 * RocketChatMobileEngine 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 RocketChatMobileEngine. If not, see <http://www.gnu.org/licenses/>.           *
 *                                                                                          *
 ********************************************************************************************/



#include <QGuiApplication>

#include "rocketchat.h"
#include "utils.h"
#include "segfaulthandler.h"
#include <QDesktopServices>
#include <QClipboard>

#include "CustomModels/models.h"

#ifdef Q_OS_IOS

#endif
#ifdef Q_OS_ANDROID
#include "android/androidcheckpermissions.h"
#include "android/androidbadges.h"
#endif
#ifdef Q_OS_WINRT
#include "WinRt/keypadhelper.h"
#include <QInputMethod>
#endif
#include <QCoreApplication>

/**
 * @brief RocketChat::RocketChat
 * @param restApi
 * @param ddp
 */
RocketChat::RocketChat( QGuiApplication *app )
{
#ifdef Q_OS_IOS
    //UrlHandler *handler = new UrlHandler;
    // QDesktopServices::setUrlHandler("file",handler,"files");
    // connect(handler,&UrlHandler::openFile,this,&RocketChat::openIosFile);

#endif
    this->mApp = app;
    connect( app, &QGuiApplication::applicationStateChanged, this, &RocketChat::onApplicationStateChanged, Qt::UniqueConnection );
    this->mStorage = PersistanceLayer::instance();

#ifdef Q_OS_WINRT
    //KeypadHelper *helper = new KeypadHelper();
    //helper->showKeypad();
    mInputMethod = QGuiApplication::inputMethod();
    connect( mInputMethod, &QInputMethod::visibleChanged, this, &RocketChat::onKeyboardVisiblityChanged );
#endif
#ifdef Q_OS_ANDROID
    mAndroidStatusBarColor = new AndroidStatusBarColor;
#endif
    qRegisterMetaType<ConnectionState>( "ConnectionState" );
    qRegisterMetaType<Qt::ApplicationState>( "Qt::ApplicationState" );


}

RocketChat::~RocketChat()
{
    mServerThread.quit();
    mStorageThread.quit();
    mServerThread.wait();
    mStorageThread.wait();
}


void RocketChat::joinChannel( const QString &pServerId, const QString &pChannelId )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {

        QMetaObject::invokeMethod( mServerMap.first(),  "joinChannel", Q_ARG( QString, pChannelId ) );

        if ( !mFileToShare.isEmpty() ) {
            uploadSharedFileToChannel( pChannelId );
        }
    }
}

void RocketChat::joinChannelByNameAndType( const QString &pServerId, const QString &pChannelName, const QString &pType )
{
    Q_UNUSED( pServerId )

    if ( mServerStatus ) {

        QMetaObject::invokeMethod( mServerMap.first(),  "joinChannelByNameAndType", Q_ARG( QString, pChannelName ), Q_ARG( QString, pType ) );
    }
}

void RocketChat::login( const QString &pServerId, const QString &pUsername, const QString &pPassword )
{
    Q_UNUSED( pServerId );

    if ( pUsername != mStorage->getUserName() ) {
        mStorage->wipeDb();
    }

    qDebug() << "login thread id: " << QThread::currentThreadId();

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "login", Q_ARG( QString, pUsername ), Q_ARG( QString, pPassword ) );
    }
}

void RocketChat::loginWithSamlToken( const QString &pToken )
{
    if ( !pToken.isEmpty() ) {
        if ( mServerStatus ) {
            QMetaObject::invokeMethod( mServerMap.first(),  "loginWtihSamlToken", Q_ARG( QString, pToken ) );
        }
    }
}

void RocketChat::loginWithMethod( const QString &method, const QString &payload )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "loginWithMethod", Q_ARG( QString, method ), Q_ARG( QString, payload ) );
    }
}

void RocketChat::loadRecentHistory( const QString &pChannelId )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "loadRecentHistory", Q_ARG( QString, pChannelId ) );
    }
}

void RocketChat::loadHistoryTill( const QString &pChannelId, qint64 pTs )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "loadHistoryTill", Q_ARG( QString, pChannelId ), Q_ARG( qint64, pTs ) );
    }
}

bool RocketChat::isServerReady()
{
    return mServerStatus;
}

bool RocketChat::isStorageReady()
{
    return mStorageStatus;
}

void RocketChat::forceVirtualKeyboardShow()
{
    QGuiApplication::inputMethod()->setVisible( true );
}

void RocketChat::forceVirtualKeyboardHide()
{
    QGuiApplication::inputMethod()->setVisible( false );
}

void RocketChat::setStatusBarColor( const QString &pColor )
{
#ifdef Q_OS_ANDROID
    mAndroidStatusBarColor->setStatusBarColor( pColor );
#else
    Q_UNUSED( pColor )
#endif
}

QVariantMap RocketChat::checkForChannelSwitchRequest()
{
    return mChannelSwitchRequest;
}

void RocketChat::resetChannelSwitchRequest()
{
    mChannelSwitchRequest.clear();
}

void RocketChat::channelViewReady()
{
#ifdef Q_OS_IOS
    emit checkForLinkedFile();
#endif
}

bool RocketChat::customEmojisReady()
{
    return mEmojisReady;
}

void RocketChat::checkLoggedIn()
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "requestIsLoggedIn" );
    }
}

void RocketChat::getChannelDetails( const QString &pServerId, const QString &pChannelName )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "requestGetChannelDetails", Q_ARG( QString, pChannelName ) );
    }
}

void RocketChat::createVideoCall( const QString &pServerId, const QString &pChannelId )
{
    Q_UNUSED( pServerId );
    QMetaObject::invokeMethod( mServerMap.first(), "createVideoCall", Q_ARG( QString, pChannelId ) );
}

void RocketChat::copyToClipboard( const QString &text )
{
    QGuiApplication::clipboard()->setText( text );
}

void RocketChat::blockUser( const QString &pChannelId )
{
    QMetaObject::invokeMethod( mServerMap.first(), "blockUser", Q_ARG( QString, pChannelId ) );
}

void RocketChat::unBlockUser( const QString &pChannelId )
{
    QMetaObject::invokeMethod( mServerMap.first(), "unBlockUser", Q_ARG( QString, pChannelId ) );
}

void RocketChat::leaveChannel( const QString &pChannelId )
{
    QMetaObject::invokeMethod( mServerMap.first(), "leaveChannel", Q_ARG( QString, pChannelId ) );
}

void RocketChat::hideChannel( const QString &pChannelId )
{
    QMetaObject::invokeMethod( mServerMap.first(), "hideChannel", Q_ARG( QString, pChannelId ) );
}

void RocketChat::reportAbusiveContent( const QString &pMessageId, const QString &pAuthor )
{
    QMetaObject::invokeMethod( mServerMap.first(), "reportAbusiveContent", Q_ARG( QString, pMessageId ), Q_ARG( QString, pAuthor ) );
}

void RocketChat::end()
{
    QCoreApplication::quit();
}

void RocketChat::searchMessage( const QString &pTerm, const QString &pChannelId )
{
    QMetaObject::invokeMethod( mServerMap.first(), "searchMessage", Q_ARG( QString, pTerm ), Q_ARG( QString, pChannelId ) );
}

void RocketChat::searchRoom( const QString &pTerm )
{
    QMetaObject::invokeMethod( mServerMap.first(), "searchRoom", Q_ARG( QString, pTerm ), Q_ARG( QString, "" ) );
}

void RocketChat::searchRoomByType( const QString &pTerm, const QString &pType )
{
    QMetaObject::invokeMethod( mServerMap.first(), "searchRoom", Q_ARG( QString, pTerm ), Q_ARG( QString, pType ) );
}

bool RocketChat::newServerByDomain( const QString &domain )
{
    newServerMutex.lock();
    mDdpConnectionEstablished = false;

    emit offline();

    if ( !mServerMap.isEmpty() ) {
        auto firstServer = mServerMap.first();
        mServerMap.remove( firstServer->getServerId() );

        auto self = this;
        connect( firstServer, &RocketChatServerData::destroyed, [ &, self, domain]() {
            qDebug() << "domain: " << domain;
            QString baseUrl = domain;
            QString apiUri = QStringLiteral( "https://" ) + domain + QStringLiteral( "/api/v1" );

            Models::resetModels();

            RocketChatServerData *server =  new RocketChatServerData( domain, baseUrl, apiUri );

            registerServer( server );
            newServerMutex.unlock();
        } );
        QMetaObject::invokeMethod( firstServer, "deleteLater" );

    } else {
        QString baseUrl = domain;
        QString apiUri = QStringLiteral( "https://" ) + domain + QStringLiteral( "/api/v1" );

        Models::resetModels();

        RocketChatServerData *server = new RocketChatServerData( domain, baseUrl, apiUri );

        registerServer( server );
        newServerMutex.unlock();

    }

    return 0;
}

//TODO: make asynchonous
void RocketChat::getUserOfChannel( const QString &pServerId, const QString &pChannelId )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "requestUsersOfChannel", Q_ARG( QString, pChannelId ) );
    }
}


void RocketChat::openPrivateChannelWith( const QString &pServerId, const QString &pUsername )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "openPrivateChannelWith", Q_ARG( QString, pUsername ) );
    }
}

void RocketChat::getFileRessource( const QString &pUrl )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "getFileRessource", Q_ARG( QString, pUrl ), Q_ARG( QString, QStringLiteral( "temp" ) ) );
    }
}

void RocketChat::getFileRessource( const QString &pUrl, const QString &pType )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "getFileRessource", Q_ARG( QString, pUrl ), Q_ARG( QString, pType ) );
    }
}

void RocketChat::uploadVideo( const QString &pChannelId, const QString &pPath )
{
    qDebug() << "video path" << pPath;

    if ( pPath.length() ) {

        QStringList split = pPath.split( Utils::getPathPrefix() );

        qDebug() << "splitted string" << split;
        QString realpath;

        if ( split.count() > 1 ) {
            realpath = split[1];
        } else {
            realpath = split[0];
        }

        qDebug() << "video path" << realpath;
        uploadFile( pChannelId, realpath );
    }
}

void RocketChat::uploadFile( const QString &pChannelId, const QString &pPath )
{
    qDebug() << "upload file called";
    mCurrentChannel = pChannelId;
    openFileNameReady( pPath );

}

void RocketChat::addUsersToChannel( const QString &pServerId, const QString &pChannelName, const QString &pUsernames )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QStringList unserList = pUsernames.split( ',' );
        QMetaObject::invokeMethod( mServerMap.first(), "addUsersToChannel", Q_ARG( QString, pChannelName ), Q_ARG( QStringList, unserList ) );
    }
}


void RocketChat::sendMessage( const QString &pServerId, const QString &pChannelId, const QString &pMessage )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        RocketChatServerData *server = mServerMap.first();
        QMetaObject::invokeMethod( server,  "sendMessage", Q_ARG( QString, pChannelId ), Q_ARG( QString, pMessage ) );
    }
}

void RocketChat::openFileDialog( const QString &pChannelId )
{
    mCurrentChannel = pChannelId;
#ifdef Q_OS_ANDROID
    openAndroidFileDialog( pChannelId );
#endif

}

void RocketChat::openFileExternally( const QString &pPath )
{
#ifdef Q_OS_LINUX
    Q_UNUSED( pPath );
#endif
#ifdef Q_OS_ANDROID
    Q_UNUSED( pPath );
#endif
#ifdef Q_OS_IOS
    emit openIOSFileDialog( pPath );
#endif

}

void RocketChat::getSortOrderByCategory( const QString &pServerId, const QString &pType )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "requestChannelSortOrder", Q_ARG( QString, pType ) );
    }
}

bool RocketChat::hasCameraPermission()
{
    int granted = 1;
#ifdef Q_OS_ANDROID
    AndroidCheckPermissions permCheck;

    if ( !permCheck.hasCameraAccess() ) {
        granted = 0;
    }

#endif
    return granted;
}

QString RocketChat::getCleanString( const QString &pText )
{
    QString text = Utils::replaceUnicodeEmojis( pText, mServerMap.first()->getEmojiRepo() );
    text = Utils::removeUtf8Emojis( text );
    return text;
}

void RocketChat::getAllChannels()
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "requestAllChannels" );
    }
}

void RocketChat::uploadSharedFileToChannel( const QString &pChannelId )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "uploadFile", Q_ARG( QString, pChannelId ), Q_ARG( QString, mFileToShare ) );
        mFileToShare.clear();
    }
}

void RocketChat::joinJitsiCall( const QString &pServer, const QString &pChannelIdm, const QString &pMessageId )
{
    Q_UNUSED( pServer );
    Q_UNUSED( pMessageId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "joinJitsiCall", Q_ARG( QString, pChannelIdm ) );
    }
}

//TODO: make async
QString RocketChat::getUsername( const QString &pServerId )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        return mServerMap.first()->getUsername();
    } else {
        return "";
    }
}

//TODO: make async
QString RocketChat::getPassword( const QString &pServerId )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        return mStorage->getPassword();
    } else {
        return "";
    }
}

void RocketChat::setUsername( const QString &pServerId, const QString &pUsername )
{
    Q_UNUSED( pServerId );
    mStorage->setUserName( pUsername );
}

void RocketChat::setPassword( const QString &pServerId, const QString &pPassword )
{
    Q_UNUSED( pServerId );
    mStorage->setPassword( pPassword );
}

void RocketChat::setCurrentChannel( const QString &pServerId, const QString &pCurrentChannel, const QString &pChannelName )
{
    Q_UNUSED( pServerId );
    Q_UNUSED( pChannelName );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "setCurrentChannel", Q_ARG( QString, pCurrentChannel ) );
    }
}

QString RocketChat::getNewVideoPath()
{
    return mStorage->getNewVideoPath();
}

void RocketChat::setSetting( const QString &pKey, const QString &pValue )
{
    mStorage->setSetting( pKey, pValue );
}

QString RocketChat::getSetting( const QString &pKey )
{
    return mStorage->getSetting( pKey );
}

void RocketChat::callGalleryPicker( const QString &pChannelId )
{

#ifdef Q_OS_IOS
    mCurrentChannel = pChannelId;
    emit openGallery();

#else
    Q_UNUSED( pChannelId )
#endif
}

void RocketChat::createAccount( const QString &serverId, const QString &email, const QString &username, const QString &password )
{
    Q_UNUSED( serverId )
    auto server = mServerMap.first();
    server->createAccount( username, email, password );
}

void RocketChat::markChannelAsRead( const QString &pChannelId )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "markChannelAsRead", Q_ARG( QString, pChannelId ) );
    }
}

QString RocketChat::getCurrentChannel()
{
    std::tuple<QString, QString> tuple = mStorage->getCurrentChannel();
    QJsonObject data = {{QStringLiteral( "id" ), std::get<0>( tuple )}, {QStringLiteral( "name" ), std::get<1>( tuple )}};
    QJsonDocument doc( data );
    return doc.toJson();
}

void RocketChat::resetCurrentChannel()
{
    mStorage->setCurrentChannel( QStringLiteral( "none" ), QStringLiteral( "none" ) );
}

void RocketChat::getUserSuggestions( const QString &pTerm, const QString &pExceptions )
{
    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "getUserSuggestions", Q_ARG( QString, pTerm ), Q_ARG( QString, pExceptions ) );
    }
}

void RocketChat::getRoomInformation( const QString &pServerId, const QString &pChannelName )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "getRoomInformation", Q_ARG( QString, pChannelName ) );
    }
}

void RocketChat::cancelUpload( const QString &pServerId, const QString &pFileId )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "cancelUpload", Q_ARG( QString, pFileId ) );
    }
}

void RocketChat::logout( const QString &pServerId )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "logout" );
        emit loggedOut( pServerId );
    }
}

void RocketChat::createChannel( const QString &pServerId, const QString &pChannelName, const QStringList &pUsersNames, bool pReadonly )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "createChannel", Q_ARG( QString, pChannelName ), Q_ARG( QStringList, pUsersNames ), Q_ARG( bool, pReadonly ) );
    }
}

void RocketChat::createPrivateGroup( const QString &pServerId, const QString &pChannelName, const QStringList &pUsersNames, bool pReadonly )
{
    Q_UNUSED( pServerId );

    if ( mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(), "createPrivateGroup", Q_ARG( QString, pChannelName ), Q_ARG( QStringList, pUsersNames ), Q_ARG( bool, pReadonly ) );
    }
}

void RocketChat::registerServer( RocketChatServerData *pServer )
{
    qDebug() << "serverId:" << pServer->getServerId();
    qDebug() << "move to thread";

    pServer->moveToThread( &mServerThread );
    qDebug() << "add server to map";
    mServerMap[pServer->getServerId()] = pServer;
    connect( pServer, &RocketChatServerData::readyToCheckForPendingNotification, this, &RocketChat::onServerSlotsReady, Qt::UniqueConnection );

    if ( !mServerThread.isRunning() ) {
        connect( &mServerThread, &QThread::started, this, &RocketChat::serverReadySlot, Qt::UniqueConnection );
        qDebug() << "start thread";
        mServerThread.start();
    } else {
        serverReadySlot();
    }
}

void RocketChat::addLoginMethod( const QMap<QString, QVariant> &pMethod )
{
    Models::getLoginMethodsModel()->addLoginMethod( pMethod );
}

void RocketChat::resetLoginMethods()
{
    Models::getLoginMethodsModel()->clear();
}

void RocketChat::openIosFile( const QString &fileName )
{
    mFileToShare = fileName;
    openShareDialog();
}

void RocketChat::openUrl( const QString url )
{
    if ( !QDesktopServices::openUrl( url ) ) {
        qDebug() << "Jitsi meet could not be opened";
        emit noJitsiMeetAvailable();
    }
}

void RocketChat::registerForPush()
{
#ifdef Q_OS_ANDROID
    mNotificationsObject.registerWithService();
#endif
#ifdef Q_OS_IOS
    emit registerForPushIOS();
#endif
}

void RocketChat::onLogout( const QString &pServerId )
{

    emit loggedOut( pServerId );
}

void RocketChat::onUnreadCountChanged( const QString &pServerId, uint pUnread )
{

    mUnreadSum[pServerId] = pUnread;

    qDebug() << "onUnreadCountChanged";
    uint number = 0;

    if ( mServerStatus ) {
        for ( auto count : mUnreadSum ) {
            number += count;
        }

        qDebug() << "set Unread Badges to:" << number;
#ifdef Q_OS_ANDROID

        AndroidBadges::setNumber( number );
#endif
#ifdef Q_OS_IOS
        emit setBadge( number );
#endif

    }

}

void RocketChat::onLoggedIn( const QString &pServerId )
{
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
    checkForpendingNotification();
#endif
    emit loggedIn( pServerId );
}

void RocketChat::onChannelSwitchRequest( QSharedPointer<RocketChatChannel> pChannel )
{
    //TODO: fix
    bool readonly = pChannel->getReadOnly() && pChannel->getOwnerName() != getUsername( "default" );
    emit channelSwitchRequest( "default", pChannel->getRoomId(), pChannel->getName(), pChannel->getType(), readonly );
    mChannelSwitchRequest[QStringLiteral( "server" )] = "default";
    mChannelSwitchRequest[QStringLiteral( "rid" )] = pChannel->getRoomId();
    mChannelSwitchRequest[QStringLiteral( "name" )] = pChannel->getName();
    mChannelSwitchRequest[QStringLiteral( "type" )] = pChannel->getName();
    mChannelSwitchRequest[QStringLiteral( "ro" )] = readonly;
}

void RocketChat::serverReadySlot()
{
    qDebug() << "server ready slot";
    auto pServer = mServerMap.first();
    connect( pServer, &RocketChatServerData::ddpConnected, this, &RocketChat::onDDPConnected, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::loggedIn, this, &RocketChat::onLoggedIn, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::privateChannelCreated, this, &RocketChat::onPrivateChannelCreated, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::customEmojisReceived, this, &RocketChat::onEmojisReady, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::loggedOut, this, &RocketChat::onLogout, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::suggestionsReady, this, &RocketChat::suggestionsReady, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::loginError, this, &RocketChat::loginError, Qt::UniqueConnection );

    connect( pServer, &RocketChatServerData::fileuploadStarted, this, &RocketChat::fileuploadStarted, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::fileUploadProgressChanged, this, &RocketChat::fileUploadProgressChanged, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::fileUploadFinished, this, &RocketChat::fileUploadFinished, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::error, this, &RocketChat::error, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::fileRessourceProcessed, this, &RocketChat::fileRessourceProcessed, Qt::UniqueConnection );

    connect( pServer, &RocketChatServerData::channelSwitchRequest, this, &RocketChat::onChannelSwitchRequest, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::onHashLoggedIn, this, &RocketChat::hashLoggedIn, Qt::UniqueConnection );

    connect( pServer, &RocketChatServerData::registerForPush, this, &RocketChat::registerForPush, Qt::UniqueConnection );

    connect( pServer, &RocketChatServerData::openUrl, this, &RocketChat::openUrl, Qt::UniqueConnection );

    connect( pServer, &RocketChatServerData::usersReady, this, &RocketChat::channelUsersReady, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::channelDetailsReady, this, &RocketChat::channelDetailsReady, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::unreadCountChanged, this, &RocketChat::onUnreadCountChanged, Qt::UniqueConnection );

    connect( &mNetworkConfiguration, &QNetworkConfigurationManager::onlineStateChanged, this, &RocketChat::onOnlineStateChanged, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::newLoginMethod, this, &RocketChat::addLoginMethod, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::resetLoginMethods, this, &RocketChat::resetLoginMethods, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::offlineMode, this, &RocketChat::offlineMode, Qt::UniqueConnection );

    connect( pServer, &RocketChatServerData::loggingIn, this, &RocketChat::loggingIn, Qt::UniqueConnection );
    connect( pServer, &RocketChatServerData::historyReady, this, &RocketChat::historyReady, Qt::UniqueConnection );

    QMetaObject::invokeMethod( pServer, "init" );

}

void RocketChat::storageReadySlot()
{
    mStorageStatus = true;
    emit storageReady();
}
#ifdef Q_OS_ANDROID
//TODO: do this in a clean way
void RocketChat::openAndroidFileDialog( QString channelId )
{
    currentChannel = channelId;

    if ( mAndroidFileDialog == nullptr ) {
        mAndroidFileDialog = new AndroidFileDialog();
        connect( mAndroidFileDialog, &AndroidFileDialog::existingFileNameReady, this, &RocketChat::openFileNameReady, Qt::UniqueConnection );
        bool success = mAndroidFileDialog->provideExistingFileName();

        if ( !success ) {
            qWarning() << "Problem with JNI or sth like that...";
            disconnect( mAndroidFileDialog, &AndroidFileDialog::existingFileNameReady, this, &RocketChat::openFileNameReady );
            //or just delete fileDialog instead of disconnect
            mAndroidFileDialog->deleteLater();
            mAndroidFileDialog = nullptr;
        }
    }
}

#endif

#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
void RocketChat::checkForpendingNotification()
{
#ifdef Q_OS_ANDROID
    QAndroidJniObject::callStaticMethod<void>( "com/osalliance/rocketchatMobile/MainActivity", "checkForPendingIntent" );
#endif
#ifdef Q_OS_IOS
    emit checkForpendingNotificationIOS();
#endif
}
#endif
void RocketChat::openFileNameReady( const QString &pFile )
{
#ifdef Q_OS_ANDROID
    mAndroidFileDialog->deleteLater();
    mAndroidFileDialog = nullptr;
#endif
    qDebug() << "file to be uploaded " << pFile;

    if ( pFile == "null" ) {
        emit error( QStringLiteral( "invalid file information" ) );
    } else if ( !pFile.isEmpty() && mServerStatus ) {
        QMetaObject::invokeMethod( mServerMap.first(),  "uploadFile", Q_ARG( QString, mCurrentChannel ), Q_ARG( QString, pFile ) );
    }
}

void RocketChat::onKeyboardVisiblityChanged()
{
    QRectF keyBoardRect = mInputMethod->keyboardRectangle();
    float height = floor( keyBoardRect.height() / 2 ) - 5;
    bool visible = mInputMethod->isVisible();
    emit keyboardVisibilityChanged( visible, height );
}

void RocketChat::onEmojisReady( const QVariantList &pEmojiList )
{
    mEmojisReady = true;
    emit emojisReady( pEmojiList );
}

void RocketChat::onServerSlotsReady()
{
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
    auto firstServer = mServerMap.first();
#endif
#ifdef Q_OS_ANDROID
    connect( &mNotificationsObject, &Notifications::tokenReceived, firstServer, &RocketChatServerData::sendPushToken, Qt::UniqueConnection );
    connect( &mNotificationsObject, &Notifications::messageReceived, firstServer, &RocketChatServerData::switchChannel, Qt::UniqueConnection );
#endif
#ifdef Q_OS_IOS
    connect( this, &RocketChat::pushTokenReceived, firstServer, &RocketChatServerData::sendPushToken, Qt::UniqueConnection );
    connect( this, &RocketChat::pushMessageReceived, firstServer, &RocketChatServerData::switchChannel, Qt::UniqueConnection );
#endif
#if defined(Q_OS_ANDROID) || defined(Q_OS_IOS)
    //   checkForpendingNotification();

#endif
    mServerStatus = true;

    if ( !mChannelToSwitchTo.isEmpty() && !mChannelToSwitchToType.isEmpty() ) {
        onExternalChannelSwitchRequest( mChannelToSwitchTo, mChannelToSwitchToType );
    }

    emit serverReady();

}

void RocketChat::onExternalChannelSwitchRequest( const QString &pName, const QString &pType )
{
    if ( mServerStatus ) {
        auto server = mServerMap.first();
        QMetaObject::invokeMethod( server, "switchChannelByName", Q_ARG( QString, pName ), Q_ARG( QString, pType ) );
        mChannelToSwitchTo.clear();
        mChannelToSwitchToType.clear();
    } else {
        qDebug() << "room name: " << pName;
        mChannelToSwitchTo = pName;
        mChannelToSwitchToType.clear();
    }
}

void RocketChat::onDDPConnected( const QString &pServerId )
{
    mDdpConnectionEstablished = true;
    emit serverConnected( pServerId );
}

void RocketChat::onPrivateChannelCreated( const QString &pServerId, const QString &pRid, const QString &pUsername )
{
    qDebug() << "sending private channel creation to gui";
    emit privateChannelCreated( pServerId, pRid, pUsername );
}

void RocketChat::onOnlineStateChanged( bool pOnline )
{
    qDebug() << "stat changed" << pOnline;
    connect( &mNetworkConfiguration, &QNetworkConfigurationManager::onlineStateChanged, this, &RocketChat::onOnlineStateChanged, Qt::UniqueConnection );

    if ( mServerStatus ) {
        if ( pOnline ) {

            for ( const auto &server : mServerMap ) {
                QMetaObject::invokeMethod( server,  "resume" );
            }
        } else {
            for ( const auto &server : mServerMap ) {
                QMetaObject::invokeMethod( server, "setConnectionState", Q_ARG( ConnectionState, ConnectionState::OFFLINE ) );
            }

            emit offline();
        }
    }
}

void RocketChat::onApplicationStateChanged( const Qt::ApplicationState &pState )
{
    if ( pState == Qt::ApplicationActive && mServerStatus ) {
        QDateTime date;
        qDebug() << "application changed to active";
        qDebug() << "time: " << date.currentDateTime();
        qDebug() << "initialized: " << mInitialized;
        qDebug() << "networkconfig: " << mNetworkConfiguration.isOnline();
        //checks if a networkconnection is available

        mInitialized = 1;

        if ( mInitialized && mNetworkConfiguration.isOnline() ) {
            qDebug() << "network connection active";

            for ( const auto server : mServerMap ) {

                //check if websocket connection is still alive, and if DDP is timedout
                QMetaObject::invokeMethod( server, "onStateChanged", Q_ARG( Qt::ApplicationState, pState ) );
            }
        } else {
            mInitialized = 1;
        }
    } else if ( ( ( pState == Qt::ApplicationInactive ) || pState == Qt::ApplicationSuspended ) && mServerStatus ) {
        qDebug() << "away";

        if ( mNetworkConfiguration.isOnline() ) {
            for ( auto server : mServerMap ) {
                QMetaObject::invokeMethod( server, "setUserPresenceStatus", Q_ARG( int, 2 ) );
                QMetaObject::invokeMethod( server,  "disconnectFromServer" );

            }
        }
    }
}

bool RocketChat::getDdpConnectionEstablished() const
{
    return mDdpConnectionEstablished;
}