﻿#include <iostream>
#include <cmath>

using namespace std;

// funkcja wyswietlajaca czołówkę
void czolowka();
// funkcja wyświetlajaca menu
void wyswietlMenu();
// funkcja pobierająca liczbę od użytkownika
// zwraca wskaźnik na typ double
double* pobierzLiczbe(string nazwa);
// funkcja ustawiajaca kolor czcionki oraz tła
void kolorCzcionkiOrazTła();
// funkcja pobierająca liczby i oblicząjaca wynik
void obliczenia();


int main()
{
    // wyświetlamy czołówkę programu
    czolowka();

    // ustawiamy kolor czcionki oraz tła za pomocą polecenia systemowego
    // system("color 1A");
    kolorCzcionkiOrazTła();

    // głowna funkcja pobierająca liczby i oblicząjaca wynik
    obliczenia();   

    return 0;
}

void czolowka()
{
    // wyświetlamy czołówkę programu
    // (jest nieco uboga, możesz coś dodać :) 
    cout << "Kalkulator\n\n";
}

void wyswietlMenu()
{
    // wyświetlamy menu kalkulatora
    cout << "\nwybierz działanie\n";

    cout << "\n[1] dodawanie\n";
    cout << "[2] odejmowanie\n";
    cout << "[3] mnozenie\n";
    cout << "[4] dzielenie\n";
    cout << "[5] potegowanie\n";
}

double* pobierzLiczbe(string nazwa) {
   // wskaźnik, który będzie adresem pobranej liczby
   // inicjalizujemy wskazywaną liczbę zerem 
   double* x = new double(0);
   // komunikat
   cout << "\nPodaj " << nazwa << " liczbe\n";
   // pobieramy liczbę
   // w przypadku podania nieprawidłowego typu 
   // (w naszym przypadku innego niż double)
   // wyrażenie cin >> x zwraca false
   // oraz zostaje ustawiony failbit (jeden ze stanów strumienia) 
   // wtedy wchodzimy w pętlę while
   while (!(cin >> *x)) {
        // komunikat 
        cout << "nie podsałeś liczby\n";
        cout << "\nPodaj " << nazwa << " liczbe\n";
        // zerujemy stan strumienia (m.in failbit)
        cin.clear();
        // usuwamy to co zostało wczytane do strumienia
        // (czyli błedne znaki)
        // pierwszy parametr - ilość znaków do usuniecia (w naszym przypadku max)
        // drugi parametr - usuwane są znaki do znaku nowego wiersza
        // (jeśli taki sie pojawi, jeśli nie usuwa max znaków)
        cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }

    // funkcja zwraca wskażnik na pobraną liczbę
    return x;
}

void kolorCzcionkiOrazTła()
{
    
    // wyświetlamy menu zmiany koloru czcionki
    cout << "\nwybierz kolor czcionki\n";

    cout << "\n[8] szary\n";
    cout << "[9] jasnoniebieski\n";
    cout << "[A] jasnozielony\n";
    cout << "[B] jasnoblekitny\n";
    cout << "[C] jasnoczerwony\n";

    // zmienna na kolor czcionki
    string kolorCzcionki = "";

    // pobieramy kolor czcionki
    // (wilkość liter nie ma znaczenia)
    cin >> kolorCzcionki;

    // wyświetlamy menu zmiany koloru tła
    cout << "\nwybierz kolor tła\n";

    cout << "\n[0] czarne\n";
    cout << "[1] niebieske\n";
    cout << "[2] zielone\n";
    cout << "[3] blekitne\n";
    cout << "[4] czerwone\n";

    // zmienna na kolor tła
    string kolorTla = "";

    // pobieramy kolor tła
    cin >> kolorTla;

    // konkatenacja(sklejanie) stringów w celu uzyskania polecenia
    // systemowego zmiany koloru czcionki i tła
    string kolor = "color " + kolorTla + kolorCzcionki;

    // wywołujemy polecenie systemowe zmiany koloru
    // czcionki oraz tła,
    // funkcja system() przyjmuje jako parametr c-string
    // dlatego należy zamienić zmienną kolor typu string na c-napis
    // robi się to za pomoca metody c_str() obiektu kolor
    system(kolor.c_str());
}

void obliczenia()
{
    // wskaźniki na liczby
    double* a = nullptr;
    double* b = nullptr;

    // wskaźnik na wynik obliczeń
    // inicjalizujemy liczbę wskazywaną przez wsakżnik na zero
    double* wynik = new double(0);

    // zmienna na wybrane przez uzytkownika menu
    short menu = 0;

    // flaga wyjścia z programu
    char wyjscie = 'w';

    // pętla obliczeniowa
    // petla zakończy sie jeśli zmienna wyjście 
    // będzie miała wartość 't' 
    // (na końcu petli pytamy czy uzytkownik chce opuścić 
    // program, jeśli tak to ma wybrać 't' czyli tak) 
    while (wyjscie != 't') {
      
        // pobieramy liczby
        a = pobierzLiczbe("pierwsza");
        b = pobierzLiczbe("druga"); 

        // wyswietlamy menu
        wyswietlMenu();

        // pobieramy wybór uzytkownika
        cin >> menu;

        // instrukcja wyboru działania
        // wyświetlamy też wynik obliczeń
        switch (menu) {
        // jeśli użytkownik wybrał 1 czyli dodawanie
        // obliczamy i wypisujemy wynik
        case 1:
            *wynik = *a + *b;
            cout << "Wynik: " << *wynik;
            break;
        case 2:
            *wynik = *a - *b;
            cout << "Wynik: " << *wynik;
            break;
        case 3:
            *wynik = *a * *b;
            cout << "Wynik: " << *wynik;
            break;
        // jeśli użytkownik wybrał 4 czyli dzielenie
        // musimy być czujni, bo nie dzieli sie przez zero 
        case 4:
            if (*b != 0) {
                *wynik = *a / *b;
                cout << "Wynik: " << *wynik;
            }
            // zabezpieczenie przed dzieleniem przez zero
            else {
                cout << "Nie dzielimy przez zero";
                // dopóki dzielnik (druga liczba) będzie zerem 
                // użytkownik ma ją podać
                while (*b == 0) {
                    cout << "\nPodaj druga liczbe\n";
                    cin >> *b;
                }
                *wynik = *a / *b;
                cout << "Wynik: " << *wynik;
            }
            break;
        case 5:
            *wynik = pow(*a, *b);
            cout << "Wynik: " << *wynik;
            break;
        default:
            cout << "niewlasciwe dzialanie\n";
        }

        // zapytanie o wyjście z programu
        cout << "\nwyjscie: t/n" << endl;
        // pobieramy wybór użytkownika co do dalszego ciagu działania
        // kalkulatora
        // jeśli użytkownik nacisnie znak 't'
        // wyjdziemy z petli obliczeniowej progarmu while
        cin >> wyjscie;

    }
    
    // usuwamy zmienne na stercie
    delete a;
    delete b;
    delete wynik;
    a = nullptr;
    b = nullptr;
    wynik = nullptr;
}
