#include <shell.h>
#include <lib.h>
#include <fd.h>

static int local_var_count;
static struct LocalVar local_var[MAX_LOCAL_VARCOUNT];

// 执行cd命令
int execute_cd(int argc, char **argv) {
    // 参数个数为0时切换到根目录
	char* path;
	if (argc > 2) {
		printf("Too many args for cd command\n");
		return 1;		
	} else if (argc == 1) {
		path = "/";
	} else {
		path = argv[1];
	}

    // 处理路径
    char cur_path[MAXPATHLEN];
	char abs_path[MAXPATHLEN];
	syscall_get_env_dir(0, cur_path);	
	merge_path(abs_path, cur_path, path);
	
	struct Stat st;
    int r;
	r = stat(abs_path, &st);
    // 检查路径是否存在
	if (r < 0) {
		printf("cd: The directory '%s' does not exist\n", path);
		return 1;
	}
    // 检查是否为目录
	if (!st.st_isdir) {
		printf("cd: '%s' is not a directory\n", path);
		return 1;
	}
    // 设置工作目录
    if (syscall_set_env_dir(0, abs_path) < 0) {
        printf("cd: failed to set directory\n");
        return 1;
    }

    return 0;
}
// 执行pwd命令
int execute_pwd(int argc, char **argv) {
    if (argc != 1) {
        printf("pwd: expected 0 arguments; got %d\n", argc - 1);
        return 2;
    }

    char buf[MAXPATHLEN];
    if (syscall_get_env_dir(0, buf) < 0) {
        strcpy(buf, "/");
    }
    printf("%s\n", buf);
    return 0;
}
// 执行exit命令
int execute_exit(int argc, char **argv) {
    exit(0);//正常退出
    return 0; 
}
// 执行history命令
int execute_history(int argc, char **argv) {
	int fd = open(HISTORY_FILE, O_RDONLY);
	if (fd < 0) {
		debugf("error: failed to open %s\n", HISTORY_FILE);
		return 1;
	}
	static char buf[MAX_COMMAND_LENGTH*HISTORY_FILE_SIZE];
	int r;
	int n;
	while ((n = read(fd, buf, (long)sizeof buf)) > 0) {
		if ((r = write(1, buf, n)) != n) {
			debugf("write error copying %s: %d\n", HISTORY_FILE, r);
		}
	}
	if (n < 0) {
		debugf("read error in file %s: %d\n", HISTORY_FILE, n);
	}
	close(fd);
	return 0;
}
// local 环境变量
int set_local_var(char* key, char* value, int writable) {
    // 检查键值是否已存在
    for (int i = 0; i < local_var_count; ++i) {
        if (strcmp(key, local_var[i].key) == 0) {
            if (!local_var[i].writable) {
                return -E_INVALID_SET_ENV_VAR;
            }
            strcpy(local_var[i].value, value);
            return 0;
        }
    }
    
    // 检查变量表是否已满
    if (local_var_count >= MAXVARCOUNT) {
        return -E_NO_FREE_ENV_VAR;
    }
    
    // 添加新变量
    struct LocalVar *var = &local_var[local_var_count++];
    strcpy(var->key, key);
    strcpy(var->value, value);
    var->writable = writable;
    
    return 0;
}
int remove_local_var(char* key) {
    // 查找变量并检查可写性
    for (int i = 0; i < local_var_count; ++i) {
        if (strcmp(key, local_var[i].key) == 0) {
            if (!local_var[i].writable) {
                return -E_INVALID_SET_ENV_VAR;
            }
            
            // 移除变量：将后续元素前移
            local_var_count--;
            if (i < local_var_count) 
			{
                memmove(&local_var[i], &local_var[i+1], (local_var_count - i) * sizeof(struct LocalVar));
            }
            return 0;
        }
    }
    return -E_ENV_VAR_NOT_FOUND;
}
// 全局 环境变量
int execute_declare(int argc, char **argv) {
    // 解析选项
    int is_env_var = 0;
    int writable = 1;
    
    ARGBEGIN {
        default:
            printf("usage: declare [-xr] [NAME[=VALUE]]\n");
            return 1;
        case 'x':
            is_env_var = 1;
            break;
        case 'r':
            writable = 0;
            break;
    } ARGEND;

    // 处理无参数情况：打印所有变量
    if (argc == 0) {
        print_all_variables();
        return 0;
    }

    // 检查参数数量
    if (argc != 1) {
        printf("usage: declare [-xr] [NAME[=VALUE]]\n");
        return 1;
    }

    // 解析键值对
    char *input = argv[0];
    char *delim = strchr(input, '=');
    
    char key[MAX_LOCAL_KEYLEN];
    char value[MAX_LOCAL_VALUELEN] = "";  // 默认为空字符串
    
    if (delim) {
        // 提取键和值
        size_t key_len = delim - input;
        if (key_len >= MAX_LOCAL_KEYLEN) key_len = MAX_LOCAL_KEYLEN - 1;
        strncpy(key, input, key_len);
        key[key_len] = '\0';
        
        strncpy(value, delim + 1, MAX_LOCAL_VALUELEN - 1);
        value[MAX_LOCAL_VALUELEN - 1] = '\0';
    } else {
        // 无值的情况
        strncpy(key, input, MAX_LOCAL_KEYLEN - 1);
        key[MAX_LOCAL_KEYLEN - 1] = '\0';
    }

    // 设置变量
    return set_variable(is_env_var, key, value, writable);
}

// 辅助函数：打印所有变量
void print_all_variables() {
    // 打印环境变量
    int env_count = syscall_get_env_var_count(0);
    for (int i = 0; i < env_count; ++i) {
        char key[MAX_LOCAL_KEYLEN], value[MAX_LOCAL_VALUELEN];
        syscall_get_env_id_var(0, i, key, value);
        printf("%s=%s\n", key, value);
    }
    
    // 打印局部变量
    for (int i = 0; i < local_var_count; ++i) {
        printf("%s=%s\n", local_var[i].key, local_var[i].value);
    }
}

// 辅助函数：设置变量
int set_variable(int is_env_var, char* key, char* value, int writable) {
    if (is_env_var) {
        // 设置环境变量
        remove_local_var(key);  // 忽略错误，可能不存在
        return syscall_set_env_var(0, key, value, writable) ? 1 : 0;
    } else {
        // 设置局部变量
        syscall_remove_env_var(0, key);  // 忽略错误，可能不存在
        return set_local_var(key, value, writable) ? 1 : 0;
    }
}
int execute_unset(int argc, char **argv) {
	if (argc != 2) {
		printf("usage: unset NAME\n");
		return 1;
	}
	char* key = argv[1];
	if (remove_local_var(key) == -E_INVALID_SET_ENV_VAR) {
		return 1;
	}
	if (syscall_remove_env_var(0, key) == -E_INVALID_SET_ENV_VAR) {
		return 1;
	}
	return 0;
}
int get_var(char* key, char* value) {
	for (int i = 0; i < local_var_count; i++) {
		if (strcmp(key, local_var[i].key) == 0) {
			strcpy(value, local_var[i].value);
			return 0;
		}
	}
	return syscall_get_env_var(0, key, value);
}
// 替换环境变量
void replace_command_var(char* arg) {
    char result[MAX_COMMAND_LENGTH] = {0};  // 结果缓冲区
    char current_var[MAX_LOCAL_KEYLEN] = {0};  // 当前变量名
    char var_value[MAX_LOCAL_VALUELEN] = {0};  // 变量值
    
    char *src = arg;  // 源字符串指针
    char *dest = result;  // 目标缓冲区指针
    char *var_ptr = current_var;  // 变量名收集指针

    while (*src) {
        if (*src == '$') {
            // 开始变量替换
            src++;  // 跳过'$'
            
            // 收集变量名
            while (*src && isvar(*src)) {
                *var_ptr++ = *src++;
            }
            *var_ptr = '\0';  // 终止变量名字符串
            
            // 获取变量值（不存在则置空）
            get_var(current_var, var_value) ? (var_value[0] = '\0') : 0;
            
            // 复制变量值到结果
            char *val_ptr = var_value;
            while (*val_ptr) {
                *dest++ = *val_ptr++;
            }
            
            // 重置变量名收集器
            var_ptr = current_var;
            *var_ptr = '\0';
        } else {
            // 直接复制普通字符
            *dest++ = *src++;
        }
    }
    *dest = '\0';  // 确保结果字符串终止
    
    // 将结果复制回原始参数
    strcpy(arg, result);
}

int runcmd(char *s,struct tempFd *tempfd,int* rightpipe,int argc,char **argv,int pipeend) {
	int returncode =0;
	if(pipeend==PIPE_JUDGE_MAINOUT ){
		returncode = wait(* rightpipe);
		return returncode;
	}
    if (argc <= 0) {
        returncode= -1;
    }
    if(returncode==0){
        argv[argc] = 0;

        // 替换命令中的环境变量
        for (int i = 0; i < argc; i++) {
            if (strchr(argv[i], '$')) {
                replace_command_var(argv[i]);
            }
        }
        if (is_builtin(argv[0])) {
            // 执行内建命令
            if (strcmp(argv[0], "cd") == 0) {
                returncode = execute_cd(argc, argv);
                
            } else if (strcmp(argv[0], "pwd") == 0) {
                returncode = execute_pwd(argc, argv);
                
            } else if (strcmp(argv[0], "exit") == 0) {
                returncode = execute_exit(argc, argv);
                
            } else if (strcmp(argv[0], "declare") == 0) {
                returncode = execute_declare(argc, argv);
                
            } else if (strcmp(argv[0], "unset") == 0) {
                returncode = execute_unset(argc, argv);
            } else if (strcmp(argv[0], "history") == 0) {
                returncode = execute_history(argc, argv);
            }
        }

        // 处理外部命令
        else if (strcmp(argv[0], "touch") == 0) {
            if (argc != 2) {
                printf("touch: expected 1 argument\n");
                returncode=-1;
            }
            if(returncode==0){
            char *touch_argv[] = {"touch", argv[1], NULL};
            int child = spawn("touch", touch_argv);
            returncode=wait(child);
            }
        } 
        else if (strcmp(argv[0], "mkdir") == 0) {
            if (argc < 2) {
                printf("mkdir: expected at least 1 argument\n");
                returncode=-1;
            }
            if(returncode==0){
            char *mkdir_argv[argc+1];
            mkdir_argv[0] = "mkdir";
            for (int i = 1; i < argc; i++) {
                mkdir_argv[i] = argv[i];
            }
            mkdir_argv[argc] = NULL;
            int child = spawn("mkdir", mkdir_argv);
            returncode=wait(child);
            }
        } 
        else if (strcmp(argv[0], "rm") == 0) {
            if (argc < 2) {
                printf("rm: expected at least 1 argument\n");
                returncode=-1;
            }
            if(returncode==0){
            char *rm_argv[argc+1];
            rm_argv[0] = "rm";
            for (int i = 1; i < argc; i++) {
                rm_argv[i] = argv[i];
            }
            rm_argv[argc] = NULL;
            int child = spawn("rm", rm_argv);
            returncode=wait(child);
            }   
        } 
        else {
            // 其他命令
            int child = spawn(argv[0], argv);
            if (child >= 0) {
                returncode=wait(child);
            } else {
                returncode=-1;
                debugf("spawn %s: %d\n", argv[0], child);
            }
        }
    }
    resetdup(tempfd);
    if(*rightpipe!=0  && pipeend!=PIPE_JUDGE_MAINOUT ){//-1 pipeleft 
        //对应最左侧父进程不退出//对应中间
        returncode = wait(*rightpipe);
        exit(returncode);
    }
    if(*rightpipe==0){
        //对应没有子进程的正常指令
        if(pipeend==PIPE_JUDGE_PIPEEND){
            ////对应非正常指令，管道最右侧
            exit(returncode);
        }
    }

	return returncode;
}