<?php
/**
 * @package    pixelcms_articles
 *
 * @author     christophf <your@email.com>
 * @copyright  A copyright
 * @license    GNU General Public License version 2 or later; see LICENSE.txt
 * @link       http://your.url.com
 */

use Joomla\CMS\MVC\View\HtmlView;

defined('_JEXEC') or die;

/**
 * Pixelcms_articles view.
 *
 * @package  pixelcms_articles
 * @since    1.0
 */
class Pixelcms_articlesViewPixelcms_articles extends HtmlView
{
    const templates = [
        0 => 'text-only',
        1 => '1-images',
        3 => '3-images',
        5 => '5-images',
    ];
    public $item_id;
    public $article;
    public $category;
    public $articleId;
    public $cms_url;
    public $alias;
    /**
     * @var extendedRegistry
     * @since version
     */
    public $params;
    public $options;
    public $hasVimeoPlayer = false;
    public $hasYoutubePlayer = false;
    public $hasFacebookPlayer = false;
    public $hasVideoPlayer = false;
    public $templateClass;
    protected $is_module = false;

    static $attachments = [
        'galleries' => 'gallery',
        'workers' => 'worker',
        'pdfs' => 'pdf',
        'files' => 'file',
        'videos' => 'video',
        'images' => 'image',
        'locations' => 'location',
        'departments' => 'department',
    ];

    protected function _setPath($type, $path)
    {
        $component = 'com_pixelcms_articles';
        $app = JFactory::getApplication();

        // Clear out the prior search dirs
        $this->_path[$type] = array();

        // Actually add the user-specified directories
        $this->_addPath($type, $path);

        // Always add the fallback directories as last resort
        switch (strtolower($type))
        {
            case 'template':
                // Set the alternative template search dir
                if (isset($app))
                {
                    $component = preg_replace('/[^A-Z0-9_\.-]/i', '', $component);
                    $fallback = JPATH_THEMES . '/' . $app->getTemplate() . '/html/' . $component . '/' . $this->getName();
                    $this->_addPath('template', $fallback);
                }
                break;
        }
    }

    public function compileClassList(array $classList): string
    {
        $classList = array_filter($classList);
        $classList = array_map(function($className, $classModifier) {
            return (is_numeric($className)) ? "cms_article--$classModifier" : "cms_article--$className-$classModifier";
            }, array_keys($classList), $classList);

        return implode(' ', $classList);
    }

    public function displayFile($file)
    {
        return "<a class='pdf' target='_blank' href='{$this->params->get('pixel_cms_url')}$file->url'><span class='pdf__title'>$file->title</span></a>";
    }

    public function getIntro(string $value, int $limit = 200, string $allowedTags = '<p><i><u><a><b><ul><li><strong><br>'): string
    {
        if ($allowedTags !== false) {
            $value = strip_tags($value, $allowedTags);
        }

        if ($limit === 0) {
            return $value;
        }

        return  preg_replace( "/\r|\n/", "", $this->substrHtml($value, $limit));
    }

    private function substrHtml(string $value, int $limit = 200): string
    {
        if (mb_strwidth($value, 'UTF-8') <= $limit) {
            return $value;
        }

        // Stores fulltext length
        $textLength = mb_strwidth($value, 'UTF-8');

        // Strip text with HTML tags, sum html len tags too.
        // Is there another way to do it?
        do {
            $len          = mb_strwidth($value, 'UTF-8');
            $len_stripped = mb_strwidth(strip_tags($value), 'UTF-8');
            $len_tags     = $len - $len_stripped;

            $value = mb_strimwidth($value, 0, $limit + $len_tags, '', 'UTF-8');
        } while ($len_stripped > $limit);

        // if intro is shorter append the 3 dots
        if (mb_strwidth($value, 'UTF-8') < $textLength) {
            $value = '<?xml encoding="utf-8" ?>'.$value.'…';
        } else {
            $value = '<?xml encoding="utf-8" ?>'.$value;
        }

        // Load as HTML ignoring errors
        $dom = new DOMDocument();
        @$dom->loadHTML($value, LIBXML_HTML_NODEFDTD);

        // Fix the html errors
        $value = $dom->saveHtml($dom->getElementsByTagName('body')->item(0));

        // Remove body tag
        $value = mb_strimwidth($value, 6, mb_strwidth($value, 'UTF-8') - 13, '', 'UTF-8'); // <body> and </body>
        // Remove empty tags
        return preg_replace('/<(\w+)\b(?:\s+[\w\-.:]+(?:\s*=\s*(?:"[^"]*"|"[^"]*"|[\w\-.:]+))?)*\s*\/?>\s*<\/\1\s*>/', '', $value);

    }

    public function displayWorker($worker)
    {
        //$html[] =  "<pre>". print_r($worker, true) ."</pre>";
        if ($worker->image) {
            $thumb = preg_replace('/(^(?!http)(?:(?!thumb).)*)\.(jpe?g|png|gif)/', '$1.500-cropped.$2', $worker->image->url);
            $html[] = "<div class='worker__image' style='background-image: url({$this->params->get('pixel_cms_url')}{$thumb})'></div>";
	    } else {
		    $gender = ($worker->title === 2) ? 'female' : 'male';
		    $html[] = "<div class='worker__image worker__image--empty worker__image--empty--$gender'></div>";
        }
        $html[] = "<h4 class='worker__title'>$worker->first_name $worker->last_name</h4>";
        if (isset($worker->role) && $worker->role !== '') {
            $html[] = "<span class=\"worker__role\">$worker->role</span>";
        }
        if (isset($worker->bio) && $worker->bio !== '') {
            $html[] = "<span class=\"worker__bio\">$worker->bio</span>";
        }
        $html[] = "<ul class=\"worker__contact\">";
        if ($worker->email) {
            $worker->email = str_rot13($worker->email);
            $html[] = "<li><a class='emails--encrypted' href=\"mailto:$worker->email\"><i class=\"pixelcms-icons\">email</i><span>$worker->email</span></a></li>";
        }
        if ($worker->tel) {
            $telNumber = $this->getCallablePhone($worker->tel);
            $displayNumber = $this->getDisplayablePhone(($worker->tel));
            $html[] = "<li><a href=\"tel:$telNumber\"><i class=\"pixelcms-icons\">phone</i><span>$displayNumber</span></a></li>";
        }
        if ($worker->mobile) {
            $telNumber = $this->getCallablePhone($worker->mobile);
            $displayNumber = $this->getDisplayablePhone(($worker->mobile));
            $html[] = "<li><a href=\"tel:$telNumber\"><i class=\"pixelcms-icons\">phone_android</i><span>$displayNumber</span></a></li>";
        }
        if ($worker->fax) {
            $telNumber = $this->getCallablePhone($worker->fax);
            $displayNumber = $this->getDisplayablePhone(($worker->fax));
            $html[] = "<li><a href=\"fax:$telNumber\"><i class=\"pixelcms-icons\">print</i><span>$displayNumber</span></a></li>";
        }

        $html[] =  "</ul>";
        return implode("\n", $html);
    }

    private function getCallablePhone($phone)
    {
        return preg_replace([
            '/[\s\/\-]/',
            // '/(\+\s?\d{2})(?:\s?(?:\(0\)|0)\s?)?/',
        ], [
            '',
            '$1',
        ], $phone);
    }

    public function paginate()
    {

    }

    private function getDisplayablePhone($phone)
    {
        return preg_replace([
            //'/(\d)\s(\d)/',
            '/ - /',
            // '/\+\s?\d{2}\s?(?:\s?(?:\(0\)|0)\s?)?/',
        ], [
            //'$1$2',
            ' ',
            // '0',
        ], $phone);
    }

    public function displayDepartment($department) {
        $html[] = '';
        foreach ($department->workers as $worker) {
            $html[] = "<div class='worker worker--col-4 worker--col-2-phone worker--col-3-tablet'>";
            $html[] = $this->displayWorker($worker);
            $html[] = "</div>";
        }
        return implode("\n", $html);
    }

    public function displayPdf($pdf)
    {
        # Todo: Remove in Next Major Update
        $pdfLink = preg_replace('/(^[^\/])/', '/$1', $pdf->link);
        return "<a class='pdf' target='_blank' href='{$this->params->get('pixel_cms_url')}$pdfLink'><img class='pdf__image' src='{$this->params->get('pixel_cms_url')}$pdf->url'><span class='pdf__title'>$pdf->title</span></a>";
    }

    public function displayVideo($video)
    {
        $this->hasVideoPlayer = true;
        if ($video->vendor_id === 2) {
            $this->hasVimeoPlayer = true;
            return "<iframe class='vimeo_player' src=\"https://player.vimeo.com/video/$video->video_id?title=0&byline=0&portrait=0\" width=\"1280\" height=\"720\" frameborder=\"0\" allowfullscreen></iframe>";
        } else if ($video->vendor_id === 3) {
            $uid = bin2hex(random_bytes(3));
            $this->hasFacebookPlayer = true;
            return "<div class=\"facebook_player fb-video\" id='fb-v-$video->video_id-$uid' data-id='fb-v-$video->video_id-$uid' data-href=\"$video->url\" data-allowfullscreen=\"true\" data-width=\"720\"></div>";
        }
        $this->hasYoutubePlayer = true;
        return "<iframe class='youtube_player' src=\"https://www.youtube-nocookie.com/embed/$video->video_id?rel=0&showinfo=0&enablejsapi=1\" width=\"1280\" height=\"720\" frameborder=\"0\" allowfullscreen></iframe>";
    }


	public function getThumbnail($image, int $size = 500, bool $cropped = true): string
	{
	    $url = (is_string($image)) ? $image : $image->url;

	    if (!is_string($image) && $image->is_animated_gif) {
	        return $url;
        }

		return preg_replace('/^(?:\/)?((?!http)(?:(?!thumb).)*)(?:\.\d+)?\.(jpe?g|png|gif)/', ($cropped) ? "$1.$size-cropped.$2" : "$1.$size.$2", $url);
    }

    public function displayGallery($gallery, $showDescription = false)
    {
        $html = [];

        $thumbSize = $this->params->get('pixelcms_images_thumb_size', 500);
        $previewSize = $this->params->get('pixelcms_images_preview_size', 1600);

        $cssClass = ($showDescription) ? 'gallery__item__thumb' : 'gallery__item';

        foreach ($gallery->images as $image) {
            $thumb = $this->getThumbnail($image, $thumbSize);
            $preview = $this->getThumbnail($image, $previewSize, false);

            $elm = ["<a class='js-img $cssClass $cssClass--image img' data-title='$image->title'  href='{$this->params->get('pixel_cms_url')}/$preview' style='background-image: url({$this->params->get('pixel_cms_url')}/$thumb)'></a>"];

            if ($showDescription) {
                $this->renderGalleryItemDesc($elm, $image);
            }

            $html[] = implode('', $elm);
        }
        foreach ($gallery->videos as $video) {
            $elm = ["<div class='$cssClass $cssClass--video' style='background-image: url($video->thumb)'></div>"];

            if ($showDescription) {
                $this->renderGalleryItemDesc($elm, $video);
            }

            $html[] = implode('', $elm);
        }

        return implode('', $html);
    }

    private function renderGalleryItemDesc(array &$elm, $item): void
    {
        $preElm = '<div class="gallery__item gallery__item--desc">';

        $elm[] = '<div class="gallery__item__meta">';
        $elm[] = "<span class='gallery__item__meta__title'>$item->title</span>";
        $elm[] = "<span class='gallery__item__meta__desc'>$item->description</span>";
        $elm[] = "</div>";


        array_unshift($elm, $preElm);
        $elm[] = "</div>";
    }

    public function hasSidebar($sidebar = ['workers','pdfs','files'], $article = null)
    {
        $article = $article ?? $this->article;

        foreach ($sidebar as $attachment) {
            if ($this->hasAttachment($attachment, $article)) return true;
        }
        return false;
    }

    public function hasAttachment($attachment_name, $article = null)
    {
        $article = $article ?? $this->article;
        return isset($article->attachments->{$attachment_name}) && $article->attachments->{$attachment_name};
    }

    public function attachPlayerScripts()
    {
        if (!$this->hasVideoPlayer) {
            return "";
        }
        $html = [];
        $script = ['var play_class = "video--playing";'];
        if ($this->hasVimeoPlayer) {
            $html[] = "<script src='https://player.vimeo.com/api/player.js'></script>";
            $script[] = '
                [].slice.call(document.querySelectorAll(".vimeo_player")).forEach(function (el) {
                    var player = new Vimeo.Player(el);
                
                    player.on(\'play\', function () {
                        el.parentElement.classList.add(play_class);
                    });
                    player.on(\'pause\', function () {
                        el.parentElement.classList.remove(play_class);
                    });
                });
            ';
        }
        if ($this->hasYoutubePlayer) {
            $html[] = "<script src='https://www.youtube.com/iframe_api'></script>";
            $script[] = '
                function onYouTubeIframeAPIReady() {
                    [].slice.call(document.querySelectorAll(".youtube_player")).forEach(function (el) {
                        var player = new YT.Player(el, {
                            events: {
                                onStateChange: function onStateChange(event) {
                                    if (event.data === YT.PlayerState.PLAYING) {
                                        el.parentElement.classList.add(play_class);
                                    } else if (event.data === YT.PlayerState.PAUSED) {
                                        el.parentElement.classList.remove(play_class);
                                    }
                                }
                            }
                        });
                    });
                }
            ';
        }
        if ($this->hasFacebookPlayer) {
            $html[] = "<script src='https://connect.facebook.net/de_DE/sdk.js'></script>";
            $script[] = '
                function fbAsyncInit() {
                    FB.init({
                        appId      : \'922247001285262\',
                        xfbml      : true,
                        version    : \'v2.11\'
                    });

                    FB.Event.subscribe(\'xfbml.ready\', function(msg) {
                        console.log(msg.instance, msg);
                        if (msg.type === \'video\') {
                            msg.instance.subscribe(\'startedPlaying\', function(e) {
                                document.getElementById(msg.id).parentElement.classList.add(play_class);
                            });
                            msg.instance.subscribe(\'paused\', function(e) {
                                document.getElementById(msg.id).parentElement.classList.remove(play_class);
                            });
                            msg.instance.subscribe(\'finishedPlaying\', function(e) {
                                document.getElementById(msg.id).parentElement.classList.remove(play_class);
                            });
                        }
                    });
                };
            ';
        }
        $script = array_map(function($value) {
            return preg_replace('/[\s]{2,}/', '', $value);
        }, $script);
        $html[] = '<script>' . implode("", $script) . '</script>';
        return implode("\n", $html);
    }

    public function displayAttachment($article, $attachment_name)
    {
        // Checks if the attachment is set on the article.
        if (!$this->hasAttachment($attachment_name)) return "";

        $attachment_name_singular = static::$attachments[$attachment_name];
        $attachment_count = count($article->attachments->{$attachment_name} ?? []);

        $html[] = "<div class='article_attachment article_attachment--$attachment_name'>";
        // $html[] = "<pre>". print_r($article->attachments->{$attachment_name}, true) ."</pre>";

        foreach ($article->attachments->{$attachment_name} as $attachment) {
            $html[] = "<div class='{$attachment_name_singular}'>";
            if ($attachment_name === 'pdfs') {
                $html[] = $this->displayPdf($attachment);
            } else if ($attachment_name === 'galleries') {
                if ($attachment_count > 1) {
                    $html[] = "<h3 class='{$attachment_name_singular}__headline'>$attachment->title</h3>";
                }
                $html[] = "<div class='{$attachment_name_singular}__body'>";
                $html[] = $this->displayGallery($attachment, $this->params->get('show_gallery_desc', false));
                $html[] = "</div>";
            } else if ($attachment_name === 'videos') {
                $html[] = $this->displayVideo($attachment);
            } else if ($attachment_name === 'files') {
                $html[] = $this->displayFile($attachment);
            } else if ($attachment_name === 'workers') {
                $html[] = $this->displayWorker($attachment);
            } else if ($attachment_name === 'departments') {
                if ($attachment_count > 1) {
                    $html[] = "<h3 class='{$attachment_name_singular}__headline'>$attachment->title</h3>";
                }
                $html[] = "<div class='{$attachment_name_singular}__body'>";
                $html[] = $this->displayDepartment($attachment);
                $html[] = "</div>";
            }
            $html[] = "</div>";
        }
        $html[] = "</div>";
        return implode('', $html);
    }

    public function getContainerClass(): string
    {
        $viewName = $this->getName();

        $classList[] = "$viewName-wrapper";
        if ($this->params->get('is_module')) {
            $classList[] = 'mod_cms-wrapper';
            $classList[] = "$viewName-mod-wrapper";
        }

        return implode(' ', $classList);
    }

	function display($tpl = null)
	{
		// Assign data to the view
        $articleData = $this->get('Article');

        $this->article = isset($articleData->data) ? $articleData->data : $articleData;
        if (isset($articleData->data)) {
            $this->pagination = (object) [
                'current_page' => (int) $articleData->current_page,
                'per_page' => (int) $articleData->per_page,
                'total' => (int) $articleData->total,
                'last_page' => ceil($articleData->total / $articleData->per_page),
            ];
        }

        $this->category = $this->get('Category');
		$this->params = $this->get('state')->get('params');

		if (gettype($this->article) === 'object' && $this->params->get('force_list', false)) {
		    $this->article = [$this->article];
		    $this->params->set('show_archiv', false);
        }

        if (gettype($this->article) === 'array') {
            $tpl = 'listing';
        } else if (gettype($this->article) === 'object') {
            $this->article->content = nl2br($this->article->content);
            $this->templateClass = 'tmpl-' . self::templates[$this->article->template];
        }

        $document = JFactory::getDocument();
        $document->addStyleSheet(JURI::base(true) . '/media/com_pixelcms_articles/css/fonts.css', [
            'version' => md5_file(JPATH_BASE . '/media/com_pixelcms_articles/css/fonts.css'),
        ]);
        $document->addStyleSheet(JURI::base(true) . '/media/com_pixelcms_articles/css/style.css', [
            'version' => md5_file(JPATH_BASE . '/media/com_pixelcms_articles/css/style.css'),
        ]);
        $document->addScript(JURI::base(true) . '/media/com_pixelcms_articles/js/script.js', [
            'version' => md5_file(JPATH_BASE . '/media/com_pixelcms_articles/js/script.js'),
        ]);

        // Erster Artikel Vollständig wenn gewünscht
        if (is_array($this->article) && $this->params->get('first_article_full') && (!$this->pagination || $this->pagination && $this->pagination->current_page === 1)) {
            $tempArticles = $this->article;

            $this->article =  array_shift($tempArticles);
            $this->article->title = $this->params->get('page_title');
            $this->article->content = nl2br($this->article->content);
            $this->templateClass = 'tmpl-' . self::templates[$this->article->template];

            // Wenn als Modul eingebunden blende ersten Artikel aus.
            // TODO: Vlt. das auch konfigurierbar machen?
            if (!$this->params->get('is_module', false)) {
                parent::display(null);
            }

            $this->params->set('page_title', sprintf($this->params->get('page_subtitle', 'Weiteres aus %s'), $this->params->get('page_title')));

            $this->article = $tempArticles;

            if (count($this->article ?? []) === 0) return;
        }

        parent::display($tpl);
    }

    public function paginationLink($page, $disabled, $title = null, $active = false)
    {
        $title = $title ?? $page;

        $link = JRoute::_("index.php?Itemid=$this->item_id&page=$page");

        $html[] = '<li class="page-item'. ($disabled ? " disabled" : "") . ($active ? " active" : "") . '">';
        $html[] = '<a class="page-link" href="'.$link.'">' .$title. '</a>';
        $html[] = '</li>';

        return implode('', $html);
    }
}
