#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#define MAX_COMMANDS 7
#define MAX_ARGS 10
#define MAX_INPUT_LENGTH 100

void execute_command(char *command) {
    pid_t pid = fork();

    if (pid == -1) {
        perror("Error forking child process");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // Child process

        char *args[MAX_ARGS];
        int argc = 0;

        // Tokenize the command into arguments
        char *token = strtok(command, " ");
        while (token != NULL && argc < MAX_ARGS) {
            args[argc++] = token;
            token = strtok(NULL, " ");
        }
        args[argc] = NULL;

        // Execute the command
        if (execvp(args[0], args) == -1) {
            perror("Error executing command");
            exit(EXIT_FAILURE);
        }
    } else {
        // Parent process
        if (wait(NULL) == -1) {
            perror("Error waiting for child process");
            exit(EXIT_FAILURE);
        }
    }
}

void execute_piped_commands(char *commands[], int num_commands) {
    int pipes[num_commands - 1][2];
    int command_status[MAX_COMMANDS] = {0};

    // Create pipes for each command
    for (int i = 0; i < num_commands - 1; i++) {
        if (pipe(pipes[i]) == -1) {
            perror("Error creating pipe");
            exit(EXIT_FAILURE);
        }
    }

    // Fork child processes for each command
    for (int i = 0; i < num_commands; i++) {
        pid_t pid = fork();

        if (pid == -1) {
            perror("Error forking child process");
            exit(EXIT_FAILURE);
        } else if (pid == 0) {
            // Child process

            // Redirect input/output as necessary
            if (i == 0) {
                // First command, redirect output to pipe
                if (dup2(pipes[i][1], STDOUT_FILENO) == -1) {
                    perror("Error redirecting output");
                    exit(EXIT_FAILURE);
                }
                // Close unused read end of the pipe
                close(pipes[i][0]);
            } else if (i == num_commands - 1) {
                // Last command, redirect input from pipe
                if (dup2(pipes[i - 1][0], STDIN_FILENO) == -1) {
                    perror("Error redirecting input");
                    exit(EXIT_FAILURE);
                }
                // Close unused write end of the pipe
                close(pipes[i - 1][1]);
            } else {
                // Middle commands, redirect both input and output
                if (dup2(pipes[i - 1][0], STDIN_FILENO) == -1) {
                    perror("Error redirecting input");
                    exit(EXIT_FAILURE);
                }
                if (dup2(pipes[i][1], STDOUT_FILENO) == -1) {
                    perror("Error redirecting output");
                    exit(EXIT_FAILURE);
                }
                // Close unused ends of the pipes
                close(pipes[i - 1][1]);
                close(pipes[i][0]);
            }

            // Close all pipe ends
            for (int j = 0; j < num_commands - 1; j++) {
                close(pipes[j][0]);
                close(pipes[j][1]);
            }

            // Execute the command
            execute_command(commands[i]);
            exit(EXIT_SUCCESS);
        }
    }

    // Close all pipe ends in the parent process
    for (int i = 0; i < num_commands - 1; i++) {
        close(pipes[i][0]);
        close(pipes[i][1]);
    }

    // Wait for child processes to finish and collect their exit status
    for (int i = 0; i < num_commands; i++) {
        int status;
        if (wait(&status) == -1) {
            perror("Error waiting for child process");
            exit(EXIT_FAILURE);
        }
        command_status[i] = WEXITSTATUS(status);
    }

    // Determine the overall exit status based on the logical operators
    int overall_status = 0;
    for (int i = 0; i < num_commands; i++) {
        if (command_status[i] != 0 && commands[i][0] == '&') {
            overall_status = 1;
            break;
        }
        if (command_status[i] == 0 && commands[i][0] == '|') {
            overall_status = 1;
            break;
        }
    }

    // exit(overall_status);
}

void execute_command_with_redirection(char *command, char *filename, int mode) {
    int fd;

    // Open the file for redirection
    if (mode == 0) {
        fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    } else if (mode == 1) {
        fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0644);
    } else if (mode == 2) {
        fd = open(filename, O_RDONLY);
    }

    if (fd == -1) {
        perror("Error opening file");
        exit(EXIT_FAILURE);
    }

    // Fork a child process
    pid_t pid = fork();

    if (pid == -1) {
        perror("Error forking child process");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // Child process

        if (mode == 0 || mode == 1) {
            // Output redirection
            if (dup2(fd, STDOUT_FILENO) == -1) {
                perror("Error redirecting output");
                exit(EXIT_FAILURE);
            }
        } else if (mode == 2) {
            // Input redirection
            if (dup2(fd, STDIN_FILENO) == -1) {
                perror("Error redirecting input");
                exit(EXIT_FAILURE);
            }
        }

        // Close the file descriptor
        close(fd);

        // Tokenize the command into arguments
        char *args[MAX_ARGS];
        int argc = 0;

        char *token = strtok(command, " ");
        while (token != NULL && argc < MAX_ARGS) {
            args[argc++] = token;
            token = strtok(NULL, " ");
        }
        args[argc] = NULL;

        // Execute the command
        if (execvp(args[0], args) == -1) {
            perror("Error executing command");
            exit(EXIT_FAILURE);
        }
    }

    // Close the file descriptor in the parent process
    close(fd);

    // Wait for the child process to finish
    if (wait(NULL) == -1) {
        perror("Error waiting for child process");
        exit(EXIT_FAILURE);
    }
}

int main() {
    char input[MAX_INPUT_LENGTH];

    while (1) {
        printf("mshell$ ");
        fgets(input, sizeof(input), stdin);

        // Remove the newline character from the input
        input[strcspn(input, "\n")] = '\0';

        // Tokenize the input into commands
        char *commands[MAX_COMMANDS];
        int num_commands = 0;

        char *token = strtok(input, "|");
        while (token != NULL && num_commands < MAX_COMMANDS) {
            commands[num_commands++] = token;
            token = strtok(NULL, "|");
        }

        // Check if piping is required
        if (num_commands > 1) {
            execute_piped_commands(commands, num_commands);
            // Remove the exit statement here
        } else {
            // Tokenize the command into individual commands
            char *sequential_commands[MAX_COMMANDS];
            int num_sequential_commands = 0;

            token = strtok(commands[0], ";");
            while (token != NULL && num_sequential_commands < MAX_COMMANDS) {
                sequential_commands[num_sequential_commands++] = token;
                token = strtok(NULL, ";");
            }

            // Execute each command sequentially
            for (int i = 0; i < num_sequential_commands; i++) {
                char *command = sequential_commands[i];

                // Check for redirection operators
                char *output_redirect = strstr(command, ">>");
                char *input_redirect = strstr(command, "<");
                char *output_redirect_truncate = strstr(command, ">");

                if (output_redirect != NULL) {
                    *output_redirect = '\0';
                    char *filename = output_redirect + 2;
                    execute_command_with_redirection(command, filename, 1);
                } else if (input_redirect != NULL) {
                    *input_redirect = '\0';
                    char *filename = input_redirect + 1;
                    execute_command_with_redirection(command, filename, 2);
                } else if (output_redirect_truncate != NULL) {
                    *output_redirect_truncate = '\0';
                    char *filename = output_redirect_truncate + 1;
                    execute_command_with_redirection(command, filename, 0);
                } else {
                    execute_command(command);
                    // Remove the exit statement here
                }
            }
        }
    }

    return 0;
}

in the above code && and || condition is not working correctly