/*
 * 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 "LinkedIntList.h"

#include <cstdlib>    // for EXIT_SUCCESS, EXIT_FAILURE
#include <iostream>   // for cout, cerr, endl
#include <memory>     // for unique_ptr, make_unique

#include "IntList.h"

using intlist333::IntList;
using intlist333::LinkedIntList;
using std::cerr;
using std::cout;
using std::endl;

namespace {

constexpr int kOne = 1;
constexpr int kTwo = 2;
constexpr int kThree = 3;
constexpr int kFour = 4;
constexpr int kFive = 5;

template <typename T>
void CheckEquals(T expected, T actual) {
  if (expected != actual) {
    cerr << "ERROR" << endl;
    cerr << "expected value: " << expected << endl;
    cerr << "actual value: " << actual << endl;
    exit(EXIT_FAILURE);
  }
}

}  // namespace

int main() {
  std::unique_ptr<IntList> list = std::make_unique<LinkedIntList>();
  int output;

  // Verify the empty list case.
  CheckEquals(0, list->num_elements());
  CheckEquals(false, list->Pop(&output));
  CheckEquals(false, list->Slice(&output));

  // Insert an element.
  list->Push(kOne);
  CheckEquals(1, list->num_elements());

  // Pop the element from the front.
  CheckEquals(true, list->Pop(&output));
  CheckEquals(kOne, output);

  // Push another element and remove it from the back.
  list->Push(kTwo);
  CheckEquals(1, list->num_elements());
  CheckEquals(true, list->Slice(&output));
  CheckEquals(kTwo, output);
  CheckEquals(0, list->num_elements());

  // Verify that removals from an empty list fail.
  CheckEquals(false, list->Pop(&output));
  CheckEquals(false, list->Slice(&output));

  // Insert five elements.
  list->Push(kThree);
  list->Push(kTwo);
  list->Push(kOne);
  list->Append(kFour);
  list->Append(kFive);
  CheckEquals(5, list->num_elements());

  // Remove the back element.
  CheckEquals(true, list->Slice(&output));
  CheckEquals(kFive, output);
  CheckEquals(4, list->num_elements());

  // Remove the front element.
  CheckEquals(true, list->Pop(&output));
  CheckEquals(kOne, output);
  CheckEquals(3, list->num_elements());

  cout << "All tests passed! Be sure to run under valgrind!" << endl;

  return EXIT_SUCCESS;
}