/*
 * Copyright ©2026 Soham Pardeshi. All rights reserved.
 * Permission is hereby granted to students registered for University of
 * Washington CSE 333 for use solely during Summer Quarter 2026 for
 * purposes of the course. No other use, copying, distribution, or
 * modification is permitted without prior written consent. Copyrights
 * for third-party components of this work must be honored. Instructors
 * interested in reusing these course materials should contact the author.
 */

#include <cstdlib>   // for EXIT_SUCCESS, EXIT_FAILURE
#include <iostream>  // for cout, cerr, endl
#include <string>    // for string

#include "dirutil.h"
#include "fileutil.h"

using std::cerr;
using std::cout;
using std::endl;
using std::string;

#define NUM_BYTES_TO_PRINT 256
#define HEADER_SIZE 50
/*
 * This program:
 * - Takes the name of a directory as its single command-line argument.
 * - Prints "Contents of <dir>:", then, for each entry in the directory,
 *   prints the entry's name and size, an "=" divider line, and up to
 *   NUM_BYTES_TO_PRINT bytes of its contents, using the dirutil and fileutil
 *   modules.
 * - On any error (wrong usage, an unopenable directory, or an unreadable
 *   file), prints a useful message to std::cerr and exits with
 *   EXIT_FAILURE.
 */
int main(int argc, char** argv) {
  // This program takes exactly one argument: the directory to list.
  if (argc != 2) {
    cerr << "Usage: " << argv[0] << " <directory>" << endl;
    return EXIT_FAILURE;
  }
  string dirname = argv[1];

  // Open the directory for iteration over its entries.
  DirIter* iter = DirIter_Allocate(dirname.c_str());
  if (iter == nullptr) {
    cerr << "Could not open directory: " << dirname << endl;
    return EXIT_FAILURE;
  }

  cout << "Contents of " << dirname << ":" << endl;

  // Walk every entry, printing its size and the first NUM_BYTES_TO_PRINT bytes
  // of its contents.
  char buf[NUM_BYTES_TO_PRINT];
  while (DirIter_IsValid(iter)) {
    const char* name = DirIter_Get(iter);

    // Build the full path to the entry: "<dirname>/<name>".
    string path = dirname;
    if (!path.empty() && path.back() != '/') {
      path += '/';
    }
    path += name;

    ssize_t size = FileSize(path.c_str());
    // Read the whole buffer in one chunk (chunk_size == buflen).
    ssize_t bytes_read = ReadFile(path.c_str(), buf, NUM_BYTES_TO_PRINT,
                                  NUM_BYTES_TO_PRINT);
    if (size < 0 || bytes_read < 0) {
      cerr << "Could not read file: " << path << endl;
      DirIter_Free(iter);
      return EXIT_FAILURE;
    }

    // Blank line, then "<name> (<size> bytes):", then the raw contents.
    cout << endl
         << name << " (" << size << " bytes):" << endl;
    cout << std::string(HEADER_SIZE, '=') << endl;
    cout.write(buf, bytes_read);
    cout << endl;

    DirIter_Next(iter);
  }

  DirIter_Free(iter);
  return EXIT_SUCCESS;
}