#include <unistd.h>
#include <pwd.h>
#include <grp.h>

#include <QStringList>
#include <QMutex>
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QTextStream>
#include <QThread>
#include <QDebug>
#include <QProcess>
#include <QByteArray>

#include "common.h"

CheckRes checkCommand(const QStringList &command)
{
    if (command.isEmpty())
        return MAINWINDOW;
    else if(command.at(0).compare("debug")==0)
        return DEBUG;
    else if(command.at(0).compare("show")==0)
        return MAINWINDOW;
    else if (command.size() != 2) {
        return CHECK_FALSE;
    }
    else if (command.at(0).compare("add")==0
          || command.at(0).compare("remove")==0
          || command.at(0).compare("add_uri")==0 ) {
            
        return POPWINDOW;
    }
    return CHECK_FALSE;
}


/**
 * qDebug 重定向：
 * 打印代码位置及调用函数，以及所在线程
 * 
 */
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
    QByteArray localMsg = msg.toLocal8Bit();
    switch (type) {
    case QtDebugMsg:
        fprintf(stdout, "[qDebug] %s:%u\t%s:\n", QString(context.file).remove(QDir::currentPath() + "/").toStdString().c_str(), context.line, context.function);
        break;
    case QtWarningMsg:
        fprintf(stdout, "[qWarning] %s:%u\t%s:\n", QString(context.file).remove(QDir::currentPath() + "/").toStdString().c_str(), context.line, context.function);
        break;
    case QtCriticalMsg:
        fprintf(stdout, "[qCritical] %s:%u\t%s:\n", QString(context.file).remove(QDir::currentPath() + "/").toStdString().c_str(), context.line, context.function);
        break;
    case QtFatalMsg:
        fprintf(stdout, "[qFatal] %s:%u\t%s:\n", QString(context.file).remove(QDir::currentPath() + "/").toStdString().c_str(), context.line, context.function);
        break;
    default:
        break;
    }
    qDebug () << "thread: " << QThread::currentThread();
    fprintf(stdout, "\t %s\n",localMsg.constData());
    return ;
}

QString getRetFromCommand(const QStringList &command)
{
    QProcess proc;
    QStringList options;
    options << "-c"<< command.join(" ");
    proc.closeWriteChannel();
    proc.start("bash", options);
    if (!proc.waitForFinished())
        return "";
    QString res = QString(proc.readAll());
    proc.close();
    if(res.right(1) == "\n")
        res.chop(1);
    return res;
}

void runCommand(const QStringList &command)
{
    QProcess proc;
    QStringList options;
    options << "-c"<< command.join(" ");
    proc.closeWriteChannel();
    proc.startDetached("bash", options);
    
    return ;
}

const char *qstringTochar(const QString &qstr)
{
    if (qstr.isEmpty())
        return nullptr;
    QByteArray ba = qstr.toLatin1();
    return ba.data();
}

QString getUserName()
{
    uid_t uid;
    uid_t NO_UID = -1;
    struct passwd *pw;

    errno = 0;
    uid = geteuid ();
    if (uid == -1 && errno) {
        qDebug () << "get uid error";
        return "";
    }
    pw = getpwuid (uid);
    if (!pw) {
        qDebug ("cannot find name for user ID %lu", (unsigned long int) uid);
        return "";
    }
    return QString(pw->pw_name);
}

bool isAdministratorUser()
{
    static gid_t list[100];
    int n_gp = getgroups(100,list);
    struct group *gp;
    for(int i = 0;i < n_gp; i++) {
        gp = getgrgid(list[i]);
        if (!gp) {
            continue;
        }
        if(QString(gp->gr_name) == "lpadmin") {
            return true;
        }
    }
    return false;
}

void specialDeviceCheck(QString &vendor, QString &model)
{
    QMap<QString, QString>::const_iterator iter = mfgConvertMap.begin();
    while (iter != mfgConvertMap.end())
    {
        if (iter.key().compare(vendor, Qt::CaseInsensitive) == 0) {
            vendor = iter.value();
            break;
        }
        iter++;
    }
    if (model.indexOf("HP") == 0) {
        model.remove(0, 2);
        if (model.at(0) == " ") {
            model.remove(0, 1);
        }
    }

    if (model.contains(" series")) {
        model.remove(" series");
    }
}

QString devicePathCheck(const QString &path)
{
    QString ppath = path;
    if (ppath.contains("unbind@"))
        ppath.remove("unbind@");
    if (ppath.contains("bind@"))
        ppath.remove("bind@");
    return ppath;
}

bool ipIsValid(const QString &ipAddr)
{
    QRegExp rx2("^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$");
    if (!rx2.exactMatch(ipAddr)) {
        return false;
    } else {
        QStringList pieces = ipAddr.split(".");
        bool ok = true;
        for (int i = 0; i < 4; i++) {
            int num = pieces.value(i).toInt(&ok, 10); //合理性判断
            if (!ok) {
                return false;
            }
            if (num > 255) {
                return false;
            }
        }
    }
    return true;
}

extern bool printerNameIsLegal(const QString &printerName)
{
    if (printerName.contains(" ")
     || printerName.contains("/")
     || printerName.contains("\\")
     || printerName.contains("'")
     || printerName.contains('"')
     || printerName.contains("?")
     || printerName.contains("#")
     || printerName.size() > 127) {

        return false;
    }
    return true;
}