#include <iostream> // подключение библиотеки ввода-вывода
#include <cmath> // подключение библиотеки для проведения математических операций

using namespace std; // подключение стандартного пространства имён

class Triangle{ // класс Треугольник

    float length[3]; // массив, хранящий стороны треугольника

    static int total_quantity; // статическая переменная, хранящая общее возможное количество объектов класса

    public:

    static int get_total_quantity(){ return total_quantity; } // возвращение значения статической переменной (статического поля) - геттер

    static void set_total_quantity(int _new_total_quantity){ total_quantity = _new_total_quantity; } // изменение значения статической переменной - сеттер

    Triangle(){ // конструктор без параметров
        cout << "\n\t\t\t\t\t\t\t\tConstructor " << this << " initialized.\n"; // вывод информации о инициализации конструктора
    }

    Triangle(float _first_length, float _second_length, float _third_length){ // конструктор с параметрами
        cout << "\n\t\t\t\t\t\t\t\tConstructor " << this << " initialized.\n"; // вывод информации о инициализации конструктора
        // присваивание сторонам треугольника значений, введённых пользователем
        this->length[0] = _first_length; this->length[1] = _second_length; this->length[2] = _third_length;
    }
/*
    Triangle(float _first_length = 1, float _second_length = 1, float _third_length = 1){ // конструктор с параметрами по умолчанию
        cout << "\n\t\t\t\t\t\t\t\tConstructor " << this << " initialized.\n"; // вывод информации о инициализации конструктора
        // присваивание сторонам треугольника значений, введённых пользователем
        this->length[0] = _first_length; this->length[1] = _second_length; this->length[2] = _third_length;
    }
*/
    ~Triangle(){ // деструктор
        cout << "\n\t\t\t\t\t\t\t\tDestructor " << this << " initialized.\n"; // вывод информации о инициализации деструктора
    }

    void set_triangle_lengths(float _first_length, float _second_length, float _third_length){
        // присваивание сторонам треугольника значений, введённых пользователем
        this->length[0] = _first_length; this->length[1] = _second_length; this->length[2] = _third_length;
    }

    bool is_equilteral(){ // проверка на равносторонность
        return (this->length[0] == this->length[1] && this->length[1] == this->length[2] && this->length[0] == this->length[2]);
    }

    float get_square(){ // вычисление и возвращение площади равностороннего треугольника по формуле (sqrt(3)/4 * lenght^2)
        return ((sqrt(3)/4) * pow(this->length[0], 2));
    }

    bool operator == (Triangle& triangle){ // проверка на равносторонность через перегрузку оператора сравнения
        return triangle.is_equilteral();
    }
};

ostream& operator<< (ostream& out, Triangle& triangle){ //перегрузка оператора вывода
    return out << "Square: " << triangle.get_square(); // вывод значения площади треугольника
}

void check_equilteral(Triangle *triangles[], int triangles_count){ // функция проверки треугольников на равносторонность
    for (int i = 0; i < triangles_count; i++){ // цикл на прохождение треугольников
        // проверка осуществляется через перегрузку оператора сравнения, в который передаётся объект класса треугольник
        // и в переданном объекте вызывается функция проверки на равносторонность
        // соответственно, если объект равен сам себе, то треугольник равносторонний
        if ((*triangles[i]) == (*triangles[i])){ // если треугольник равносторонний
            cout << i+1 << " triangle is equilteral. " << (*triangles[i]); // вывод номера и площади текущего треугольника через перегрузку оператора вывода
        } 
    }
}

enum UserChoice { // список возможных выборов пользователя
    DEFAULT = 1, // конструктор по умолчанию (без параметров)
    WITH_PARAMETERS = 2, // конструктор с параметрами
    STATIC_EXAMPLE = 3 // использование статического метода и конструктор без параметров
};

int Triangle::total_quantity = 5; // присваивание значения статической переменной класса

int main(){
    char change_static_value; // изменение значения статической переменной класса
    int choice; // выбор типа конструктора (без параметров, с параметрами, использование статической переменной)
    int triangles_count; // переменная, хранящая количество треугольников
    // ввод количества треугольников
    cout << "Input triangles count: "; cin >> triangles_count;
    // если количество < 1, то просиходит завершение программу
    if (triangles_count < 1){
        cout << "Triangles count can't be less than 1.\n";
        return 0;
    }
    // вывод возможных вариантов для инициализации объектов
    cout << "\nPlease, choose constructor's type:" << "\n";
    cout << "1. Default constructor (without parameters)." << "\n";
    cout << "2. Constructor with parameters." << "\n";
    cout << "3. Example static point." << "\n";
    // ввод пользователя
    cin >> choice;

    switch (choice)
    {
    case UserChoice::DEFAULT:{ // конструктор без параметров
        Triangle* triangles[triangles_count]; // указатель на массив с объектами класса Triangle

        for (int i = 0; i < triangles_count; i++){ // цикл на ввод треугольников
            float length[3]; // стороны треугольника
            cout << "\tInput " << i+1 << " triangle\n";

            for (int j = 0; j < 3; j++){ // цикл на ввод сторон текущего треугольника
                cout << "\t\t" << j+1 << " side: "; cin >> length[j];
            }

            triangles[i] = new Triangle(); // создание нового объекта класса Triangle через динамическое выделение памяти
            (*triangles[i]).set_triangle_lengths(length[0], length[1], length[2]); // передача введённых сторон в текущий треугольник
        }

        check_equilteral(triangles, triangles_count); // проверка треугольников на равносторонность

        for (int i = 0; i < triangles_count; i++) delete triangles[i]; // очистка памяти от динамического массива объектов класса Triangle

        break;
    }
    case UserChoice::WITH_PARAMETERS:{ // конструктор с параметрами
        Triangle* triangles[triangles_count]; // указатель на массив с объектами класса Triangle

        for (int i = 0; i < triangles_count; i++){ // цикл на ввод треугольников
            float length[3]; // стороны треугольника
            cout << "\tInput " << i+1 << " triangle\n";

            for (int j = 0; j < 3; j++){ // цикл на ввод сторон текущего треугольника
                cout << "\t\t" << j+1 << " side: "; cin >> length[j];
            }

            // создание нового объекта класса Triangle через динамическое выделение памяти и передача введённых сторон в текущий треугольник
            triangles[i] = new Triangle(length[0], length[1], length[2]); 
        }

        check_equilteral(triangles, triangles_count); // проверка треугольников на равносторонность

        for (int i = 0; i < triangles_count; i++) delete triangles[i]; // очистка памяти от динамического массива объектов класса Triangle

        break;
    }
    case UserChoice::STATIC_EXAMPLE:{ // использование статической переменной и конструктора с параметрами
        cout << "Total possible quantity of triangles: " << Triangle::get_total_quantity() << endl; // вывод макисмально возможного количества треугольников
        cout << "Do you want to change this value? y/n "; cin >> change_static_value; // изменение значения статической переменной 

        if (change_static_value == 'y') { // если пользователь хочет изменить значение 
            int new_total_quantity; // объявление новой переменной
            cout << "Input new total possible quantity of triangles: "; cin >> new_total_quantity; // ввод значения
            Triangle::set_total_quantity(new_total_quantity); // передача значения в функцию изменения значения статической переменной (сеттер)
        }

        Triangle* triangles[triangles_count]; // указатель на массив с объектами класса Triangle

        for (int i = 0; i < triangles_count; i++){ // цикл на ввод треугольников
            if (i >= (*triangles[i]).get_total_quantity()) break;
            float length[3]; // стороны треугольника
            cout << "\tInput " << i+1 << " triangle\n";

            for (int j = 0; j < 3; j++){ // цикл на ввод сторон текущего треугольника
                cout << "\t\t" << j+1 << " side: "; cin >> length[j];
            }

            // создание нового объекта класса Triangle через динамическое выделение памяти и передача введённых сторон в текущий треугольник
            triangles[i] = new Triangle(length[0], length[1], length[2]);
        }

        check_equilteral(triangles, (*triangles[0]).get_total_quantity()); // проверка треугольников на равносторонность

        for (int i = 0; i < (*triangles[0]).get_total_quantity(); i++) delete triangles[i]; // очистка памяти от динамического массива объектов класса Triangle

        break;
    }
    default: // если ничего не выбрано
        cout << "\n" << "Incorrect input." << "\n\n"; // вывод о некорректном вводе
        return 0; // завершение программы
    }

    return 0; // завершение 
}