/*
    Парус 8 - Панели мониторинга
    Хуки для таблиц данных
*/

//---------------------
//Подключение библиотек
//---------------------

import { useReducer, useCallback, useEffect, useContext, useRef, useMemo } from "react"; //Классы React
import { BackEndCtx } from "../context/backend"; //Контекст взаимодействия с сервером
import { object2Base64XML } from "../core/utils"; //Вспомогательные функции
import config from "../../app.config"; //Настройки приложения
import { DG_AT, INITIAL_STATE, dataGridReducer } from "./p8p_data_grid_reducer"; //Редьюсер состояния

//---------
//Константы
//---------

//Константы - значения по умолчанию
const DG_PAGE_SIZE_DEF = config.SYSTEM.PAGE_SIZE; //Размер страницы
const DG_NODE_NAME_DEF = "XDATA_GRID"; //Наименование узла, содержащего информацию о таблице
const FILTERS_NODE_NAME_DEF = "filters"; //Наименование узла отборов
const ORDERS_NODE_NAME_DEF = "orders"; //Наименование узла сортировок
const RESP_ARG_DEF = "COUT"; //Имя параметра, содержащего информацию о таблице

//-----------
//Тело модуля
//-----------

//Хук для P8PDataGrid
const useP8PDataGrid = ({
    stored,
    respArg = RESP_ARG_DEF,
    contentNodeName = DG_NODE_NAME_DEF,
    filtersNodeName = FILTERS_NODE_NAME_DEF,
    ordersNodeName = ORDERS_NODE_NAME_DEF,
    pageSize = DG_PAGE_SIZE_DEF,
    reloadDef = false,
    initFilters = [],
    initOrders = [],
    storedArgs = {},
    resetPageNumberOnStoredArgsChange = true,
    executeStoredArgs = {},
    resetPageNumberOnExecuteStoredArgsChange = true,
    allowDataLoad = () => true
}) => {
    //Подключим редьюсер состояния
    const [state, dispatch] = useReducer(dataGridReducer, INITIAL_STATE({ initFilters, initOrders }));

    //Установка даных таблицы
    const setDataGrid = (dataGridData, pageSize, isError) => dispatch({ type: DG_AT.SET_DATA_GRID, payload: { dataGridData, pageSize, isError } });

    //Установка фильтра таблицы
    const setDataGridFilter = filters => dispatch({ type: DG_AT.SET_DATA_GRID_FILTER, payload: filters });

    //Установка сортировок таблицы
    const setDataGridOrder = orders => dispatch({ type: DG_AT.SET_DATA_GRID_ORDER, payload: orders });

    //Установка страницы таблицы
    const setDataGridPageNumber = pageNumber => dispatch({ type: DG_AT.SET_DATA_GRID_PAGE_NUMBER, payload: pageNumber });

    //Установка флага загруженности данных
    const setIsDataLoaded = isDataLoaded => dispatch({ type: DG_AT.SET_IS_DATA_LOADED, payload: isDataLoaded });

    //Установка флага активности процесса загрузки данных
    const setIsLoading = isLoading => dispatch({ type: DG_AT.SET_IS_LOADING, payload: isLoading });

    //Установка флага необходимости обновления данных
    const setReload = (reload, resetPageNumber = false) => dispatch({ type: DG_AT.SET_RELOAD, payload: { reload, resetPageNumber } });

    //Ссылка на актуальные параметры хранимой процедуры
    const refStoredArgs = useRef(storedArgs);

    //Ссылка на актуальные параметры исполнения хранимой процедуры
    const refExecuteStoredArgs = useRef(executeStoredArgs);

    //Признак допустимости обновления данных
    const isAllowDataLoad = useMemo(() => {
        return allowDataLoad();
    }, [allowDataLoad]);

    //Подключение к контексту взаимодействия с сервером
    const { executeStored, SERV_DATA_TYPE_CLOB, isRespErr } = useContext(BackEndCtx);

    //Загрузка данных таблицы с сервера
    const loadData = useCallback(async () => {
        try {
            //Поднимаем флаг начала загрузки данных
            setIsLoading(true);
            //Получаем данные с сервера БД
            const data = await executeStored({
                stored,
                args: {
                    CFILTERS: {
                        VALUE: object2Base64XML(state.dataGrid.filters, { arrayNodeName: filtersNodeName }),
                        SDATA_TYPE: SERV_DATA_TYPE_CLOB
                    },
                    CORDERS: { VALUE: object2Base64XML(state.dataGrid.orders, { arrayNodeName: ordersNodeName }), SDATA_TYPE: SERV_DATA_TYPE_CLOB },
                    NPAGE_NUMBER: state.dataGrid.pageNumber,
                    NPAGE_SIZE: pageSize,
                    NINCLUDE_DEF: reloadDef ? 1 : state.isDataLoaded ? 0 : 1,
                    ...refStoredArgs.current
                },
                respArg,
                ...refExecuteStoredArgs.current
            });
            //Устанавливаем полученные бизнес-данные, признак загрузки данных с учетом возможных ошибок, признак наличия бизнес-данных
            setDataGrid(data[contentNodeName], pageSize, isRespErr(data));
        } catch (e) {
            //Если произошла ошибка - данные не загружены
            setIsDataLoaded(false);
        } finally {
            //Сбрасываем признаки загрузки и перезагрузки данных
            setIsLoading(false);
        }
    }, [
        SERV_DATA_TYPE_CLOB,
        contentNodeName,
        state.isDataLoaded,
        state.dataGrid.filters,
        state.dataGrid.orders,
        state.dataGrid.pageNumber,
        executeStored,
        filtersNodeName,
        isRespErr,
        ordersNodeName,
        pageSize,
        reloadDef,
        respArg,
        stored
    ]);

    //При изменении состояния фильтра
    const handleFilterChanged = useCallback(({ filters }) => setDataGridFilter(filters), []);

    //При изменении состояния сортировки
    const handleOrderChanged = useCallback(({ orders }) => setDataGridOrder(orders), []);

    //При изменении количества отображаемых страниц
    const handlePagesCountChanged = useCallback(() => setDataGridPageNumber(state.dataGrid.pageNumber + 1), [state.dataGrid.pageNumber]);

    //При изменении страницы отображения
    const handlePageChange = useCallback(({ page }) => setDataGridPageNumber(page), []);

    //При необходимости обновления таблицы
    const doReload = useCallback(
        ({ returnOnFirstPage = false }) => setReload(true, state.dataGrid.pagesCount <= 0 || returnOnFirstPage),
        [state.dataGrid.pagesCount]
    );

    //Проверка изменений параметров
    const isArgsChanged = useCallback(
        (currentArgs, args) => {
            //Если дополнительные параметры изменились (и сейчас не происходит загрузка данных с сервера)
            return !state.isLoading && JSON.stringify(currentArgs) != JSON.stringify(args);
        },
        [state.isLoading]
    );

    //При изменение дополнительных параметров процедуры
    useEffect(() => {
        //Если параметры изменились
        if (isArgsChanged(refStoredArgs.current, storedArgs)) {
            //Устанавливаем новые дополнительные параметры
            refStoredArgs.current = storedArgs;
            //При изменении дополнительных параметров необходимо перезагрузить данные
            setReload(true, resetPageNumberOnStoredArgsChange);
        }
    }, [storedArgs, resetPageNumberOnStoredArgsChange, isArgsChanged]);

    //При изменение дополнительных параметров вызова процедуры
    useEffect(() => {
        //Если параметры изменились
        if (isArgsChanged(refExecuteStoredArgs.current, executeStoredArgs)) {
            //Устанавливаем новые дополнительные параметры
            refExecuteStoredArgs.current = executeStoredArgs;
            //При изменении дополнительных параметров необходимо перезагрузить данные
            setReload(true, resetPageNumberOnExecuteStoredArgsChange);
        }
    }, [executeStoredArgs, resetPageNumberOnExecuteStoredArgsChange, isArgsChanged]);

    //При необходимости обновить данные таблицы
    useEffect(() => {
        if (isAllowDataLoad && state.reload) {
            loadData();
        }
    }, [isAllowDataLoad, state.reload, loadData]);

    //Возвращаем данные таблицы
    return {
        dataGrid: state.dataGrid,
        isDataLoaded: state.isDataLoaded,
        isDataFound: state.isDataFound,
        isLoading: state.isLoading,
        handleFilterChanged,
        handleOrderChanged,
        handlePagesCountChanged,
        handlePageChange,
        doReload
    };
};

//----------------
//Интерфейс модуля
//----------------

export { useP8PDataGrid };
