#include "Common.h"
#include "ScopeSemaphoreExit.h"

Common::Common(){}

QString Common::getTimeString() {
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString formattedDateTime = currentDateTime.toString("yyyy-MM-dd hh:mm:ss");
    return formattedDateTime;
}
QString Common::timestampToDateString(qint64 timestamp) {
    QDateTime dateTime = QDateTime::fromSecsSinceEpoch(timestamp);
    QString formattedDate = dateTime.toString("yyyy-MM-dd hh:mm:ss");
    return formattedDate;
}
QString Common::generateSignature(const QString& accessKeySecret, const QString& verb,
                                  const QString& contentMD5, const QString& contentType,
                                  const QString& date, const QString& ossHeaders,
                                  const QString& canonicalizedResource)
{
    // 构造规范化的字符串
    QString stringToSign = verb + "\n" +
            contentMD5 + "\n" +
            contentType + "\n" +
            date + "\n" +
            ossHeaders+ "\n" +  // 添加'\n'分隔符，并确保ossHeaders末尾没有多余的空白
            canonicalizedResource;
    
    // 将密钥和消息转换为字节数组
    QByteArray hmacKey = accessKeySecret.toUtf8();
    QByteArray message = stringToSign.toUtf8();
    // 使用HMAC-SHA1计算签名
    QMessageAuthenticationCode mac(QCryptographicHash::Sha1);
    mac.setKey(hmacKey);
    mac.addData(message);
    
    
    QByteArray signature = mac.result().toBase64();  // 直接使用QMessageAuthenticationCode的结果
    
    return QString(signature);
}
QString Common::getVideoOut(){
    return videoOut;
}
void Common::setVideoOut(QString videoOut){
    videoOut.append("/");
    this->videoOut=videoOut;
}


QString Common::getVideoDownload(){
    return videoDownload;
}
void Common::setVideoDownload(QString videoDownload){
    videoDownload.append("/");
    this->videoDownload=videoDownload;
}

QString Common::getImages(){
    return images;
}
void Common::setImages(QString images){
    images.append("/");
    this->images=images;
}

QString Common::DecIpToHexIp(const QString& decIp) {
    // 将 IP 地址按点号分割成多个部分
    QStringList parts = decIp.split(".");

    // 检查 IP 地址是否有效（应包含 4 个部分）
    if (parts.size() != 4) {
        return QString(); // 如果无效，返回空字符串
    }

    QString hexIp; // 用于存储最终的十六进制表示

    // 从最后一个部分开始遍历
    for (int i = 3; i >= 0; --i) {
        // 将每个部分转换为整数
        bool ok;
        int part = parts[i].toInt(&ok);
        if (!ok) return QString(); // 如果转换失败，返回空字符串

        // 将整数转换为十六进制字符串，并在必要时补零
        QString hexPart = QString::number(part, 16).rightJustified(2, '0');

        // 将十六进制字符串添加到结果中
        hexIp.append(hexPart);
    }

    // 在结果前添加 "0x" 以表示十六进制
    hexIp.prepend("0x");

    return hexIp; // 返回最终的十六进制表示
}
QString Common::GetLocalIp() {
    QString ipAddress;
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
    for (const QHostAddress& address : list) {
        if (address != QHostAddress::LocalHost && address.toIPv4Address()) {
            ipAddress = address.toString();
            break;
        }
    }
    if (ipAddress.isEmpty()) {
        ipAddress = QHostAddress(QHostAddress::LocalHost).toString();
    }
    return ipAddress;
}

// 计算校验和
unsigned short Common::calculate_checksum(void *b, int len) {
    unsigned short *buf = (unsigned short *)b;
    unsigned int sum = 0;
    unsigned short result;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char *)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    result = ~sum;
    return result;
}


bool Common::pingAddress(const QString &address) {

    QByteArray &&byJsonIp = address.toUtf8();
    const char *target = byJsonIp.data();

    struct sockaddr_in dest;
    struct hostent *host_entity;

    // 解析主机名或IP地址
    if ((host_entity = gethostbyname(target)) == NULL) {
        perror("gethostbyname");
        return false; // 解析失败，返回false
    }

    memset(&dest, 0, sizeof(dest));
    dest.sin_family = AF_INET;
    dest.sin_addr = *(struct in_addr *)host_entity->h_addr;

    // 创建原始套接字
    int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
    if (sock < 0) {
        perror("socket");
        return false; // 套接字创建失败，返回false
    }

    // 设置2秒的接收超时
    struct timeval timeout;
    timeout.tv_sec = 2;  // 2秒
    timeout.tv_usec = 0; // 0微秒
    if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) < 0) {
        perror("setsockopt");
        close(sock);
        return false; // 设置超时失败，返回false
    }

    // 设置ICMP包头
    struct icmphdr icmp_hdr;
    icmp_hdr.type = ICMP_ECHO;      // ICMP Echo Request
    icmp_hdr.code = 0;
    icmp_hdr.un.echo.id = getpid(); // 使用进程ID作为标识符
    icmp_hdr.un.echo.sequence = 1;
    icmp_hdr.checksum = 0;

    // 计算ICMP校验和
    icmp_hdr.checksum = calculate_checksum(&icmp_hdr, ICMP_HDRLEN);

    // 发送ICMP数据包
    if (sendto(sock, &icmp_hdr, ICMP_HDRLEN, 0, (struct sockaddr *)&dest, sizeof(dest)) <= 0) {
        perror("sendto");
        close(sock);
        return false; // 发送失败，返回false
    }

    // 接收ICMP回复
    char buffer[1024];
    struct sockaddr_in recv_addr;
    socklen_t addr_len = sizeof(recv_addr);

    if (recvfrom(sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&recv_addr, &addr_len) <= 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // 超时错误处理
            printf("Ping timeout.\n");
        } else {
            // 其他接收错误
            perror("recvfrom");
        }
        close(sock);
        return false; // 超时或接收失败，返回false
    }

    // 关闭套接字
    close(sock);
    return true; // 成功，返回true
}





//获取本机mask
bool GetLocalNetMask(const char *eth_inf,char* netmask_addr)
{
    int sock_netmask;
    struct ifreq ifr_mask;
    struct sockaddr_in *net_mask;

    sock_netmask = socket( AF_INET, SOCK_STREAM, 0 );
    if( sock_netmask == -1)
    {
        perror("create socket failture...GetLocalNetMask\n");
        return false;
    }

    memset(&ifr_mask, 0, sizeof(ifr_mask));
    strncpy(ifr_mask.ifr_name, eth_inf, sizeof(ifr_mask.ifr_name )-1);

    if( (ioctl( sock_netmask, SIOCGIFNETMASK, &ifr_mask ) ) < 0 )
    {
        printf("mac ioctl error\n");
        return false;
    }

    net_mask = ( struct sockaddr_in * )&( ifr_mask.ifr_netmask );
    strcpy( netmask_addr, inet_ntoa( net_mask -> sin_addr ) );
    close( sock_netmask );
    return true;
}
//获取本机gateway
bool GetLocalGateWay(char* gateway)
{
    FILE *fp;
    char buf[512];
    char cmd[128];
    char *tmp;

    strcpy(cmd, "ip route");
    fp = popen(cmd, "r");
    if(NULL == fp)
    {
        perror("popen error");
        return false;
    }
    while(fgets(buf, sizeof(buf), fp) != NULL)
    {
        tmp =buf;
        while(*tmp && isspace(*tmp))
            ++ tmp;
        if(strncmp(tmp, "default", strlen("default")) == 0)
            break;
    }
    sscanf(buf, "%*s%*s%s", gateway);
    pclose(fp);

    return true;
}

// 确定当前网络接口
void Common::determine_interface(char *interface) {
    struct ifaddrs *ifaddr, *ifa;
    int family, s;
    char host[NI_MAXHOST];

    if (getifaddrs(&ifaddr) == -1) {
        perror("getifaddrs");
        exit(EXIT_FAILURE);
    }

    // Walk through linked list, maintaining head pointer so we can free list later
    for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
        if (ifa->ifa_addr == NULL)
            continue;

        family = ifa->ifa_addr->sa_family;

        // Check for IPv4 or IPv6
        if (family == AF_INET || family == AF_INET6) {
            s = getnameinfo(ifa->ifa_addr,
                            (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6),
                            host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
            if (s != 0) {
                printf("getnameinfo() failed: %s\n", gai_strerror(s));
                exit(EXIT_FAILURE);
            }

            // Check if the interface is up and running
            if (ifa->ifa_flags & IFF_UP && ifa->ifa_flags & IFF_RUNNING) {
                strncpy(interface, ifa->ifa_name, IFNAMSIZ - 1);
                break;
            }
        }
    }

    freeifaddrs(ifaddr);
}
QString Common::GetLocalGateWay() {
    FILE *fp;
    char buf[512];
    char cmd[128];
    char gateway[INET_ADDRSTRLEN] = {0};  // Store the gateway address

    strcpy(cmd, "ip route");
    fp = popen(cmd, "r");
    if (NULL == fp) {
        perror("popen error");
        return QString();
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
        char *tmp = buf;
        while (*tmp && isspace(*tmp))
            ++tmp;
        if (strncmp(tmp, "default", strlen("default")) == 0)
            break;
    }

    sscanf(buf, "%*s%*s%s", gateway);  // Capture the third word as gateway
    pclose(fp);

    return QString(gateway);  // Convert C-string to QString
}

Common::~Common(){}
