/*==============================================================================
  Лабораторна робота №2. Завдання 1. Варіант 19.
  Тема: розгалужені обчислювальні процеси.

  Умова: визначити значення функції залежно від значення її аргументу,
         що вводиться з клавіатури (таблиця 2.1, варіант 19):

                  | 4 - x^2,  0 < x < 4
                  | 0,        x = 0
           f(x) = | x^3,      x < 0
                  | 1,        x > 4

  Зауваження щодо області визначення: умови таблиці не покривають точку
  x = 4 (інтервал заданий строгими нерівностями 0 < x < 4 та x > 4).
  Тому x = 4 обробляється як точка, в якій функцію не визначено, — про це
  виводиться окреме повідомлення, а не довільно домальоване значення.

  Виконав: Одарчук Олексій, КНУ імені Тараса Шевченка, ФІТ, група ІПЗ-11.

  Компілятор: g++ -std=c++17
==============================================================================*/

#include <iostream>

/* Код результату обчислення функції: чи визначено її в заданій точці. */
enum FuncStatus { FUNC_OK, FUNC_UNDEFINED };

/*------------------------------------------------------------------------------
  evaluate — обчислити значення кусково-заданої функції f(x).

  Параметри:
      x      [вхідний]  — аргумент функції;
      result [вихідний] — адреса змінної для значення функції;
                          заповнюється лише при поверненні FUNC_OK.

  Повертає: FUNC_OK        — функцію визначено, значення записано в *result;
            FUNC_UNDEFINED — функцію не визначено в точці x (випадок x = 4).

  Гілки реалізовано вкладеною конструкцією if ... else if ... else, оскільки
  умови є діапазонними: оператор switch тут незастосовний, бо його
  вираз-селектор не може належати до дійсного типу.
------------------------------------------------------------------------------*/
FuncStatus evaluate(double x, double *result)
{
    if (x < 0.0) {
        *result = x * x * x;
    } else if (x == 0.0) {
        *result = 0.0;
    } else if (x < 4.0) {
        *result = 4.0 - x * x;
    } else if (x > 4.0) {
        *result = 1.0;
    } else {
        return FUNC_UNDEFINED; /* залишається єдиний випадок x = 4 */
    }

    return FUNC_OK;
}

/*------------------------------------------------------------------------------
  branchName — текстова назва гілки, яку задіяно для заданого аргументу.
  Використовується для протоколювання: показує, яка саме умова спрацювала.

  Параметри: x [вхідний] — аргумент функції.
  Повертає : рядок-константу з описом гілки.
------------------------------------------------------------------------------*/
const char *branchName(double x)
{
    if (x < 0.0)
        return "x < 0      ->  f(x) = x^3";
    if (x == 0.0)
        return "x = 0      ->  f(x) = 0";
    if (x < 4.0)
        return "0 < x < 4  ->  f(x) = 4 - x^2";
    if (x > 4.0)
        return "x > 4      ->  f(x) = 1";
    return "x = 4      ->  функцію не визначено";
}

/*------------------------------------------------------------------------------
  readArgument — прочитати дійсне число з контролем коректності введення.

  Параметри: x [вихідний] — адреса змінної для аргументу функції.
  Повертає : true — число прочитано; false — вхідні дані вичерпано.
------------------------------------------------------------------------------*/
bool readArgument(double *x)
{
    std::cout << "Уведіть аргумент x = ";

    while (!(std::cin >> *x)) {
        if (std::cin.eof())
            return false;

        std::cin.clear();            /* зняти прапорець помилки */
        std::cin.ignore(1024, '\n'); /* очистити буфер клавіатури */
        std::cout << "Помилка: очікується дійсне число. Повторіть: ";
    }
    return true;
}

/*------------------------------------------------------------------------------
  Головна функція. Організовує введення аргументу, виклик обчислення
  та виведення результату.

  Локальні змінні:
      x      — аргумент функції, введений з клавіатури;
      y      — обчислене значення функції;
      status — ознака визначеності функції в точці x.
------------------------------------------------------------------------------*/
int main()
{
    std::cout << "Лабораторна робота №2, завдання 1 (варіант 19)\n"
                 "Виконав: студент групи ІПЗ-11 Одарчук Олексій\n"
                 "Обчислення кусково-заданої функції f(x):\n"
                 "    4 - x^2,  якщо 0 < x < 4\n"
                 "    0,        якщо x = 0\n"
                 "    x^3,      якщо x < 0\n"
                 "    1,        якщо x > 4\n"
              << std::endl;

    double x = 0.0;
    if (!readArgument(&x)) {
        std::cout << "\nВхідні дані вичерпано." << std::endl;
        return 1;
    }

    double y = 0.0;
    const FuncStatus status = evaluate(x, &y);

    /* Дійсні числа виводяться у фіксованому форматі з шістьма знаками. */
    std::cout.setf(std::ios::fixed);
    std::cout.precision(6);

    std::cout << "\nАргумент:  x = " << x << std::endl;
    std::cout << "Гілка:     " << branchName(x) << std::endl;

    if (status == FUNC_UNDEFINED) {
        std::cout << "Результат: функцію не визначено в точці x = 4 "
                     "(умова варіанта не покриває цю точку)."
                  << std::endl;
        return 2;
    }

    std::cout << "Результат: f(" << x << ") = " << y << std::endl;
    return 0;
}
