#include <iostream>

using namespace std;

class Point {
    int x, y; // переменные x y, представляющие собой координаты точки
    // прямая задаётся по уравнению y = k*x + b
    static double line_coefficients[2]; // массив, хранящий коэффициенты прямой (k - угол наклона прямой, b - ордината точки пересечения прямой оси Y)

    public:
    // функции для работы со статической переменной
    static double* get_line(){ return line_coefficients; } // получение значений прямой
    static void set_line(double *_coefficients) { line_coefficients[0] = _coefficients[0]; line_coefficients[1] = _coefficients[1]; } // установка значений прямой
    static void change_line_angle(double _angle_coefficient){ line_coefficients[0] = _angle_coefficient; } // изменение коэффциента угла наклона прямой

    Point(){
        cout << "\n\t\t\t\t\t\t\t\t\t\t\t" << "Constructor without parameters " << this << " initialized."; // вывод информации о инициализации конструктора
    }

    Point(int _x, int _y){ // конструктор с параметрами
        cout << "\n\t\t\t\t\t\t\t\t\t\t\t" << "Constructor with parameters " << this << " initialized."; // вывод информации о инициализации конструктора
        this->x = _x; this->y = _y; 
    }

    Point(int _x = 0, int _y = 0){ // конструктор с параметрами по умолчанию
        cout << "\n\t\t\t\t\t\t\t\t\t\t\t" << "Constructor with parameters by default " << this << " initialized.\n"; // вывод информации о инициализации конструктора
        this->x = _x; this->y = _y; 
    }

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

    // проверка на принадлежность точки прямой
    bool is_point_on_line(){ return (this->y == (line_coefficients[0] * this->x + line_coefficients[1])); }
    // перегрузка оператора сравнения
    bool operator == (Point& point){ return point.is_point_on_line(); }
    // объявление перегрузки оператора ввода дружественной для прямого ввода приватных переменных x и y
    friend istream& operator>> (istream &in, Point& point);
};

istream& operator>> (istream &in, Point& point){ // перегрузка оператора ввода для прямого ввода координат точки
    cout << "\tInput point x and y coordinates (use space to split them): "; in >> point.x >> point.y; // ввод координат точки
    return in;
}
// функция установки коэффциентов прямой
void set_line_coefficients(){
    double coefficients[2]; // массив для ввода новых значений статической прямой
    // получение текущих значений статической прямой
    double *line_coefficients = Point::get_line();
    // вывод текущих значений статической прямой
    cout << "\n" << "Current coefficients of static line:" << "\n";
    cout << "\t" << "Inclination angle: " << line_coefficients[0] << "\n"; // вывод коэффициента угла наклона
    cout << "\t" << "The ordinate of the point of intersection: " << line_coefficients[1] << "\n"; // вывод ординаты точки пересечения прямой оси Y
    // ввод новых значений коэффициентов статической прямой
    cout << "\n" << "Input new values of static line:" << "\n";
    cout << "\t" << "Input new inclination angle: "; cin >> coefficients[0]; // ввод нового значения углового коэффциента
    cout << "\t" << "Input new ordinate of the point of intersection: "; cin >> coefficients[1]; // ввод нового значения ординаты точки пересечения прямой
    cout << "\n\n";
    // передача введённых значений в класс
    Point::set_line(coefficients);
}

void output_points_on_line(Point** _points, int _points_count){
    for (int i = 0; i < _points_count; i++) if ((*_points[i]) == (*_points[i])) cout << "\t" << i+1 << " point is on a line" << "\n";
}

// установка значений статического массива с коэффциентами по умолчанию во избежание ошибки "Неопределённая ссылка"
double Point::line_coefficients[2] = {1.0, 0.0};

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

int main(){
    int choice; // выбор типа конструктора (без параметров, с параметрами)
    int points_count; // количество точек
    double inclination_angle; // угловой коэффциент прямой
    // ввод количества точек
    cout << "Input points count: "; cin >> points_count;
    if (points_count < 1) { cout << "Points count can't be less than 1!\n"; return 0; }
    
    Point* points[points_count]; // создание массива указателей на объекты класса Point с размером points_count

    // вывод возможных вариантов для инициализации объектов
    cout << "\nPlease, choose constructor's type:" << "\n";
    cout << "1. Default constructor (without parameters)." << "\n";
    cout << "2. Constructor with parameters." << "\n";
    // ввод пользователя
    cin >> choice;

    switch (choice){
    case UserChoice::DEFAULT:{ // использование конструктора без параметров
        for (int i = 0; i < points_count; i++){
            points[i] = new Point(); // создание нового объекта класса Point через явный конструктор без параметров
            cout << "\nInput " << i+1 << " point:\n"; cin >> (*points[i]);
        }
        break;
    }
    case UserChoice::WITH_PARAMETERS:{ // использование конструктора с параметрами
        int x, y; // объявление переменных, отвечающих за координаты точки
        for (int i = 0; i < points_count; i++){
            cout << "\nInput " << i+1 << " point:\n";
            cout << "\tInput point x and y coordinates (use space to split them): "; cin >> x >> y; // ввод x и y
            points[i] = new Point(x, y); // создание нового объекта класса Point через явный конструктор с параметрами
        }
        break;
    }
    default: // если ввод не соответствует никакому варианту
        cout << "\n" << "Incorrect input." << "\n\n"; // вывод о некорректном вводе
        return 0; // завершение программы
    }

    set_line_coefficients(); // изменение коэффициентов прямой

    // вывод точек, которые находяться на заданной прямой
    cout << "\n" << "Points on the line: " << "\n\n";
    output_points_on_line(points, points_count);

    // ввод нового значения угла наклона заданной прямой
    cout << "\n" << "Input new inclination angle: "; cin >> inclination_angle;
    Point::change_line_angle(inclination_angle);

    // вывод точек, которые находяться на заданной прямой после изменения угла наклона прямой
    cout << "\n" << "Points on the line after changing inclination angle of line: " << "\n\n";
    output_points_on_line(points, points_count);

    // удаление объектов в динамическом массиве
    for (int i = 0; i < points_count; i++) delete points[i];
    
    // завершение программы
    return 0;
}