#include <iomanip>
#include <iostream>
#include <vector>

using namespace std;

class BankAccount
{
public:
   /**
      Konstruuje konto bankowe z zerowym saldem.
   */
   BankAccount();

   /**
      Dokonuje wpłaty na konto.
      @param amount kwota wpłaty
   */
   virtual void deposit(double amount);

   /**
      Dokonuje wypłaty z konta lub nalicza karę
      przy braku dostępnych środków.
      @param amount kwota wypłaty
   */
   virtual void withdraw(double amount);

   /**
      Wykonuje przetwarzanie na koniec miesiąca
      właściwe dla danego konta.
    */
   virtual void month_end();

   /**
      Pobiera bieżące saldo konta bankowego.
      @return bieżące saldo
   */
   double get_balance() const;
private:
   double balance;
};

BankAccount::BankAccount()
{
   balance = 0;
}

void BankAccount::deposit(double amount)
{
   balance = balance + amount;
}

void BankAccount::withdraw(double amount)
{
   balance = balance - amount;
}

void BankAccount::month_end()
{
}

double BankAccount::get_balance() const
{
   return balance;
}

//....................................................................

class SavingsAccount : public BankAccount
{
public:
   /**
      Konstruuje konto oszczędnościowe z zerowym saldem.
   */
   SavingsAccount();

   /**
      Ustawia stopę zysku na koncie.
      @param rate miesięczna stopa zysku w procentach
   */
   void set_interest_rate(double rate);
   virtual void withdraw(double amount);
   virtual void month_end();
private:
   double interest_rate;
   double min_balance;
};

SavingsAccount::SavingsAccount()
{
   interest_rate = 0;
   min_balance = 0;
}

void SavingsAccount::set_interest_rate(double rate)
{
   interest_rate = rate;
}

void SavingsAccount::withdraw(double amount)
{
   BankAccount::withdraw(amount);
   double balance = get_balance();
   if (balance < min_balance)
   {
      min_balance = balance;
   }
}

void SavingsAccount::month_end()
{
   double interest = min_balance * interest_rate / 100;
   deposit(interest);
   min_balance = get_balance();
}

//....................................................................

class CheckingAccount : public BankAccount
{
public:
   /**
      Konstruuje konto rozliczeniowe z zerowym saldem.
   */
   CheckingAccount();
   virtual void withdraw(double amount);
   virtual void month_end();
private:
   int withdrawals;
};

CheckingAccount::CheckingAccount()
{
   withdrawals = 0;
}

void CheckingAccount::withdraw(double amount)
{
   const int FREE_WITHDRAWALS = 3;
   const int WITHDRAWAL_FEE = 1;

   BankAccount::withdraw(amount);
   withdrawals++;
   if (withdrawals > FREE_WITHDRAWALS)
   {
      BankAccount::withdraw(WITHDRAWAL_FEE);
   }
}

void CheckingAccount::month_end()
{
   withdrawals = 0;
}

//....................................................................

int main()
{
   cout << fixed << setprecision(2);

   // Utwórz konta.
   const int ACCOUNTS_SIZE = 10;
   BankAccount* accounts[ACCOUNTS_SIZE];
   for (int i = 0; i < ACCOUNTS_SIZE / 2; i++)
   {
      accounts[i] = new CheckingAccount;
   }
   for (int i = ACCOUNTS_SIZE / 2; i < ACCOUNTS_SIZE; i++)
   {
      SavingsAccount* account = new SavingsAccount;
      account->set_interest_rate(0.75);
      accounts[i] = account;
   }

   // Wykonuj polecenia.
   bool more = true;
   while (more)
   {
      cout << "D)epozyt W)ypłata K)oniec miesiąca Z)akończ: ";
      string input;
      cin >> input;
      if (input == "D" || input == "W") // Depozyt lub wypłata
      {
         cout << "Wprowadź numer konta i kwotę:  ";
         int num;
         double amount;
         cin >> num >> amount;

         if (input == "D") { accounts[num]->deposit(amount); }
         else { accounts[num]->withdraw(amount); }

         cout << "Stan konta: " << accounts[num]->get_balance() << endl;
      }
      else if (input == "K") // Przetwarzanie na koniec miesiąca
      {
         for (int n = 0; n < ACCOUNTS_SIZE; n++)
         {
            accounts[n]->month_end();
            cout << n << " " << accounts[n]->get_balance() << endl;
         }
      }
      else if (input == "Z")
      {
         more = false;
      }
   }

   return 0;
}

