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


int _gettoken(char *s, char **p1, char **p2) {
    *p1 = 0;
    *p2 = 0;
    if (s == 0) {
        return 0;
    }

    while (strchr(WHITESPACE, *s)) {
        *s++ = 0;
    }
    if (*s == 0) {
        return 0;
    }


    if (strchr(SYMBOLS, *s)) {
        // 处理双字符符号">>"
        if (*s == '>' && *(s+1) == '>') {
            *p1 = s;        // p1指向第一个'>'
            *s++ = 0;       // 终止第一个'>'
            *s++ = 0;       // 终止第二个'>'，s指向下一个字符
            *p2 = s;
            return TOKEN_APPEND;
        }
        if (*s == '&' && *(s+1) == '&') {
            *p1 = s;        
            *s++ = 0;       
            *s++ = 0;       
            *p2 = s;
            return TOKEN_AND;
        }
        if (*s == '|' && *(s+1) == '|') {
            *p1 = s;        // p1指向第一个'>'
            *s++ = 0;       // 终止第一个'>'
            *s++ = 0;       // 终止第二个'>'，s指向下一个字符
            *p2 = s;
            return TOKEN_OR;
        }
        // 其他单字符符号
        int t = *s;
        *p1 = s;
        *s++ = 0;
        *p2 = s;
        return t;
    }

    *p1 = s;
    while (*s && !strchr(WHITESPACE SYMBOLS, *s)) {
        s++;
    }
    *p2 = s;
    return TOKEN_WORD;
}

int gettoken(char *s, char **p1) {
    static int c, nc;
    static char *np1, *np2;

    if (s) {
        nc = _gettoken(s, &np1, &np2);
        return 0;
    }
    c = nc;
    *p1 = np1;
    nc = _gettoken(np2, &np1, &np2);
    return c;
}

int is_builtin(char *cmd) {
    return strcmp(cmd, "cd") == 0 || strcmp(cmd, "pwd") == 0 ||
           strcmp(cmd, "exit") == 0 || strcmp(cmd, "declare") == 0 ||
           strcmp(cmd, "unset") == 0 || strcmp(cmd, "history") == 0;
}
int savedup(struct tempFd * tempfd,int from){
    struct Fd*  temp;
    fd_alloc(&temp);
    dup(from,fd2num(temp));
    //debugf("save dup %d -> %d\n",from,fd2num(temp));
    tempfd->temp[tempfd->size][0] = from;
    tempfd->temp[tempfd->size][1] = fd2num(temp);
    tempfd->size++;
}
int resetdup(struct tempFd * tempfd){
    //debugf("reset dup size %d \n",tempfd->size);
    if(tempfd->size>0){
        for(int i=tempfd->size;i>0;i--){
            //debugf("reset dup %d -> %d\n",(tempfd->temp)[i-1][1],(tempfd->temp)[i-1][0]);
            dup((tempfd->temp)[i-1][1],(tempfd->temp)[i-1][0]);
            close((tempfd->temp)[i-1][1]);
            tempfd->size--;
        }
    }
}

int parsecmd(char **argv, int *rightpipe,struct tempFd * tempfd,int *pipeend,int *inpipe,int * judge) {
    int argc = 0;
    while (1) {
        char *t;
        int fd, r;
        int c = gettoken(0, &t);
        struct Stat stat;
        * judge=0;
        if (*inpipe) {
            *pipeend=PIPE_JUDGE_PIPEEND;
        }
        else{
            if(*pipeend!=PIPE_JUDGE_MAINOUT ) {
                *pipeend=PIPE_JUDGE_NORMAL;
            }
        }

        
        switch (c) {
        case 0:
            return argc;
        case TOKEN_WORD:
            if (argc >= MAXARGS) {
                debugf("too many arguments\n");
                exit(1);
            }
            argv[argc++] = t;
            if(*pipeend==PIPE_JUDGE_MAINOUT ){
                continue;
            }
            break;
        case '<':
            if (gettoken(0, &t) != TOKEN_WORD) {
                debugf("syntax error: < not followed by word\n");
                exit(1);
            }
            if(*pipeend==PIPE_JUDGE_MAINOUT ){
                continue;
            }
            fd = open(t, O_RDONLY);
            if (fd < 0) {
                debugf("failed to open '%s'\n", t);
                exit(1);
            }
            savedup( tempfd,0);
            dup(fd, 0);
            close(fd);
            break;
        case '>':
            if (gettoken(0, &t) != TOKEN_WORD) {
                debugf("syntax error: > not followed by word\n");
                exit(1);
            }
            if(*pipeend==PIPE_JUDGE_MAINOUT ){
                continue;
            }
            fd = open(t, O_WRONLY | O_CREAT | O_TRUNC);
            if (fd < 0) {
                debugf("failed to open '%s'\n", t);
                exit(1);
            }
            savedup( tempfd,1);
            //debugf("dup %d -> %d\n",fd,1);
            dup(fd, 1);
            close(fd);
            break;
        // 处理追加重定向
        case TOKEN_APPEND:
            if (gettoken(0, &t) != TOKEN_WORD) {
                debugf("syntax error: >> not followed by word\n");
                exit(1);
            }
            if(*pipeend==PIPE_JUDGE_MAINOUT ){
                continue;
            }
            // 使用O_APPEND标志打开文件
            fd = open(t, O_WRONLY | O_CREAT);
            
            if (fd < 0) {
                debugf("failed to open '%s'\n", t);
                exit(1);
            }
            fstat(fd, &stat);
            seek(fd,stat.st_size);
            savedup( tempfd,1);
            dup(fd, 1);
            close(fd);
            break;
        case TOKEN_AND:
            *judge = JUDGE_AND;
            return argc;
        case TOKEN_OR:
            *judge = JUDGE_OR;
            return argc;
        case '|':
                if(*pipeend==PIPE_JUDGE_MAINOUT ){
                    continue;
                }
                else{
                    *pipeend=PIPE_JUDGE_NORMAL;
                }
                r=0;
                if(!*inpipe)
                {
                    r = fork();
                }
                if (r == 0) {
                    int p[2];
                    r = pipe(p);
                    if (r != 0) {
                        debugf("pipefaild: %d\n", r);
                        exit(1);
                    }
                    r = fork();
                    if (r < 0) {
                        exit(1);
                    }
                    *inpipe = 1;
                    if (r == 0) {
                        savedup( tempfd,0);
                        dup(p[0], 0);
                        close(p[0]);
                        close(p[1]);
                        int no=0;
                        return parsecmd(argv, rightpipe,tempfd,pipeend,inpipe,&no);
                    } else {
                        *rightpipe = r;
                        savedup( tempfd,1);
                        dup(p[1], 1);
                        close(p[1]);
                        close(p[0]);
                        return argc;
                    }
                    break;
                }
                else {
		            *rightpipe = r;
                    *pipeend=PIPE_JUDGE_MAINOUT ;
	            }	

        }
    }

    return argc;
}
