#include "common.h"

// 计算字符串长度
int _strlen(const char *str) {
    if (str == NULL)
        return 0;

    const char *_p = strchr(str, '\0');
    return _p - str;
}


// 自定义 printf 函数
void _printf(const char *format, ...)
{
    va_list args;
    va_start(args, format);

    // 获取当前时间
    time_t now = time(NULL);
    struct tm local_time;
    localtime_r(&now, &local_time);
    char time_str[20]; // YYYY-MM-DD HH:MM:SS 格式
    strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", &local_time);

    // 打印时间戳到控制台
    printf("[%s] ", time_str);
    vprintf(format, args); // 打印内容到控制台
    va_end(args); // 结束对变参列表的处理

    // 重新启动变参列表
    va_start(args, format);

    // 打开日志文件（追加模式）
    FILE *log_file = fopen(PRINT_LOG_FILE, "a");
    if (log_file != NULL) {
        // 打印时间戳到日志文件
        fprintf(log_file, "[%s] ", time_str);

        // 打印内容到日志文件
        vfprintf(log_file, format, args);

        // 关闭日志文件
        fclose(log_file);
    } else {
        perror("Unable to open log file");
    }

    va_end(args); // 结束对变参列表的处理
}

void split_string(char string[], char delims[], char (*whitelist_ip)[WHITELIST_IP_NUM])
{
    int i = 0;
    char *result = NULL;
    char temp[WHITELIST_IP_NUM];                 // 创建一个足够大的副本缓冲区

    // 复制原始字符串到副本
    strncpy(temp, string, sizeof(temp) - 1);
    temp[sizeof(temp) - 1] = '\0';        // 确保字符串以 '\0' 结尾

    result = strtok(temp, delims);               // 使用副本进行拆分
    while (result != NULL && i < WHITELIST_IP_NUM)
    {
        strncpy(whitelist_ip[i], result, WHITELIST_IP_NUM - 1);
        whitelist_ip[i][WHITELIST_IP_NUM - 1] = '\0';   // 确保每个元素以 '\0' 结尾
        i++;
        result = strtok(NULL, delims);
    }
}

// IP段白名单对比
int whitelist(char *client_ip, char (*whitelist_ip)[WHITELIST_IP_NUM])
{
    int i;

    for (i = 0; i < WHITELIST_IP_NUM; i++) {  // 从 i = 0 开始
        // 如果白名单 IP 是空字符串，跳出循环
        if (whitelist_ip[i][0] == '\0') {
            break;
        }

        // 对比 client_ip 的前缀是否与白名单中的IP段匹配
        if (strncmp(client_ip, whitelist_ip[i], strlen(whitelist_ip[i])) == 0) {
            return 1;  // 匹配成功
        }
    }

    return 0;  // 未找到匹配
}

// 地域段白名单对比
int isregion(char *str, char (*region_list)[WHITELIST_IP_NUM])
{
    int i;
    char *p;

    for (i = 0; i < WHITELIST_IP_NUM; i++) {
        // 如果 region_list[i] 为空字符串，跳出循环
        if (region_list[i][0] == '\0') {
            break;
        }

        // 在str中查找 region_list[i]
        p = strstr(str, region_list[i]);
        if (p != NULL) {
            return 1; // 匹配成功，返回1
        }
    }

    return 0; // 没有匹配，返回0
}

int8_t _copy_new_mem(char *src, int src_len, char **dest)
{
    *dest = (char *)malloc(src_len + 1);
    if (*dest == NULL)
        return 1;
    memcpy(*dest, src, src_len);
    *((*dest) + src_len) = '\0';

    return 0;
}

// 返回的时间字符串存储在静态缓冲区中
char *_time() {
    static char temp[BUFFER];
    const char *wday[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
    time_t t = time(NULL);
    struct tm *p = localtime(&t);

    if (!p) {
        perror("localtime failed");
        return NULL;
    }

    snprintf(temp, sizeof(temp), "[%d/%02d/%02d %s %02d:%02d:%02d]", 
             1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, 
             wday[p->tm_wday], p->tm_hour, p->tm_min, p->tm_sec);

    return temp; // 返回静态缓冲区地址
}

// 将字符串转换为IPv4地址
int is_valid_ip(const char *ip)
{
    struct sockaddr_in sa;
    // 将字符串转换为IPv4地址
    int result = inet_pton(AF_INET, ip, &(sa.sin_addr));

    return result != 0;
}

// 修改进程优先级
int _nice(int increment) {
    // 获取当前优先级
    int oldprio = getpriority(PRIO_PROCESS, getpid());
    if (oldprio == -1 && errno != 0) {
        perror("getpriority failed");
        return -1;
    }

    printf("Current priority: %d\n", oldprio);

    // 检查是否溢出
    if ((increment > 0 && oldprio > INT_MAX - increment) ||
        (increment < 0 && oldprio < INT_MIN - increment)) {
        fprintf(stderr, "Priority overflow error\n");
        return -1;
    }

    // 计算新的优先级
    int newprio = oldprio + increment;

    // 检查新的优先级是否在有效范围内
    if (newprio < PRIO_MIN || newprio > PRIO_MAX) {
        fprintf(stderr, "New priority out of range: %d (valid range is %d to %d)\n", newprio, PRIO_MIN, PRIO_MAX);
        return -1;
    }

    // 设置新的优先级
    if (setpriority(PRIO_PROCESS, getpid(), newprio) == -1) {
        perror("setpriority failed");
        return -1;
    }

    printf("New priority: %d\n", newprio);
    return 0;
}

// 判断命令是否存在
int command_exists(const char *command) {
    const char *path_env = getenv("PATH");
    if (!path_env) {
        return 0;  // 如果 PATH 不存在，返回不存在
    }

    char filepath[1024];  // 缓冲区大小
    const char *dir = path_env;

    while (dir && *dir) {
        // 查找 PATH 中的下一个目录
        const char *end = strchr(dir, ':');
        size_t len = end ? (size_t)(end - dir) : strlen(dir);

        // 构建路径并检查长度
        if (snprintf(filepath, sizeof(filepath), "%.*s/%s", (int)len, dir, command) >= (int)sizeof(filepath)) {
            return 0;  // 缓冲区溢出，返回不存在
        }

        // 检查文件是否存在且可执行
        if (access(filepath, X_OK) == 0) {
            puts(filepath);
            return 1;  // 命令存在
        }

        // 更新 dir 指针
        dir = end ? end + 1 : NULL;
    }

    return 0;  // 命令不存在
}

// 定义一个函数，执行命令并返回输出
char *_execute_command(const char *command) {
    FILE *fp;
    char buffer[1024];
    char *output = NULL;
    size_t output_size = 0;
    size_t total_read = 0;

    // 打开管道，执行命令
    fp = popen(command, "r");
    if (fp == NULL) {
        perror("popen");
        return NULL;
    }

    // 读取命令的输出
    while (fgets(buffer, sizeof(buffer), fp) != NULL) {
        size_t len = strlen(buffer);
        if (total_read + len + 1 > output_size) {
            output_size = output_size == 0 ? 128 : output_size * 2;
            char *new_output = realloc(output, output_size);
            if (new_output == NULL) {
                perror("realloc");
                free(output);  // 释放已分配的内存
                pclose(fp);     // 关闭管道
                return NULL;
            }
            output = new_output;
        }
        // 复制内容并增加总计读取的长度
        strcpy(output + total_read, buffer);
        total_read += len;
    }

    // 确保输出以 null 结尾
    if (output_size > 0) {
        output[total_read] = '\0';
    }

    // 关闭管道
    if (pclose(fp) == -1) {
        perror("pclose");
        free(output);  // pclose 失败时释放内存
        return NULL;
    }

    return output;
}

