<?php

/**
 * Class ModuleBuilderHelper
 * Helper functions for Module Builder module.
 *
 * @copyright MTC media Ltd.
 * @author Rihards Silins
 *
 * @version 2 14/07/2016
 */
namespace Mtc\Modules\ModuleBuilder\Classes;

class ModuleHelper
{
    /**
     * ModuleBuilderHelper::generateNondestructiveUrl()
     * Generate a url with and/or without the desired params without destroying any existing params.
     *
     * @param string[] new_params - get params that need to be added
     * @param string[] remove_params - get params that need to be removed
     *
     * @return string url
     */
    public static function generateNondestructiveUrl($new_params = array(), $remove_params = array(), $href = null)
    {
        $url = '';

        $parsed_url = parse_url($_SERVER['REQUEST_URI']);
        $parsed_query = array();
        if (isset($parsed_url['query']) && ! empty($parsed_url['query'])) {
            parse_str($parsed_url['query'], $parsed_query);
        }

        foreach ($remove_params as $value) {
            // check if all need to be removed
            if ($value == '*') {
                $parsed_query = array();
                break;
            }
            unset($parsed_query[$value]);
        }

        $merged_query = array_merge($parsed_query, $new_params);

        $url = $parsed_url['path'];

        if ($href != null) {
            if ($href[0] == '/') {
                $url = $href;
            } else {
                // get path up to current module's admin directory
                preg_match('#(/[^/]+){3}/#', $url, $match);
                if (! empty($match[0])) {
                    $url = $match[0].$href;
                } else {
                    $url = $href;
                }
            }
        }

        if (! empty($merged_query)) {
            $url .= '?'.http_build_query($merged_query);
        }

        return $url;
    }

    /**
     * ModuleBuilderHelper::generatePagination()
     * A neat reusable helper function for generating a simple pagination as there's alot of logic in these usually.
     * Used by all modules generated by the module builder.
     *
     * @param int number_of_pages_in_the_pagination - how many pagination pages are there in total
     * @param int current_page - what the current page is
     * @param int how_many_numbers_to_show - how many number to show ... [1] [2] [3] ...
     *
     * @return string pagination_html
     */
    public static function generatePagination(
        $number_of_pages_in_the_pagination,
        $current_page = 1,
        $how_many_numbers_to_show = 10,
        $template_path = '/admin/module_builder/module_helper',
    ) {
        $html = '';

        if ($number_of_pages_in_the_pagination < 2) {
            return $html;
        }

        $first_number = $current_page - floor($how_many_numbers_to_show / 2);
        if ($first_number <= 1) {
            $first_number = 1;
        }

        $pagination_tree = array();

        if ($current_page > 1) {
            $pagination_tree[] = array(
                'class' => 'first',
                'title' => 'First Page',
                'link' => self::generateNondestructiveUrl(['page' => 1]),
            );
            $pagination_tree[] = array(
                'class' => 'prev',
                'title' => 'Previous',
                'rel' => 'prev',
                'link' => self::generateNondestructiveUrl(['page' => $current_page - 1]),
            );
        }

        if ($first_number > 1) {
            $pagination_tree[] = array(
                'class' => 'dots',
                'title' => '&hellip;',
                'link' => false,
            );
        }

        $last_number = $first_number + $how_many_numbers_to_show - 1;
        if ($last_number >= $number_of_pages_in_the_pagination) {
            $last_number = $number_of_pages_in_the_pagination;
        }

        // generate the numbers part .. [1] [2] [3] ...

        for ($i = $first_number; $i <= $last_number; ++$i) {
            $class = '';
            if ($i == $current_page) {
                $class = 'active';
            }

            $pagination_tree[] = array(
                'class' => $class,
                'link' => self::generateNondestructiveUrl(['page' => $i]),
                'title' => $i,
            );
        }

        if ($last_number < $number_of_pages_in_the_pagination) {
            $pagination_tree[] = array(
                'class' => 'dots',
                'title' => '&hellip;',
                'link' => false,
            );
        }

        if ($current_page < $number_of_pages_in_the_pagination) {
            $pagination_tree[] = array(
                'class' => 'next',
                'title' => 'Next',
                'rel' => 'next',
                'link' => self::generateNondestructiveUrl(['page' => $current_page + 1]),
            );
            $pagination_tree[] = array(
                'class' => 'last',
                'title' => 'Last Page',
                'link' => self::generateNondestructiveUrl(['page' => $number_of_pages_in_the_pagination]),
            );
        }

        global $twig;
        $html = $twig->render(
            $template_path.'/pagination.twig',
            array(
                'pagination_tree' => $pagination_tree,
            ),
        );

        return $html;
    }

    /**
     * Merge in session messages with form_messages. Then unset the session ones.
     * @param string[][] $form_messages
     * @return string[][] $form_messages
     */
    public static function mergeSessionMessages($form_messages)
    {
        // process session stored messages, alerts, errros
        foreach (array('success', 'error', 'alert') as $message_type) {
            if (empty($_SESSION['model_form'][$message_type])) {
                continue;
            }
            $form_messages[$message_type] = array_merge(
                $form_messages[$message_type],
                $_SESSION['model_form'][$message_type],
            );
            unset($_SESSION['model_form'][$message_type]);
        }

        return $form_messages;
    }

    /**
     * Print messages
     * @param string[][] $form_messages
     * @return string $messages_html
     */
    public static function printMessages($form_messages)
    {
        foreach ($form_messages as $class => $messages) {
            if (empty($messages)) {
                continue;
            }
            ?><div class="el msg <?= clean_page($class) ?>"><?php

            $already_displayed_messages = array();
            foreach ($messages as $message) {
                // Check if this message was already displayed - if so skip
                if (in_array($message, $already_displayed_messages)) {
                    continue;
                }
                ?><p><?= $message ?></p><?php

                $already_displayed_messages[] = $message;
            }
            ?></div><?php
        }
    }

    /**
     * Function retrieves and filters a list of the given model. This is used in manage and manager relation panels
     * Can also later be used in search ajax list. To unite logic.
     * @param String    $model_class_name   Name of the mode class - with the whole namespace.
     * @param mixed[][] $module             The models module setup.
     * @param mixed[][] $get                The $_GET request.
     * @param Integer   $model_manage_limit The number of items to display in one page.
     * @param String    $parent_key         Optional. Parent key column name to filter by in case this is a relation.
     * @param Integer   $parent_key         Optional. Id of parent key to filter list by in case this is a relation.
     * @return mixed[] $result Result containing 'model_list', 'model_list_count', 'model_list_page_no', 'model_manage_limit'.
     */
    public static function getList(
        $model_class_name,
        $module,
        $get,
        $model_manage_limit,
        $parent_key = null,
        $parent_id = null,
    ) {
        $model_lister = $model_class_name::query();

        if (! empty($parent_key) && ! empty($parent_id)) {
            $model_lister = $model_lister->where(
                $parent_key,
                $parent_id,
            );
        }

        // Advanced filter.
        if (! empty($module['advanced_filter'])) {
            foreach ($module['advanced_filter'] as $filter_name => $attribute) {
                if (
                    ! isset($get['filter'][$filter_name])
                    && isset($module['advanced_filter'][$filter_name]['default_value'])
                ) {
                    $value = $module['advanced_filter'][$filter_name]['default_value'];
                } elseif (isset($get['filter'][$filter_name])) {
                    if ($get['filter'][$filter_name] === '') {
                        continue;
                    }
                    $value = $get['filter'][$filter_name];
                } else {
                    continue;
                }

                if (empty($module['advanced_filter'][$filter_name]['filter_attribute'])) {
                    $attribute_name = $filter_name;
                } else {
                    $attribute_name = $module['advanced_filter'][$filter_name]['filter_attribute'];
                }

                if ($module['advanced_filter'][$filter_name]['type'] === 'datetime') {
                    $value = ModuleActions::datetimeAdjust($value, $filter_name, $module['advanced_filter']);
                }
                if (empty($module['advanced_filter'][$filter_name]['operator'])) {
                    $model_lister = $model_lister->where($attribute_name, $value);
                } else {
                    if ($module['advanced_filter'][$filter_name]['operator'] === 'LIKE') {
                        $value = '%'.$value.'%';
                    }
                    $model_lister = $model_lister->where(
                        $attribute_name,
                        $module['advanced_filter'][$filter_name]['operator'],
                        $value,
                    );
                }
                unset($value);
            }
        }

        // Group by filter
        if (! empty($module['group_by'])) {
            foreach ($module['group_by'] as $attribute_name => $attribute) {
                if (
                    ! isset($get['group_by'][$attribute_name]) && isset($module['group_by'][$attribute_name]['value'])
                ) {
                    $value = $module['group_by'][$attribute_name]['value'];
                } elseif (isset($get['group_by'][$attribute_name])) {
                    if ($get['group_by'][$attribute_name] === '') {
                        continue;
                    }
                    $value = $get['group_by'][$attribute_name];
                } else {
                    continue;
                }

                if (empty($value)) {
                    continue;
                }

                $model_lister = $model_lister->groupBy($attribute_name);

                unset($value);
            }
        }

        $model_list_count = $model_lister->count();

        $model_list_page_no = 1;
        if (! empty($get['page'])) {
            $model_list_page_no = $get['page'];
        }

        if ($model_manage_limit == 0) {
            $model_manage_limit = PHP_INT_MAX;
        }

        $model_list_offset = ($model_list_page_no - 1) * $model_manage_limit;
        $model_lister = $model_lister->take($model_manage_limit)->skip($model_list_offset);

        // apply order
        if (! empty($module['list_order'])) {
            foreach ($module['list_order'] as $order) {
                $model_lister = $model_lister->orderBy($order[0], $order[1]);
            }
        }

        return [
            'model_list' => $model_lister->get(),
            'model_list_count' => $model_list_count,
            'model_list_page_no' => $model_list_page_no,
            'model_manage_limit' => $model_manage_limit,
        ];
    }
}
