/** @file */
#include "exec.h"
#include "disk.h"
#include "struct.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

const char *cmd_list[] = {"ls",  "touch", "df", "rm", "rmdir",
                          "cat", "echo",  "cd", 0};

int do_cd(disk *d, char *path) {
  char full_path[1024] = {0};

  format_path(full_path, path, 1024);

  char *path_tmp = strdup(full_path);
  int dir_index = 0;
  char *token = strtok(path_tmp, "/");

  while (token != NULL) {
    dir_index = find_dir_inode_by_name(token, dir_index, d);

    if (dir_index == -1 || d->inodes[dir_index].filetype != TYPE_DIRECTORY) {
      dprintf(STDERR_FILENO, "cd: invalid path: %s\n", token);
      free(path_tmp);
      return -1;
    }
    token = strtok(NULL, "/");
  }

  canonicalize_path(full_path);

  set_env_value("PWD", full_path);

  free(path_tmp);
  return 1;
}

int do_echo(char **args) {
  if (args[0] == NULL) {
    dprintf(STDOUT_FILENO, "\n");
    return 1;
  }

  char result[4096] = {0};
  int pos = 0;

  for (int i = 0; args[i] != NULL; i++) {
    char *word = args[i];

    for (int j = 0; word[j] != '\0'; j++) {
      if (word[j] == '$' && word[j + 1] != '\0') {
        j++;
        int start = j;

        while (word[j] != '\0' && (isalnum(word[j]) || word[j] == '_')) {
          j++;
        }

        int len = j - start;
        if (len > 0) {
          char key[64];
          strncpy(key, &word[start], len);
          key[len] = '\0';

          char *val = get_env_value(key);
          if (val != NULL) {
            int val_len = strlen(val);
            strcpy(&result[pos], val);
            pos += val_len;
          }
        }
        j--;
      } else {
        result[pos++] = word[j];
      }
    }

    if (args[i + 1] != NULL) {
      result[pos++] = ' ';
    }
  }

  result[pos] = '\0';
  dprintf(STDOUT_FILENO, "%s\n", result);
  return 1;
}

int exec_cmd_job(disk *d, char **args) {
  if (strcmp("ls", args[0]) == 0) {
    do_ls(d, args[1]);
  } else if (strcmp("mkdir", args[0]) == 0) {
    do_mkdir(d, args[1]);
    persist_on_disk(d);
  } else if (strcmp("touch", args[0]) == 0) {
    do_touch(d, args[1]);
    persist_on_disk(d);
  } else if (strcmp("df", args[0]) == 0) {
    do_df(d);
  } else if (strcmp("rm", args[0]) == 0) {
    do_rm(d, args[1]);
    persist_on_disk(d);
  } else if (strcmp("rmdir", args[0]) == 0) {
    do_rmdir(d, args[1]);
    persist_on_disk(d);
  } else if (strcmp("cat", args[0]) == 0) {
    do_cat(d, args[1]);
  } else {
    dprintf(STDERR_FILENO, "%s: command does not exist\n", args[0]);
    return 0;
  }
  return 1;
}

int spawn_proc(disk *d, int in, int out, command *cmd) {
  int pid;

  if ((pid = fork()) == 0) {
    signal(SIGINT, SIG_DFL);

    if (out != STDOUT_FILENO) {
      dup2(out, STDOUT_FILENO);
      close(out);
    }

    if (in != STDIN_FILENO) {
      dup2(in, STDIN_FILENO);
      close(in);
    }

    return exec_cmd_job(d, cmd->argv);
  }

  return pid;
}

int execute_cmd(disk *d, command **args) {

  // cas ou l'utilisateur fait CTRD+D
  if (args == NULL) {
    dprintf(STDOUT_FILENO, "\n");
    exit(EXIT_SUCCESS);
  }

  int args_len = 0;

  for (args_len = 0; args[args_len] != NULL; args_len++)
    ;

  int i;
  int in, p[2];
  in = 0;

  for (i = 0; i < args_len - 2; i++) {
    pipe(p);
    spawn_proc(d, in, p[1], args[i]);
    close(p[1]);
    in = p[0];
  }

  spawn_proc(d, in, STDOUT_FILENO, args[i]);

  if (in != 0) {
    close(in);
  }

  int status;
  while (waitpid(-1, &status, WUNTRACED) > 0)
    ;

  return status;
}