<?php

class SimpleTags_Client
{
    /**
     * Initialize TaxoPress client
     *
     * @return boolean
     */
    public function __construct()
    {

        // Load translation
        add_action('init', array( __CLASS__, 'init_translation' ));

        // Enqueue frontend scripts
        add_action('wp_enqueue_scripts', array( $this, 'enqueue_displayformat_scripts' ), 999);

        require(STAGS_DIR . '/inc/class.client.autolinks.php');
        new SimpleTags_Client_Autolinks();

        // Call tag clouds ?
        if (1 === (int) SimpleTags_Plugin::get_option_value('active_terms_display')) {
            require_once STAGS_DIR . '/inc/tag-clouds-action.php';
        }

        // Call post tags ?
        if (1 === (int) SimpleTags_Plugin::get_option_value('active_post_tags')) {
            require_once STAGS_DIR . '/inc/post-tags-action.php';
        }

        // Call related posts ?
        if ((int) SimpleTags_Plugin::get_option_value('active_related_posts_new') === 1) {
            require_once STAGS_DIR . '/inc/related-posts-action.php';
        }
        if ((int) SimpleTags_Plugin::get_option_value('active_related_posts_new') === 1) {
            require(STAGS_DIR . '/inc/class.client.related_posts.php');
            new SimpleTags_Client_RelatedPosts();
        }

        // Call auto terms ?
        require(STAGS_DIR . '/inc/class.client.autoterms.php');
        new SimpleTags_Client_Autoterms();

        // Call post tags ?
        require(STAGS_DIR . '/inc/class.client.post_tags.php');
        new SimpleTags_Client_PostTags();


        if ((int)SimpleTags_Plugin::get_option_value('active_taxonomies') === 1) {
            require_once STAGS_DIR . '/inc/taxonomies-action.php';
            add_action('parse_query', array( __CLASS__, 'cpt_taxonomy_parse_query' ));
            if (defined('STAGS_OPTIONS_NAME')) {
                $saved_option = (array)get_option(STAGS_OPTIONS_NAME);
                if ((array_key_exists('use_tag_pages', $saved_option))) {
                    if ((int)$saved_option['use_tag_pages'] === 1) {
                        if (!array_key_exists('post_tag', taxopress_get_extername_taxonomy_data())) {
                            add_action('init', array( __CLASS__, 'init' ), 11);
                            add_action('parse_query', array( __CLASS__, 'parse_query' ));
                        }
                    }
                }
            }
        }

        return true;
    }

    public function enqueue_displayformat_scripts()
    {

        if ((int) SimpleTags_Plugin::get_option_value('disable_frontend_scripts') === 1) {
            return;
        }

        if (! apply_filters('taxopress_load_frontend_scripts', true)) {
            return;
        }

        wp_register_script('taxopress-frontend-js', STAGS_URL . '/assets/frontend/js/frontend.js', array('jquery'), STAGS_VERSION);
        wp_register_style('taxopress-frontend-css', STAGS_URL . '/assets/frontend/css/frontend.css', array(), STAGS_VERSION, 'all');

        wp_enqueue_script('taxopress-frontend-js');
        wp_enqueue_style('taxopress-frontend-css');

    }


    /**
     * Retrieves the currently queried object.
     *
     * Wrapper for WP_Query::get_queried_object().
     *
     * @since 3.1.0
     *
     * @global WP_Query $wp_query WordPress Query object.
     *
     * @return WP_Term|WP_Post_Type|WP_Post|WP_User|null The queried object.
     */
    public static function taxopress_get_queried_object()
    {
        global $wp_query;

        if (!is_object($wp_query)) {
            return null;
        }

        return $wp_query->get_queried_object();
    }

    /**
     * Add cpt to taxonomy during the query
     *
     * @param WP_Query $query
     *
     * @return void
     * @author Olatechpro
     */
    public static function cpt_taxonomy_parse_query($query)
    {
        if (function_exists('get_current_screen')) {
            $screen = get_current_screen();
        }

        if (is_admin()) {
            return $query;
        }
        if (isset($screen->id) && $screen->id == 'edit-post') {
            return $query;
        }
        if ($query->is_category == true || $query->is_tag == true || $query->is_tax == true) {
            $get_queried_object = self::taxopress_get_queried_object();
            if (is_object($get_queried_object)) {
                if (!isset($get_queried_object->taxonomy)) {
                    return $query;
                }
                if (!taxopress_show_all_cpt_in_archive_result($get_queried_object->taxonomy)) {
                    return $query;
                }
                $get_taxonomy = get_taxonomy($get_queried_object->taxonomy);
                if (is_object($get_taxonomy)) {
                    $post_types = $get_taxonomy->object_type;
                    if (isset($query->query_vars['post_type'])) {
                        if (is_array($query->query_vars['post_type'])) {
                            $post_types = array_filter(array_merge($query->query_vars['post_type'], $post_types));
                        } elseif (is_string($query->query_vars['post_type'])) {
                            $original_post_type = $query->query_vars['post_type'];
                            $get_post_type_object = get_post_type_object($original_post_type);
                            if (is_object($get_post_type_object)) {
                                if ((int)$get_post_type_object->public === 0) {
                                    return $query;
                                }
                            }
                            $post_types[] = $query->query_vars['post_type'];
                        }
                        $new_post_object = $post_types;
                    } else {
                        $new_post_object = $post_types;
                    }
                    $query->query_vars['post_type'] = $new_post_object;
                }
            }
        }
        return $query;
    }

    /**
     * Load translations
     */
    public static function init_translation()
    {
        load_plugin_textdomain('simple-tags', false, basename(STAGS_DIR) . '/languages');
    }

    /**
     * Register taxonomy post_tags for page post type
     *
     * @return void
     * @author WebFactory Ltd
     */
    public static function init()
    {
        register_taxonomy_for_object_type('post_tag', 'page');
    }

    /**
     * Add page post type during the query
     *
     * @param WP_Query $query
     *
     * @return void
     * @author WebFactory Ltd
     */
    public static function parse_query($query)
    {
        if (function_exists('get_current_screen')) {
            $screen = get_current_screen();
        }

        if (isset($screen->id) && $screen->id == 'edit-post') {
            return $query;
        }

        if ($query->is_tag == true) {
            if (isset($query->query_vars['post_type']) && is_array($query->query_vars['post_type'])) {
                $query->query_vars['post_type'][] = 'page';
            } else {
                $query->query_vars['post_type'] = array( 'post', 'page' );
            }
        }
    }

    /**
     * Randomize an array and keep association
     *
     * @param array $array
     *
     * @return boolean
     */
    public static function random_array(&$array)
    {
        if (! is_array($array) || empty($array)) {
            return false;
        }

        $keys = array_keys($array);
        shuffle($keys);

        $new = array();
        foreach ((array) $keys as $key) {
            $new[ $key ] = $array[ $key ];
        }

        $array = $new;

        return true;
    }

    /**
     * Build rel for tag link
     *
     * @return string
     */
    public static function get_rel_attribut()
    {
        global $wp_rewrite;
        $rel = (is_object($wp_rewrite) && $wp_rewrite->using_permalinks()) ? 'tag' : ''; // Tag ?
        if (! empty($rel)) {
            $rel = 'rel="' . $rel . '"'; // Add HTML Tag
        }

        return $rel;
    }

    /**
     * Retrieve the post count for a term across all taxonomies.
     *
     * This function queries terms based on the given term name and returns the number of posts associated with the first matching term.
     * It does not require specifying a taxonomy and will search across all public taxonomies.
     *
     * @param string $item
     * @return int The number of posts associated with the first matching term. Returns 0 if no term is found or if it has no posts.
     */
    public static function get_term_post_counts($item)
    {

        $terms = get_terms(array(
            'name' => strip_tags($item),
            'hide_empty' => false,
            'fields' => 'all',
            'number' => 1,
            ));

        // If terms exist, return the first matching term's count
        if (! empty($terms) && ! is_wp_error($terms)) {
            return $terms[0]->count;
        }

        return 0;
    }

    /**
     * Format data for output
     *
     * @param string $html_class
     * @param string $format
     * @param string $title
     * @param string|array $content
     * @param boolean $copyright
     * @param string $separator
     *
     * @return string|array
     */
    public static function output_content($html_class = '', $format = 'list', $title = '', $content = '', $copyright = true, $separator = '', $div_class = '', $a_class = '', $before = '', $after = '', $taxonomy = '')
    {
        if (empty($content)) {
            return ''; // return nothing
        }

        if ($format == 'array' && is_array($content)) {
            return $content; // Return PHP array if format is array
        }

        $title = taxopress_sanitize_text_field($title);

        if (is_array($content)) {
            switch ($format) {
                case 'list':
                    $output = ''. $before .' <ul class="' . $html_class . '">' . "\n\t" . '<li>' . implode("</li>\n\t<li>", $content) . "</li>\n</ul> {$after}\n";
                    break;
                case 'ol':
                    $output = ''. $before .' <ol class="' . $html_class . '">' . "\n\t" . '<li>' . implode("</li>\n\t<li>", $content) . "</li>\n</ol> {$after}\n";
                    break;
                case 'comma':
                    $output = ''. ''. ''. ''. $before .  implode($separator, $content) . " {$after}\n";
                    break;
                case 'table':
                    $output = $before . '<table class="' . $html_class . ' taxopress-table-container">' . "\n\t";
                    $count = 0;
                    foreach ($content as $item) {

                        // If $item is an array, use its fields
                        if (is_array($item) && isset($item['html'], $item['count'])) {
                            $term_html = $item['html'];
                            $post_count = $item['count'];
                        } else {
                            // fallback for legacy
                            $term_html = $item;
                            $post_count = self::get_term_post_counts(strip_tags($item));
                        }

                        // if ( $post_count === 0 ) {
                        // 	continue;
                        // }

                        $display_class = $count >= 6 ? 'hidden' : '';
                        $output .= '<tr class="taxopress-table-row ' . $display_class . '"><td>' . $term_html . '</td><td class="taxopress-post-count">' . $post_count . '</td></tr>' . "\n\t";
                        $count++;
                    }
                    if ($count > 6) {
                        $output .= '<tr><td class="taxopress-see-more-container" colspan="2">';
                        $output .= '<span class="taxopress-see-more-link">see more <span class="taxopress-arrow right"></span></span>';
                        $output .= '<span class="taxopress-close-table-link">close table <span class="taxopress-arrow down"></span></span>';
                        $output .= '</td></tr>' . "\n";
                    }
                    $output .= "</table>" . $after . "\n";
                    break;
                case 'border':
                    $output = '<div class="taxopress-border-cloud ' . $html_class . '">'. $before .' ' . "\n\t" . implode("{$separator}\n", $content) . " {$after}</div>\n";
                    break;
                case 'box':
                    $output = '<div class="taxopress-box-list ' . $html_class . '">'. $before .' ' . "\n\t" . implode("{$separator}\n", $content) . " {$after}</div>\n";
                    break;
                case 'parent/child':
                    $output = $before . '<ul class="' . $html_class . ' taxopress-parent-child-list">' . "\n";

                    // Cache term hierarchy to avoid repeated queries
                    static $term_hierarchy = [];
                    $cache_key = md5($taxonomy . serialize($content));

                    if (!isset($term_hierarchy[$cache_key])) {
                        $terms_by_parent = [];
                        $all_terms = [];

                        $term_names = array_map(function ($term_html) {
                            return strip_tags($term_html);
                        }, array_filter($content, 'trim'));

                        if (!empty($term_names)) {
                            $terms = get_terms([
                                'taxonomy' => $taxonomy,
                                'name' => $term_names,
                                'hide_empty' => false,
                                'update_term_meta_cache' => false
                            ]);

                            if (!is_wp_error($terms)) {
                                foreach ($terms as $term) {
                                    $all_terms[$term->term_id] = [
                                        'term' => $term,
                                        'html' => $content[array_search($term->name, $term_names)],
                                        'is_parent' => false
                                    ];

                                    $parent_id = $term->parent ?: '0';
                                    $terms_by_parent[$parent_id][] = $term->term_id;
                                }

                                foreach ($terms_by_parent as $child_ids) {
                                    foreach ($child_ids as $child_id) {
                                        if (isset($terms_by_parent[$child_id])) {
                                            $all_terms[$child_id]['is_parent'] = true;
                                        }
                                    }
                                }
                            }
                        }

                        $term_hierarchy[$cache_key] = [
                            'terms' => $all_terms,
                            'hierarchy' => $terms_by_parent
                        ];
                    }

                    // Use cached hierarchy
                    $data = $term_hierarchy[$cache_key];
                    $all_terms = $data['terms'];
                    $terms_by_parent = $data['hierarchy'];

                    // Group terms by parent
                    $terms_by_parent = [];
                    $all_terms = [];

                    // First pass - collect all terms
                    foreach ($content as $term_html) {
                        if (empty(trim($term_html))) {
                            continue;
                        }

                        $term_name = strip_tags($term_html);
                        $term = get_term_by('name', $term_name, $taxonomy);

                        if (!$term) {
                            continue;
                        }

                        // Store term for reference
                        $all_terms[$term->term_id] = [
                            'term' => $term,
                            'html' => $term_html,
                            'is_parent' => false
                        ];

                        $parent_id = $term->parent ?: '0';
                        if (!isset($terms_by_parent[$parent_id])) {
                            $terms_by_parent[$parent_id] = [];
                        }
                        $terms_by_parent[$parent_id][] = $term->term_id;
                    }

                    foreach ($terms_by_parent as $parent_id => $children) {
                        foreach ($children as $child_id) {
                            if (isset($terms_by_parent[$child_id])) {
                                $all_terms[$child_id]['is_parent'] = true;
                            }
                        }
                    }

                    $output_term = function ($term_id, $level = 0) use (&$output_term, &$all_terms, &$terms_by_parent) {
                        if (!isset($all_terms[$term_id])) {
                            return '';
                        }

                        $term_data = $all_terms[$term_id];
                        $html = str_repeat("\t", $level);
                        $html .= '<li class="taxopress-parent-term">' . $term_data['html'];

                        if (isset($terms_by_parent[$term_id])) {
                            $html .= "\n" . str_repeat("\t", $level + 1);
                            $html .= '<ul class="taxopress-child-list">' . "\n";
                            foreach ($terms_by_parent[$term_id] as $child_id) {
                                $html .= $output_term($child_id, $level + 2);
                            }
                            $html .= str_repeat("\t", $level + 1) . "</ul>\n";
                        }

                        $html .= str_repeat("\t", $level) . "</li>\n";
                        return $html;
                    };
                    $display_mode = isset($current['display_mode']) ? $current['display_mode'] : 'parents_and_sub';

                    if ($display_mode === 'parents_only') {
                        foreach ($all_terms as $term_id => $term_data) {
                            if ($term_data['is_parent']) {
                                $output .= '<li class="taxopress-parent-term">' . $term_data['html'] . "</li>\n";
                            }
                        }
                    } elseif ($display_mode === 'sub_terms_only') {
                        foreach ($all_terms as $term_id => $term_data) {
                            if ($term_data['term']->parent > 0) {
                                $output .= '<li class="taxopress-child-term">' . $term_data['html'] . "</li>\n";
                            }
                        }
                    } else {
                        // Display full hierarchy
                        // Start with root terms or terms whose parents aren't in our set
                        foreach ($all_terms as $term_id => $term_data) {
                            $term = $term_data['term'];
                            if ($term->parent === 0 || !isset($all_terms[$term->parent])) {
                                $output .= $output_term($term_id);
                            }
                        }
                    }

                    $output .= "</ul>" . $after . "\n";
                    return $output;
                    break;
                default:
                    $output = '<div class="' . $html_class . '">'. $before .' ' . "\n\t" . implode("{$separator}\n", $content) . " {$after}</div>\n";
                    break;
            }
        } else {
            $content = trim($content);
            switch ($format) {
                case 'string':
                    $output = $content;
                    break;
                case 'list':
                    $output = ''. $before .' <ul class="' . $html_class . '">' . "\n\t" . '<li>' . $content . "</li>\n\t" . "</ul> {$after}\n";
                    break;
                case 'comma':
                    $output = ''. ''. ''. ''. $before . $content . " {$after}\n";
                    break;
                case 'table':
                    $output = $before . '<table class="' . $html_class . '">' . "\n\t"
                        . '<tr><td>' . $content . '</td></tr>' . "\n\t"
                        . "</table>" . $after . "\n";
                    break;
                case 'border':
                    $output = '<div class="taxopress-border-cloud ' . $html_class . '">'. $before .' ' . "\n\t" . $content . " {$after} </div>\n";
                    break;
                case 'box':
                    $output = '<div class="taxopress-box-list ' . $html_class . '">'. $before .' ' . "\n\t" . $content . " {$after} </div>\n";
                    break;
                case 'parent/child':
                    $output = $before . '<ul class="' . esc_attr($html_class) . ' taxopress-parent-child-list">' . "\n";
                    $lines = explode("\n", $content);
                    $inside_sublist = false;

                    foreach ($lines as $line) {
                        $line = trim($line);
                        if (empty($line)) {
                            continue;
                        }

                        if (strpos($line, 'taxopress-parent-term') !== false) {
                            if ($inside_sublist) {
                                $output .= "</ul></li>\n";
                                $inside_sublist = false;
                            }

                            $output .= '<li class="parent-item" style="list-style-type: disc; color: black;">' . $line;

                            $output .= "\n<ul class=\"child-items\" style=\"list-style-type: circle; color: black;\">\n";
                            $inside_sublist = true;
                        } else {
                            $output .= '<li class="child-item">' . $line . "</li>\n";
                        }
                    }

                    // Close any open tags
                    if ($inside_sublist) {
                        $output .= "</ul></li>\n";
                    }

                    $output .= "</ul>" . $after . "\n";
                    break;
                default:
                    $output = '<div class="' . $html_class . '">'. $before .' ' . "\n\t" . $content . " {$after} </div>\n";
                    break;
            }
        }

        //wrap class
        if (!empty(trim($div_class))) {
            $wrap_div_class_open = '<div class="'.taxopress_format_class($div_class).'">';
            $wrap_div_class_close = '</div>';
        } else {
            $wrap_div_class_open = '<div class="taxopress-output-wrapper"> ';
            $wrap_div_class_close = '</div>';
        }
        // Replace false by empty
        $title = trim($title);
        if (strtolower($title) == 'false') {
            $title = '';
        }

        // Put title if exist
        if (! empty($title)) {
            $title .= "\n\t";
        }

        if ($copyright === true) {
            return "\n" . '<!-- Generated by TaxoPress ' . STAGS_VERSION . ' - https://wordpress.org/plugins/simple-tags/ -->' . "\n\t" . $wrap_div_class_open . $title . $output . $wrap_div_class_close . "\n";
        } else {
            return "\n\t" . $wrap_div_class_open . $title . $output . $wrap_div_class_close . "\n";
        }
    }

    /**
     * Remplace marker by dynamic values (use for related tags, current tags and tag cloud)
     *
     * @param string $element_loop
     * @param object $term
     * @param string $rel
     * @param integer $scale_result
     * @param integer $scale_max
     * @param integer $scale_min
     * @param integer $largest
     * @param integer $smallest
     * @param string $unit
     * @param string $maxcolor
     * @param string $mincolor
     *
     * @return string
     */
    public static function format_internal_tag($element_loop = '', $term = null, $rel = '', $scale_result = 0, $scale_max = null, $scale_min = 0, $largest = 0, $smallest = 0, $unit = '', $maxcolor = '', $mincolor = '')
    {
        // Need term object
        $tag_link = get_term_link($term, $term->taxonomy);
        $element_loop = str_replace('%tag_link%', esc_url($tag_link), $element_loop);
        $element_loop = str_replace('%tag_feed%', esc_url(get_term_feed_link($term->term_id, $term->taxonomy, '')), $element_loop);

        $element_loop = str_replace('%tag_name%', esc_html($term->name), $element_loop);
        $element_loop = str_replace('%tag_name_attribute%', esc_html(strip_tags($term->name)), $element_loop);
        $element_loop = str_replace('%tag_id%', $term->term_id, $element_loop);
        $element_loop = str_replace('%tag_count%', (int) $term->count, $element_loop);
        $element_loop = str_replace('%tag_description%', esc_html($term->description), $element_loop);

        // Need rel
        $element_loop = str_replace('%tag_rel%', $rel, $element_loop);

        // Need max/min/scale and other :)
        if ($scale_result !== null) {
            $scale_result = (int) $scale_result;
            $scale_min = (int) $scale_min;
            $scale_max = (int) $scale_max;
            $largest = (int) $largest;
            $smallest = (int) $smallest;

            $element_loop = str_replace('%tag_size%', 'font-size:' . self::round(($scale_result - $scale_min) * ($largest - $smallest) / ($scale_max - $scale_min) + $smallest, 2) . $unit . ';', $element_loop);
            $element_loop = str_replace('%tag_color%', 'color:' . self::get_color_by_scale(self::round(($scale_result - $scale_min) * (100) / ($scale_max - $scale_min), 2), $mincolor, $maxcolor) . ';', $element_loop);
            $element_loop = str_replace('%tag_scale%', $scale_result, $element_loop);
        }

        // External link
        $element_loop = str_replace('%tag_technorati%', self::format_external_tag('technorati', $term->name), $element_loop);
        $element_loop = str_replace('%tag_flickr%', self::format_external_tag('flickr', $term->name), $element_loop);
        $element_loop = str_replace('%tag_delicious%', self::format_external_tag('delicious', $term->name), $element_loop);

        return $element_loop;
    }

    /**
     * This is pretty filthy. Doing math in hex is much too weird. It's more likely to work, this way!
     * Provided from UTW. Thanks.
     *
     * @param integer $scale_color
     * @param string $min_color
     * @param string $max_color
     *
     * @return string
     */
    public static function get_color_by_scale($scale_color, $min_color, $max_color)
    {
        $scale_color = $scale_color / 100;

        $minr = hexdec(substr($min_color, 1, 2));
        $ming = hexdec(substr($min_color, 3, 2));
        $minb = hexdec(substr($min_color, 5, 2));

        $maxr = hexdec(substr($max_color, 1, 2));
        $maxg = hexdec(substr($max_color, 3, 2));
        $maxb = hexdec(substr($max_color, 5, 2));

        $r = dechex(intval((($maxr - $minr) * $scale_color) + $minr));
        $g = dechex(intval((($maxg - $ming) * $scale_color) + $ming));
        $b = dechex(intval((($maxb - $minb) * $scale_color) + $minb));

        if (strlen($r) == 1) {
            $r = '0' . $r;
        }
        if (strlen($g) == 1) {
            $g = '0' . $g;
        }
        if (strlen($b) == 1) {
            $b = '0' . $b;
        }

        return '#' . $r . $g . $b;
    }

    /**
     * Extend the round PHP public static function for force a dot for all locales instead the comma.
     *
     * @param string $value
     * @param string $approximation
     *
     * @return float
     * @author WebFactory Ltd
     */
    public static function round($value, $approximation)
    {
        $value = round($value, $approximation);
        $value = str_replace(',', '.', $value); // Fixes locale comma
        $value = str_replace(' ', '', $value); // No space

        return $value;
    }

    /**
     * Format nice URL depending service
     *
     * @param string $type
     * @param string $term_name
     *
     * @return string
     */
    public static function format_external_tag($type = '', $term_name = '')
    {
        if (empty($term_name)) {
            return '';
        }

        $term_name = esc_html($term_name);
        switch ($type) {
            case 'technorati':
                return '<a class="tag_technorati" href="' . esc_url('http://technorati.com/tag/' . str_replace(' ', '+', $term_name)) . '" rel="tag">' . $term_name . '</a>';
                break;
            case 'flickr':
                return '<a class="tag_flickr" href="' . esc_url('http://www.flickr.com/photos/tags/' . preg_replace('/[^a-zA-Z0-9]/', '', strtolower($term_name)) . '/') . '" rel="tag">' . $term_name . '</a>';
                break;
            case 'delicious':
                return '<a class="tag_delicious" href="' . esc_url('http://del.icio.us/popular/' . strtolower(str_replace(' ', '', $term_name))) . '" rel="tag">' . $term_name . '</a>';
                break;
            default:
                return '';
                break;
        }
    }
}
