/**
 * File: stsh-parse.h
 * -----------------
 * This file defines the `pipeline` and `command` types that help parse a
 * user-entered shell input line into tokens and extract out the arguments
 * and input/output redirection files.
 */

#pragma once
#include <vector>
#include <string>
#include <iostream>

const size_t kMaxCommandLength = 32;
const size_t kMaxArguments = 32;

/**
 * A `command` represents a single command entered by the user that could be
 * part of a multi-command pipeline.  For instance, "wc -l" is a command, 
 * as is "./stsh" or "ls -a -l".  The string is split into parts; the name
 * of the program being run is stored as a null-terminated C string in 
 * the `command` field. The rest of the arguments (if any) are stored in 
 * an array of C strings called `tokens`, which ends with a NULL pointer.  
 * The `argv` array combines both of these - it is an array of C strings 
 * where the first element is the program name, and the remaining elements 
 * are the arguments, followed by a NULL pointer.  
 * This is useful to call execvp.  
 * 
 * As an example, if the command is "ls -a -l", `command` would be "ls", 
 * tokens would be {"-a", "-l", NULL},
 * and argv would be {"ls", "-a", "-l", NULL}.
 */
struct command {
    char command[kMaxCommandLength + 1];
    char *tokens[kMaxArguments + 1];
    char *argv[kMaxArguments + 2];
};

/**
 * A pipeline represents one line entered by the user, and is a list of
 * commands, possibly with input redirection and/or output redirection. 
 * Commands are separated by the pipe "|" character.  For example, the line
 * "cat file.txt" is just one command, but the line 
 * "cat file.txt | wc -l" is two commands.  A pipeline will store each command
 * in the vector `commands`.
 * 
 * If the line redirects the input of the first command or the output of the
 * last command, the `input` or `output` fields, respectively, will contain
 * the name of the file specified for redirection, or will be the empty string
 * otherwise.  For example, with the line
 * 
 * "grep void < stsh.cc | wc -l > output.txt"
 * 
 * the pipeline would consist of two commands: "grep void" and "wc -l".   The
 * pipeline's `input` would be "stsh.cc" and `output` would be "output.txt". 
 */
struct pipeline {
    std::string input;
    std::string output;
    std::vector<command> commands;
    bool background;

  /* Further implementation details follow - you can ignore the lines below */

/**
 * Accepts a command line and parses it to construct the pipeline.
 * The command line is parsed according to the following rules:
 *
 * The input is taken to represent either a single command, or a list of
 * commands all separated by the '|' character.
 * 
 * Each command is parsed as a list of tokens that are delimited by white space
 * except where double quotes indicate the whitespace is significant.
 * So the line:
 *
 *   ls -a my_dir
 *
 * is parsed as the 3 tokens "ls", "-a", and "my_dir"
 * 
 * The line:
 *
 *   echo "This string is a single token"
 * 
 * is parsed, unsurprisingly, as 2 tokens.
 *
 * For each command, the first token is taken to be the name of the command,
 * and the following tokens are the arguments.  The first token is placed in the
 * command field of a struct command, and the remaining tokens are laid down
 * in the tokens array field.
 *
 * The first command in the list (or the only command if no pipes are found)
 * also allows for input redirection of the form "< input" where input is the
 * name of a file containing input. This option can come before or after the
 * command.
 *
 * Similarly the last command in the list (or the only command) allows for
 * output redirection by specifying an option of the form "> output" where
 * output is the name of a file to be created that will hold the results of the
 * final command.
 *
 * Note that in the case of a single command, the one command can have both
 * input and output redirection, and those options can be specified in any
 * order. That is: "< input" , "> output", and  "command [args...]" can be
 * written in any order.
 */
    pipeline(const std::string& str);

/**
 * It frees the dynamically allocated char *s containing the argument lists.
 */
    ~pipeline();

    pipeline(const pipeline& original) = delete;
    const pipeline& operator=(const pipeline& rhs) const = delete;
};

std::ostream& operator<<(std::ostream& os, const pipeline& p);
