<?php
/**
 * ResponsiveHelper.php
 *
 * This class collects helper methods for Stud.IP's responsive design.
 *
 * @author    Jan-Hendrik Willms <tleilax+studip@gmail.com>
 * @license   GPL2 or any later version
 * @copyright Stud.IP core group
 * @since     Stud.IP 3.2
 */
class ResponsiveHelper
{
    /**
     * Returns the current navigation as an array.
     *
     * @return Array containing the navigation
     */
    public static function getNavigationArray()
    {
        $navigation = [];
        $activated  = [];

        $link_params = array_fill_keys(array_keys(URLHelper::getLinkParams()), null);

        foreach (Navigation::getItem('/')->getSubNavigation() as $path => $nav) {
            $image = $nav->getImage();

            $forceVisibility = false;
            /*
             * Special treatment for "browse" navigation which is normally hidden
             * when we are inside a course.
             */
            if ($path === 'browse' && !$image) {
                $image = Icon::create('seminar');
                $forceVisibility = true;
            }
            /*
             * Special treatment for "footer" navigation because
             * the real footer is hidden in responsive view.
             */
            if ($path === 'footer' && !$image) {
                $image = Icon::create('info');
                $nav->setTitle(_('Impressum & Information'));
                $forceVisibility = true;
            }

            $image_src = $image ? $image->copyWithRole('info_alt')->asImagePath() : false;
            $item = [
                'icon'     => $image_src ? self::getAssetsURL($image_src) : false,
                'title'    => (string) $nav->getTitle(),
                'url'      => URLHelper::getURL($nav->getURL(), $link_params, true),
                'parent'   => '/',
                'path'     => $path,
                'visible'  => $forceVisibility ? true : $nav->isVisible(true),
                'active'   => $nav->isActive()
            ];

            if ($nav->isActive()) {
                // course navigation is integrated in course sub-navigation items
                if ($path === 'course') {
                    $activated[] = 'browse/my_courses/' . (Context::get()->getId());
                } else {
                    $activated[] = $path;
                }
            }

            if ($nav->getSubnavigation() && $path != 'start') {
                $item['children'] = self::getChildren($nav, $path, $activated);
            }

            if ($path !== 'course') {
                $navigation[$path] = $item;
            }
        }

        return [$navigation, $activated];
    }

    /**
     * Returns the navigation object required for the Vue.js component.
     *
     * The object will always contain the currently selected navigation path.
     * Besides that, the object may contain the whole navigation and a hash
     * for that navigation. If a hash is passed and it matches the currently
     * genereated hash, the navigation and hash will be omitted from the
     * response for performance reasons. We don't want to include the large
     * navigation object in every response.
     *
     * @return array
     */
    public static function getNavigationObject(string $stored_hash = null): array
    {
        [$navigation, $activated] = self::getNavigationArray();
        $hash = md5(json_encode($navigation));

        $response = compact('activated');
        if ($stored_hash !== $hash) {
            $response = array_merge($response, compact('navigation', 'hash'));
        }

        return $response;
    }

    /**
     * Recursively build a navigation array from the subnavigation/children
     * of a navigation object.
     *
     * @param Navigation  $navigation The navigation object
     * @param String      $path       Current path segment
     * @param array       $activated  Activated items
     * @param String|null $cid       Optional context ID
     * @return Array containing the children (+ grandchildren...)
     */
    protected static function getChildren(Navigation $navigation, $path, &$activated = [], string $cid = null)
    {
        $children = [];

        foreach ($navigation->getSubNavigation() as $subpath => $subnav) {
            /*if (!$subnav->isVisible()) {
                continue;
            }*/

            $originalSubpath = $subpath;
            $subpath = "{$path}/{$subpath}";

            $item = [
                'title'   => (string) $subnav->getTitle(),
                'url'     => URLHelper::getURL($subnav->getURL(), $cid ? ['cid' => $cid] : []),
                'parent'  => $path,
                'path'    => $subpath,
                'visible' => $subnav->isVisible(),
                'active'  => $subnav->isActive()
            ];

            if ($subnav->isActive()) {
                // course navigation is integrated in course sub-navigation items
                if ($path === 'course') {
                    $activated[] = 'browse/my_courses/' . Context::get()->getId() . '/' . $originalSubpath;
                } else {
                    $activated[] = $subpath;
                }
            }

            if ($subnav->getSubNavigation()) {
                $item['children'] = self::getChildren($subnav, $subpath);
            }

            if ($subpath === 'browse/my_courses') {
                $item['children'] = array_merge($item['children'] ?? [], static::getMyCoursesNavigation($activated));
            }

            $children[$subpath] = $item;
        }

        return $children;
    }

    /**
     * Try to get a compressed version of the passed navigation url.
     * The URL is processed is processed by URLHelper and the absolute uri
     * of the Stud.IP installation is stripped from it afterwards.
     *
     * @param  String $url The url to compress
     * @return String containing the compressed url
     */
    protected static function getURL($url, $params = [])
    {
        return str_replace($GLOBALS['ABSOLUTE_URI_STUDIP'], '', URLHelper::getURL($url, $params));
    }

    /**
     * Try to get a compressed version of the passed assets url.
     * The absolute uri of the Stud.IP installation is stripped from the url.
     *
     * @param  String $url The assets url to compress
     * @return String containing the compressed assets url
     */
    protected static function getAssetsURL($url)
    {
        return str_replace($GLOBALS['ASSETS_URL'], '', $url);
    }

    /**
     * Specialty for responsive navigation: build navigation items
     * for my courses in current semester.
     *
     * @return array
     */
    protected static function getMyCoursesNavigation($activated): array
    {
        if (!$GLOBALS['perm']->have_perm('admin')) {
            $sem_data = Semester::getAllAsArray();

            $currentIndex = -1;

            foreach ($sem_data as $index => $semester) {
                if (!empty($semester['current'])) {
                    $currentIndex = $index;
                    break;
                }
            }

            $params = [
                'deputies_enabled' => Config::get()->DEPUTIES_ENABLE
            ];

            $courses = MyRealmModel::getCourses($currentIndex, $currentIndex, $params);
        } else {
            $courses = [];
        }

        $items = [];

        $standardIcon = Icon::create('seminar', Icon::ROLE_INFO_ALT)->asImagePath();

        // Add current course to list.
        if (Context::get() && Context::isCourse()) {
            $courses[] = Context::get();
        }

        foreach ($courses as $course) {
            $avatar = CourseAvatar::getAvatar($course->id);
            if ($avatar->is_customized()) {
                $icon = $avatar->getURL(Avatar::SMALL);
            } else {
                $icon = $standardIcon;
            }

            $cnav = [
                'icon'     => $icon,
                'title'    => $course->getFullname(),
                'url'      => URLHelper::getURL('dispatch.php/course/details', ['cid' => $course->id]),
                'parent'   => 'browse/my_courses',
                'path'     => 'browse/my_courses/' . $course->id,
                'visible'  => true,
                'active'   => Course::findCurrent() ? Course::findCurrent()->id === $course->id : false,
                'children' => []
            ];

            foreach ($course->tools as $tool) {
                if (Seminar_Perm::get()->have_studip_perm($tool->getVisibilityPermission(), $course->id)) {

                    $path = 'browse/my_courses/' . $course->id;

                    $studip_module = $tool->getStudipModule();
                    if ($studip_module instanceof StudipModule) {
                        $tool_nav = $studip_module->getTabNavigation($course->id) ?: [];
                        foreach ($tool_nav as $nav_name => $navigation) {
                            if ($nav_name && is_a($navigation, 'Navigation')) {
                                $cnav['children'][$path . '/' . $nav_name] = [
                                    'icon'     => $navigation->getImage() ? $navigation->getImage()->asImagePath() : '',
                                    'title'    => $tool->getDisplayname(),
                                    'url'      => URLHelper::getURL($navigation->getURL(), ['cid' => $course->id]),
                                    'parent'   => 'browse/my_courses/' . $course->id,
                                    'path'     => 'browse/my_courses/' . $course->id . '/' . $nav_name,
                                    'visible'  => true,
                                    'active'   => $navigation->isActive(),
                                    'children' => static::getChildren(
                                        $navigation,
                                        'browse/my_courses/' . $course->id . '/' . $nav_name,
                                        $activated,
                                        $course->id
                                    ),
                                ];
                            }
                        }
                    }
                }
            }

            $items['browse/my_courses/' . $course->id] = $cnav;

        }

        return $items;
    }
}