#include <set>
#include <algorithm>
#include <iostream>
#include <ctime>
#include <random>
#include "Currency.h"
#include "BankAccount.h"

std::default_random_engine generator;
std::uniform_real_distribution<double> distribution(-100, 500);

std::string random_string(size_t length) {
    auto randchar = []() -> char {
        const char charset[] =
                "0123456789"
                "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                "abcdefghijklmnopqrstuvwxyz";
        const size_t max_index = (sizeof(charset) - 1);
        return charset[rand() % max_index];
    };
    std::string str(length, 0);
    std::generate_n(str.begin(), length, randchar);
    return str;
}

std::string currency_to_string(CurrencyValue value) {
    if(value == CurrencyValue::USD) return "US Dollar";
    if(value == CurrencyValue::EUR) return "Euro";
    if(value == CurrencyValue::GPD) return "British Pound";
    return "Say what ?";
}

std::ostream &operator<<(std::ostream &os, Currency currency) {
    os << currency_to_string(currency.getValue());
    return os;
}

std::ostream &operator<<(std::ostream &os, Cash cash) {
    os << cash.getValue() << " " << cash.getCurrency() << ": " << cash.getSerial();
    return os;
}

std::ostream &operator<<(std::ostream &os, Money money) {
    os << money.getValue() << " " << money.getCurrency();
    return os;
}

std::ostream &operator<<(std::ostream &os, BankAccount bankAccount) {
    os << bankAccount.getName() << ": " << bankAccount.getMoney();
    return os;
}

Cash cashPrinter(double value, Currency currency) {
    return Cash(value, currency, random_string(5));
}


int main(int argc, char **argv) {
    std::set<BankAccount*> accounts;

    accounts.insert(new BankAccount("Max"));
    accounts.insert(new BankAccount("Max"));
    accounts.insert(new BankAccount("Marius"));
    accounts.insert(new BankAccount("Test"));


    std::for_each(accounts.begin(), accounts.end(), [] (BankAccount* bankAccount){
        double rnd = distribution(generator);
        Cash cash = cashPrinter(rnd, CurrencyValue::USD);
        std::cout << cash << std::endl;
        bankAccount->add(cash);
        std::cout << *bankAccount << std::endl;
    });
}