/*
 * 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 <iostream>
#include <memory>
#include <vector>

#include "Asset.h"
#include "Cash.h"
#include "DividendStock.h"
#include "Stock.h"

using cse333::Asset;
using cse333::Cash;
using cse333::DividendStock;
using cse333::Stock;
using std::cout;
using std::endl;

int main(int argc, char** argv) {
  // ---- Dynamic dispatch through a base pointer (slides 18-20) ----------
  DividendStock div("VTI", 10, 2000.0, 250.0);
  div.PayDividend(30.0);

  Stock* s = &div;  // base pointer to a derived object
  // GetMarketValue is virtual, so this runs DividendStock's version even
  // though `s` is declared as a Stock*.
  cout << "Through Stock*: GetMarketValue = " << s->GetMarketValue() << endl;
  // GetProfit is inherited from Stock, but its internal call to
  // GetMarketValue() still dispatches to the derived version.
  cout << "Through Stock*: GetProfit      = " << s->GetProfit() << endl;

  // ---- Object slicing: assigning a derived object to a base VALUE ------
  // (slide 29).  A plain Stock has no room for the dividends_, so it is
  // dropped.
  Stock sliced = div;  // SLICED: Stock's copy of just the Stock part
  cout << "\nSliced to Stock: GetMarketValue = " << sliced.GetMarketValue()
       << "  (dividends dropped)" << endl;

  // ---- A heterogeneous portfolio needs pointers (slide 30) -------------
  // vector<Asset> would be impossible (Asset is abstract) and would slice
  // anyway.  Store unique_ptr<Asset> so the container owns and frees them
  // and no slicing happens.
  std::vector<std::unique_ptr<Asset>> portfolio;
  portfolio.push_back(std::make_unique<Stock>("AAPL", 5, 500.0, 190.0));
  portfolio.push_back(std::make_unique<DividendStock>("MSFT", 4, 1200.0, 400.0));
  portfolio.push_back(std::make_unique<Cash>(1000.0));

  double total = 0.0;
  cout << "\nPortfolio:" << endl;
  for (const auto& asset : portfolio) {
    // One call site, three different GetMarketValue() bodies chosen at
    // run time by the actual object type.
    cout << "  " << asset->name() << ": " << asset->GetMarketValue() << endl;
    total += asset->GetMarketValue();
  }
  cout << "Total market value = " << total << endl;

  return EXIT_SUCCESS;
}