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

static char cmd_history[HISTORY_FILE_SIZE + 1][MAX_COMMAND_LENGTH];
static int total_history;
static int active_cmd_idx;
static int prev_cursor;
static int cursor_pos;
static int cmd_length;
void history_init() {
	int result;
	int file_desc = open(HISTORY_FILE, O_RDONLY);
	total_history = 0;
	if (file_desc < 0) {
		// debugf("error: failed to open %s\n", HISTORY_FILE);
		return;
	}
	while (total_history < HISTORY_FILE_SIZE) {
		int char_pos = 0;
		char character;
		while (1) {
			if ((result = read(file_desc, &character, 1)) != 1) {
				if (result < 0) {
					debugf("read error in file %s: %d\n", HISTORY_FILE, result);
				}
				break;
			}
			if (character == '\r' || character == '\n') {
				break;
			}
			cmd_history[total_history][char_pos] = character;
			char_pos += 1;
		}
		if (result != 1) {
			break;
		}
		cmd_history[total_history][char_pos] = '\0';
		total_history += 1;
	}
	close(file_desc);
	return;
}

// 移动光标通用函数
static void move_cursor(char direction, int count) {
	if (count <= 0) return;
	switch(direction) {
		case 'L': printf("\e[%dD", count); break; // Left
		case 'R': printf("\e[%dC", count); break; // Right  
		case 'U': printf("\e[%dA", count); break; // Up
		case 'D': printf("\e[%dB", count); break; // Down
	}
}

static void clear_current_line() {
	printf("\e[K");
}

static void store_command(char* cmd_text) {
	int result;
	static char buffer[HISTORY_FILE_SIZE][MAX_COMMAND_LENGTH];
	int file_desc = open(HISTORY_FILE, O_RDONLY);
	int buffer_count = 0;
	if (file_desc >= 0) {
		while (buffer_count < HISTORY_FILE_SIZE) {
			int char_idx = 0;
			char ch;
			while (1) {
				if ((result = read(file_desc, &ch, 1)) != 1) {
					if (result < 0) {
						debugf("read error in file %s: %d\n", HISTORY_FILE, result);
					}	
					break;
				}
				if (ch == '\r' || ch == '\n') {
					break;
				}
				buffer[buffer_count][char_idx] = ch;
				char_idx += 1;
			}
			if (result != 1) {
				break;
			}
			buffer[buffer_count][char_idx] = '\0';
			buffer_count += 1;
		}
		close(file_desc);
	}
	file_desc = open(HISTORY_FILE, O_WRONLY | O_CREAT | O_TRUNC);
	if (file_desc < 0) {
		debugf("error: failed to open %s to save command.\n", HISTORY_FILE);
		return;
	}
	for (int i = 0; i < buffer_count; ++i) {
		if (i == 0 && buffer_count == HISTORY_FILE_SIZE) {
			continue;
		}
		if ((result = write(file_desc, buffer[i], strlen(buffer[i]))) < 0) {
			debugf("write error in saving command\n");
			return;
		}
		if ((result = write(file_desc, "\n", 1)) < 0) {
			debugf("write error in saving command\n");
			return;
		}
	}
	if ((result = write(file_desc, cmd_text, strlen(cmd_text))) < 0) {
		debugf("write error in saving command\n");
		return;
	}
	if ((result = write(file_desc, "\n", 1)) < 0) {
		debugf("write error in saving command\n");
		return;
	}
	close(file_desc);
}


static void refresh_display(char* cmd_text) {
	move_cursor('L', prev_cursor);
	clear_current_line();
	printf("%s", cmd_text);
	move_cursor('L', cmd_length - cursor_pos);
}

static void remove_char(char* cmd_text) {
	if (cursor_pos > 0) {
		cursor_pos -= 1;
		for (int i = cursor_pos; i < cmd_length; ++i) {
			cmd_text[i] = cmd_text[i + 1];
		}
		cmd_length -= 1;
		cmd_text[cmd_length] = '\0';
	}
	refresh_display(cmd_text);
}

static void handle_arrow_keys() {
	char key_code;
	int result;
	if ((result = read(0, &key_code, 1)) != 1) {
		if (result < 0) {
			debugf("read error: %d\n", result);
		}
		exit(1);
	}
	if (key_code != '[') {
		debugf("read error: invalid control key\n");
		exit(1);
	}
	if ((result = read(0, &key_code, 1)) != 1) {
		if (result < 0) {
			debugf("read error: %d\n", result);
		}
		exit(1);
	}
	switch (key_code) {
	case 'D': // move left
		if (cursor_pos > 0) {
			prev_cursor -= 1;
			cursor_pos -= 1;
		} else {
			move_cursor('R', 1);
		}
		break;
	case 'C': // move right
		if (cursor_pos < cmd_length) {
			prev_cursor += 1;
			cursor_pos += 1;
		} else {
			move_cursor('L', 1);
		}
		break;
	case 'A': // move up
		move_cursor('D', 1);
		if (active_cmd_idx > 0) {
			active_cmd_idx -= 1;
			cursor_pos = cmd_length = strlen(cmd_history[active_cmd_idx]);
			refresh_display(cmd_history[active_cmd_idx]);
		}
		break;
	case 'B': // move down
		if (active_cmd_idx < total_history) {
			active_cmd_idx += 1;
			cursor_pos = cmd_length = strlen(cmd_history[active_cmd_idx]);
			refresh_display(cmd_history[active_cmd_idx]);
		}
		break;
	default:
		break;
	}
}

// 光标移动和删除通用函数
static void edit_command_line(char* cmd_text, int edit_type) {
	switch(edit_type) {
		case 1: // cursor_to_beginning
			cursor_pos = 0;
			break;
		case 2: // cursor_to_end  
			cursor_pos = cmd_length;
			break;
		case 3: // delete_to_end
			move_cursor('U', 1);
			cmd_length = cursor_pos;
			cmd_text[cursor_pos] = '\0';
			break;
		case 4: // delete_to_begin
			for (int i = cursor_pos; i < cmd_length; ++i) {
				cmd_text[i - cursor_pos] = cmd_text[i];
			}
			cmd_length -= cursor_pos;
			cursor_pos = 0;
			cmd_text[cmd_length] = '\0';
			break;
		case 5: // delete_pre_word
			{
				int del_pos = cursor_pos;
				while (del_pos >= 0 && strchr(WHITESPACE, cmd_text[del_pos])) {
					--del_pos;
				}
				while (del_pos >= 0 && !strchr(WHITESPACE, cmd_text[del_pos])) {
					--del_pos;
				}
				++del_pos;
				for (int i = cursor_pos; i < cmd_length; ++i) {
					cmd_text[i - cursor_pos + del_pos] = cmd_text[i];
				}
				cmd_length -= cursor_pos - del_pos;
				cursor_pos = del_pos;
				cmd_text[cmd_length] = '\0';
			}
			break;
	}
	refresh_display(cmd_text);
}

static void add_character(char* cmd_text, char ch) {
	move_cursor('L', 1);
	for (int i = cmd_length - 1; i >= cursor_pos; --i) {
		cmd_text[i + 1] = cmd_text[i];
	}
	cmd_text[cursor_pos] = ch;
	cursor_pos += 1;
	cmd_length += 1;
	cmd_text[cmd_length] = '\0';
	refresh_display(cmd_text);
}

void read_command(char* command, int n) {
    int result;
    char input_char;

    active_cmd_idx = total_history;
    cmd_length = 0;
    prev_cursor = 0;
    cursor_pos = 0;
    cmd_history[active_cmd_idx][0] = '\0';

    while (cmd_length < n - 1) { // 保证有空间存放'\0'
        result = read(0, &input_char, 1);
        if (result != 1) {
            if (result < 0) debugf("read error: %d\n", result);
            exit(1);
        }
        prev_cursor = cursor_pos;
        switch (input_char) {
        case '\b':
        case '\x7f': // backspace
            remove_char(cmd_history[active_cmd_idx]);
            break;
        case '\x1b': // arrow key
            handle_arrow_keys();
            break;
        case '\x01': // Ctrl-A
            edit_command_line(cmd_history[active_cmd_idx], 1);
            break;
        case '\x05': // Ctrl-E
            edit_command_line(cmd_history[active_cmd_idx], 2);
            break;
        case '\x0b': // Ctrl-K
            edit_command_line(cmd_history[active_cmd_idx], 3);
            break;
        case '\x15': // Ctrl-U
            edit_command_line(cmd_history[active_cmd_idx], 4);
            break;
        case '\x17': // Ctrl-W
            edit_command_line(cmd_history[active_cmd_idx], 5);
            break;
        case '\r':
        case '\n':
            cmd_history[active_cmd_idx][cmd_length] = '\0';
            strncpy(command, cmd_history[active_cmd_idx], n - 1);
            command[n - 1] = '\0';
            store_command(command);
            if (total_history == HISTORY_FILE_SIZE) {
                memmove(cmd_history, cmd_history + 1, sizeof(cmd_history[0]) * (HISTORY_FILE_SIZE - 1));
                strncpy(cmd_history[HISTORY_FILE_SIZE - 1], command, MAX_COMMAND_LENGTH - 1);
                cmd_history[HISTORY_FILE_SIZE - 1][MAX_COMMAND_LENGTH - 1] = '\0';
            } else {
                strncpy(cmd_history[total_history], command, MAX_COMMAND_LENGTH - 1);
                cmd_history[total_history][MAX_COMMAND_LENGTH - 1] = '\0';
                total_history++;
            }
            return;
        default:
            if ((unsigned char)input_char >= 32 && (unsigned char)input_char < 127) { // 可打印字符
                add_character(cmd_history[active_cmd_idx], input_char);
            }
            break;
        }
    }
    debugf("line too long\n");
    while ((result = read(0, &input_char, 1)) == 1 && input_char != '\r' && input_char != '\n');
    command[0] = '\0';
}





static int execute_subprocess(char* cmd_buffer, char* output_buffer, int* position, int buffer_size) {
	int result;
	int pos = *position;
	int pipe_fds[2];
	char* cmd_ptr = cmd_buffer;

	if ((result = pipe(pipe_fds)) != 0) {
		debugf("error allocating pipe:%d\n", result);
		return 1;
	}
	if ((result = fork()) < 0) {
		debugf("error to fork: %d\n", result);
		return 1;
	}
	if (result == 0) {
		struct tempFd tempfd;
		savedup(&tempfd,1);
		dup(pipe_fds[1], 1);
		close(pipe_fds[1]);
		close(pipe_fds[0]);
		
        replace_sign(cmd_ptr);
		debugf("sub:%s\n",cmd_ptr);

		char single_buffer[MAX_COMMAND_LENGTH];
        int command_count = count_mulline(cmd_ptr);

        for(int i=0;i<=command_count;i++){
            devide_mulline(cmd_ptr, single_buffer, i);
            struct tempFd temp_fd;
            temp_fd.size=0;

            gettoken(single_buffer, 0);

            char *arg_vector[MAXARGS];
            int right_pipe = 0;
            int pipe_end = 0;
            int in_pipe = 0;
            int judge_flag = 0;
            int arg_count = parsecmd(arg_vector, &right_pipe,&temp_fd,&pipe_end,&in_pipe,&judge_flag);
            int return_code=0;

            if(in_pipe){
                runcmd(single_buffer,&temp_fd,&right_pipe,arg_count,arg_vector,pipe_end);
            }
            else{
                return_code=runcmd(single_buffer,&temp_fd,&right_pipe,arg_count,arg_vector,pipe_end);
            }
            
            while(judge_flag!=0){
                int should_execute=0;
                if(judge_flag==JUDGE_AND){
                    should_execute = (return_code==0);
                }
                if(judge_flag==JUDGE_OR){
                    should_execute = (return_code!=0);
                }
                right_pipe = 0;
                pipe_end = 0;
                in_pipe = 0;
                judge_flag = 0;  

                arg_count = parsecmd(arg_vector, &right_pipe,&temp_fd,&pipe_end,&in_pipe,&judge_flag);

                if(should_execute){
                    if(in_pipe){
                    runcmd(single_buffer,&temp_fd,&right_pipe,arg_count,arg_vector,pipe_end);
                    }
                    else{
                    return_code=runcmd(single_buffer,&temp_fd,&right_pipe,arg_count,arg_vector,pipe_end);
                    }
                }
            }
        }
		resetdup(&tempfd);
		exit(result);
		close_all();
	} else {
		close(pipe_fds[1]);
		int child_pid = result;
		result = readn(pipe_fds[0], output_buffer + pos, buffer_size - pos);
		close(pipe_fds[0]);
		wait(child_pid);
		if (result < 0) {
			debugf("error to read from child shell: %d\n", result);
			return 1;
		}
		pos += result;
		if (pos >= buffer_size) {
			debugf("line too long\n");
			return 1;
		}
	}

	(*position) = pos;
	return 0;
}


int replace_backquote(char* command) {
    char temp_buffer[1024];
    char sub_command[1024];
    int temp_len = 0;
    int sub_len = 0;
    int in_backquote = 0;
    int i = 0, result;

    for (; command[i] != '\0'; ++i) {
        if (command[i] == '`') {
            if (in_backquote) {
                sub_command[sub_len] = '\0';
                int pos = 0;
                char sub_output[1024] = {0};
                result = execute_subprocess(sub_command, sub_output, &pos, sizeof(sub_output));
                if (result != 0) return result;
                // 去除末尾换行
                while (pos > 0 && (sub_output[pos - 1] == '\n' || sub_output[pos - 1] == '\r')) {
                    sub_output[--pos] = '\0';
                }
                for (int j = 0; sub_output[j] && temp_len < (int)sizeof(temp_buffer) - 1; ++j) {
                    temp_buffer[temp_len++] = sub_output[j];
                }
                sub_len = 0;
            }
            in_backquote = !in_backquote;
        } else if (in_backquote) {
            if (sub_len < (int)sizeof(sub_command) - 1)
                sub_command[sub_len++] = command[i];
        } else {
            if (temp_len < (int)sizeof(temp_buffer) - 1)
                temp_buffer[temp_len++] = command[i];
        }
    }
    temp_buffer[temp_len] = '\0';
    strcpy(command, temp_buffer);
    return in_backquote ? 2 : 0;
}
int replace_sign(char* command){
	char *pointer=command;
	int comment_found=0;
	while(*pointer!='\0'){
		if(*pointer=='#'){
			comment_found = 1;
		}
		if(comment_found == 1){
		*pointer='\0';
		}
		pointer++;
	}
	return comment_found;
}
