#pragma once

#include <string>
#include <vector>
#include <map>
#include <cstdint>

//////////////////////////////////////////////////////////////////////////////
// Color codes for output formatting

enum ColorTag_t {
    // Styles
    S_BOLD, SN_BOLD,
    S_DIM, SN_DIM,
    S_ITALIC, NS_ITALIC,
    S_ULINE, NS_ULINE,
    S_BLINK, NS_BLINK,

    // Colors
    FG_BLACK, BG_BLACK,
    FG_RED, BG_RED,
    FG_GREEN, BG_GREEN,
    FG_YELLOW, BG_YELLOW,
    FG_BLUE, BG_BLUE,
    FG_MAGENTA, BG_MAGENTA,
    FG_CYAN, BG_CYAN,
    FG_WHITE, BG_WHITE,
    FG_DEFAULT, BG_DEFAULT,
    FG_RESET, BG_RESET,
    NULLSTR
};

/**
 * @brief Get ansi color code corresponding to a tag
 * 
 * @return std::string tag
 */
char* ansicode(ColorTag_t tag);


//////////////////////////////////////////////////////////////////////////////
// Throwing messages (error, warning, success)

/**
 * @brief Throws error generated in the std::cerr stream
 * 
 * @param er_code error code 
 * @param message error message
 * @param exit flag that tells weather to exit immediately
 */
void throwError(std::string er_code, std::string message, bool Exit = false);


/**
 * @brief Throws warning generated by assembler in the std::cerr stream
 * 
 * @param wr_code warning code 
 * @param message Warning message
 */
void throwWarning(std::string wr_code, std::string message);


/**
 * @brief Displays a success message
 * 
 * @param message Success message
 */
void throwSuccessMessage(std::string message, bool Exit = false);


//////////////////////////////////////////////////////////////////////////////
// String stripping utility functions
// see: https://www.techiedelight.com/trim-string-cpp-remove-leading-trailing-spaces/#:~:text=We%20can%20use%20combination%20of,functions%20to%20trim%20the%20string.

const std::string WHITESPACE = " \n\r\t\f\v";


/**
 * @brief removes preceeding whitespaces in a string
 * 
 * @param s string
 * @return std::string 
 */
std::string lStrip(const std::string& s);


/**
 * @brief removes succeeding whitespaces in a string
 * 
 * @param s string
 * @return std::string 
 */
std::string rStrip(const std::string& s);


/**
 * @brief removes preceding & succeeding whitespaces in a string
 * 
 * @param s string
 * @return std::string 
 */
std::string strip(const std::string& s);

/**
 * @brief trims string to specified length, inserts ' ..' suffix if len exceeds
 * 
 * @param str input string
 * @param len desired length
 * @return trimmed string
*/
std::string trimstr(std::string str, size_t len);

//////////////////////////////////////////////////////////////////////////////
// String Tokenizing

/**
 * @brief splits a string accordint to delimiter 
 * 
 * @param txt input string
 * @param strs vector of strings parts
 * @param ch delimiter
 * @return size_t 
 */
size_t tokenize(const std::string &txt, std::vector<std::string> &strs, char ch);

//////////////////////////////////////////////////////////////////////////////
// File I/O

/**
 * @brief Resolves environment variable in path specified using ${VAR} syntax
 * 
 * @param path input path
 * @return std::string resolved oath
 */
std::string resolve_envvar_in_path(std::string path);


/**
 * @brief reads a binary file
 * 
 * @param memfile filepath
 * @return std::vector<char> contents
 */
std::vector<char> fReadBin(std::string memfile);


/**
 * @brief Reads a file and returns its contents
 * 
 * @param filepath Filepath
 * @return Vector of strings containing file contents
 */
std::vector<std::string> fRead (std::string filepath);


/**
 * @brief Write to a file
 * 
 * @param filepath Filepath
 */
void fWrite (std::vector<std::string> data, std::string filepath);


//////////////////////////////////////////////////////////////////////////////
// Misc

/**
 * @brief Get the Stdout From shell Command
 * 
 * @param cmd shell command to execute
 * @param get_output if true, returns stdout, else moves on(even if command isn't still complete)
 * @return std::string command output
 */
std::string GetStdoutFromCommand(std::string cmd, bool get_output);


struct DisassembledLine
{
    uint32_t instr;
    std::string disassembly;
};


/**
 * @brief Get the Disassembly of input file using riscv objdump
 * 
 * @param dis std::map<uint32_t, std::string> map of disassembly
 * @param filename input filename
 */
void getDisassembly(std::map<uint32_t, DisassembledLine> *dis, std::string filename);