<?php
/*
    VC maps module
*/
namespace vc;

if( ! defined( 'ABSPATH' ) ) exit;

new maps;
class maps {

    /*
        General constructor
    */
    public function __construct() {
        
        if (!is_admin()) {
            // render Google Maps
            add_action( 'wp_enqueue_scripts', array($this, 'load_scripts'), 99 );
            add_shortcode( 'vc_maps', array($this, 'maps_sc') );
        }
        else if (helper::is_active_plugin('js_composer/js_composer.php')) {
            // Google Maps modul
            add_action( 'vc_before_init', array($this, 'maps_vc') );
            add_action( 'admin_init', array($this, 'mod_vc') );
        }

    }

    /* visual composer */
    public function maps_vc() {
    
        vc_map(array(
            "name"          => __('Google Maps', 'core'),
            "description"   => __('Darstellung von Standorten in einer Google Maps Karte.', 'core'),
            "base"          => "vc_maps",
            "category"      => __('Inhalt', 'core'),
            "icon"          => get_template_directory_uri()."/assets/icon/location.svg",
            "params"        => self::get_params(false)
        ) );

    }

    /**
     * Get all maps vc params
     * 
     * @param bool $embeded Whether these params are embedded inside post overview
     * 
     * @return array
     */
    public static function get_params( $embeded=true ) {
        $group = $group_filter ="";
        $dependency_basic = array();
        $dependency_pt = $dependency_filter = array(
            'element' => 'pt',
            'not_empty' => true
        );
        if ($embeded) {
            // inside post overview
            $group = __('Google Maps', 'core');
            $group_filter = __('Filter', 'core');
            $dependency_basic = $dependency_pt = array(
                'element' => 'enable_map',
                'value' => 'show'
            );

        }
        $pre = "filter_";
        return array_merge(
            $embeded ? array(
                array(
                    "type"        => 'seperator',
                    "heading"     => __('Google Maps', 'core'),
                    "param_name"  => 'seperator_maps',
                    'dependency'  => array(
                        'element' => 'pt',
                        'not_empty' => true
                    ),
                    'group'       => $group,
                    "weight"      => 4,
                ),
                array(
                    'type'        => 'checkbox',
                    'heading'     => __('Google Maps', 'core'),
                    'param_name'  => 'enable_map',
                    'value'       => array( __('aktivieren', 'core') => 'show' ),
                    'admin_label' => true,
                    'edit_field_class' => 'vc_col-xs-10',
                    'dependency'  => array(
                        'element' => 'pt',
                        'not_empty' => true
                    ),
                    'group'       => $group,
                    "weight"      => 4,
                )
            ) : array(),
            array(
                // api key
                array(
                    "type"        => "textfield",
                    "heading"     => __('Google Maps API Key', 'core'),
                    "description" => __('Ohne gültigen Key wird der Entwicklungsmodus von Google Maps verwendet', 'core'),
                    "param_name"  => "key",
                    "value"       => "",
                    'edit_field_class' => 'vc_col-xs-8',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                    "weight"      => 4,
                ),
                // posttype
                array(
                    "type"        => 'new_line',
                    "param_name"  => 'new_line_posttype',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                    "weight"      => 4,
                )
            ),
            !$embeded ? array(
                array(
                    'type'        => 'select',
                    'heading'     => __('Post Type', 'core'),
                    'param_name'  => 'pt',
                    'options'     => array(),
                    'admin_label' => true,
                    'edit_field_class' => 'vc_col-xs-3',
                    'group'       => $group,
                    "weight"      => 4,
                ),
            ) : array(),
            // -> inject dropdowns for lat lon per pt
            self::filter_params_vc($group_filter, $pre, $dependency_filter),
            array(
                // layout
                array(
                    "type"        => 'seperator',
                    "heading"     => __('Layout', 'core'),
                    "param_name"  => 'seperator_layout',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                )
            ),
            $embeded ? array(
                array(
                    "type"        => "dropdown",
                    "heading"     => __('Position', 'core'),
                    "param_name"  => "position",
                    "value"       => array(
                        _x('oben', 'small', 'core') => 'top',
                        _x('unten', 'small', 'core') => 'bottom',
                    ),
                    'edit_field_class' => 'vc_col-xs-3',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                )
            ) : array(),
            array(
                array(
                    "type"        => "textfield",
                    "heading"     => __('Höhe', 'core'),
                    'description' => __('in px', 'core'),
                    "param_name"  => "height",
                    "value"       => "715px",
                    'edit_field_class' => 'vc_col-xs-3',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                ),
                array(
                    "type"        => "textfield",
                    "heading"     => __('Höhe Mobil', 'core').' <u>'.__('(bis 767px)', 'core').'</u>',
                    'description' => __('in px', 'core'),
                    "param_name"  => "height_mobile",
                    "value"       => "315px",
                    'edit_field_class' => 'vc_col-xs-3',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                ),
                array(
                    "type"        => "textfield",
                    "heading"     => __('Abstand darunter', 'core'),
                    'description' => __('in px', 'core'),
                    "param_name"  => "margin_bottom",
                    "value"       => "30px",
                    'edit_field_class' => 'vc_col-xs-3',
                    'dependency'  => $dependency_basic,
                    'group'       => $group,
                ),

                // infobox
                array(
                    "type"        => 'seperator',
                    "heading"     => __('Infobox', 'core'),
                    "param_name"  => 'seperator_box',
                    'dependency'  => $dependency_pt,
                    'group'       => $group,
                ),
                // pin
                array(
                    'type'          => 'file_picker',
                    'heading'       => __( 'Pin', 'core' ),
                    'param_name'    => 'icon',
                    'filetype'      => array('image'),
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                ),
                // header/title
                array(
                    "type"          => "textarea",
                    "heading"       => __('Titel', 'core'),
                    "param_name"    => "header_content",
                    "value"         => "",
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                ),
                array(
                    "type"          => "colorselect",
                    "heading"       => __('Titel Schriftfarbe', 'core'),
                    "param_name"    => "header_text_colorselect",
                    'edit_field_class' => 'vc_col-xs-6',
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                ),
                array(
                    "type"          => "colorselect",
                    "heading"       => __('Titel Hintergrundfarbe', 'core'),
                    "param_name"    => "header_background_colorselect",
                    'edit_field_class' => 'vc_col-xs-6',
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                ),
                // content
                array(
                    "type"          => "textarea",
                    "heading"       => __('Inhalt', 'core'),
                    "param_name"    => "body_content",
                    "value"         => "",
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                ),
                array(
                    "type"          => "colorselect",
                    "heading"       => __('Schriftfarbe', 'core'),
                    "param_name"    => "body_text_colorselect",
                    'edit_field_class' => 'vc_col-xs-6',
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                ),
                array(
                    "type"          => "colorselect",
                    "heading"       => __('Hintergrundfarbe', 'core'),
                    "param_name"    => "body_background_colorselect",
                    'edit_field_class' => 'vc_col-xs-6',
                    'dependency'    => $dependency_pt,
                    'group'         => $group,
                )
            )
        );
    }
    public static function filter_params_vc($group='', $pre="", $dependency=[]) {
        return array_merge(
            array(
                // filter
                array(
                    "type"        => 'seperator',
                    "heading"     => __('Filter', 'core'),
                    "param_name"  => 'seperator_filter',
                    'dependency'  => $dependency,
                    'group'       => $group,
                    "weight"      => 8,
                ),
                // -> inject dropdowns for filter per pt
                // filter frontend
                array(
                    'type'        => 'checkbox',
                    'heading'     => __('Dropdown im Frontend', 'core'),
                    'description' => __('nur aktiv wenn eine Filtermöglichkeit gesetzt ist.', 'core'),
                    'param_name'  => $pre.'dropdown_frontend',
                    'value'       => array( __('aktivieren', 'core') => 'show' ),
                    'edit_field_class' => 'vc_col-xs-12',
                    'dependency'  => $dependency,
                    'group'       => $group,
                ),
                array(
                    'type'        => 'dropdown',
                    'heading'     => __('Dropdown Position', 'core'),
                    'param_name'  => $pre.'position',
                    'value'       => array(
                        _x('Links oben', 'small', 'core') => 'flex-start top',
                        _x('Mitte oben', 'small', 'core') => 'center top',
                        _x('Rechts oben', 'small', 'core') => 'flex-end top',
                        _x('Links unten', 'small', 'core') => 'flex-start bottom',
                        _x('Mitte unten', 'small', 'core') => 'center bottom',
                        _x('Rechts unten', 'small', 'core') => 'flex-end bottom',
                    ),
                    'edit_field_class' => 'vc_col-xs-3',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    'group'       => $group,
                ),
                array(
                    "type"        => "dropdown",
                    "heading"     => __('Darstellung', 'core'),
                    "param_name"  => $pre."style",
                    "value"       => array(
                        _x('primäres Feld', 'small', 'core') => '_input',
                        _x('sekundäres Feld', 'small', 'core') => "_input _sec",
                        _x('individuell überschreiben', 'small', 'core') => "custom",
                    ),
                    'edit_field_class' => 'vc_col-xs-3 vc_clearleft',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    'group'       => $group,
                ),
                array(
                    'type'        => 'textfield',
                    'heading'     => __('Breite', 'core'),
                    'description' => __('in px oder %', 'core'),
                    'param_name'  => $pre.'width',
                    'edit_field_class' => 'vc_col-xs-2',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    'group'       => $group,
                ),
                array(
                    'type'        => 'textfield',
                    'heading'     => __('Abstand', 'core').' <u>'.__('darüber', 'core').'</u>',
                    'description' => __('in px', 'core'),
                    'param_name'  => $pre.'margin_top',
                    'value'       => '30px',
                    'edit_field_class' => 'vc_col-xs-2',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    "group"       => $group,
                ),
                array(
                    'type'        => 'textfield',
                    'heading'     => __('Abstand', 'core').' <u>'.__('darunter', 'core').'</u>',
                    'description' => __('in px', 'core'),
                    'param_name'  => $pre.'margin_bottom',
                    'value'       => '30px',
                    'edit_field_class' => 'vc_col-xs-2',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    "group"       => $group,
                ),
                array(
                    "type"        => 'new_line',
                    "param_name"  => $pre.'new_line_after_margin',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    'group'       => $group,
                ),
            ),
            helper::custom_element_params_vc($pre, $pre.'style', 'custom', $group),
            array(
                array(
                    "type"        => 'sub_seperator',
                    "heading"     => __('Individuelle Bezeichnungen', 'core'),
                    // 'description' => __('Gib hier individuelle Namen für die Sortierungsoptionen ein', 'core'),
                    "param_name"  => $pre."individual_names",
                    'edit_field_class' => 'vc_col-xs-12',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    'group'       => $group,
                ),
                array(
                    'type'        => 'textfield',
                    'heading'     => __('Alle anzeigen', 'core'),
                    'param_name'  => $pre.'text_all',
                    'value'       => __('Alle anzeigen', 'core'),
                    'edit_field_class' => 'vc_col-xs-6',
                    'dependency'  => array(
                        'element' => $pre.'dropdown_frontend',
                        'value' => 'show',
                    ),
                    'group'       => $group,
                ),
            )
        );
    }

    /* modify params */
    public function mod_vc() {

        // get post objects
        $posttypes = helper::get_all_posttypes();
        $all_posttypes = $all_fields = $all_taxonomies = $all_terms = array();
        foreach ($posttypes as $posttype) {
            if ($posttype->count > 0) {
                $slug = $posttype->slug;
                if ($slug != 'page') {
                    // posttype
                    $title = $posttype->title." (".$posttype->count.")";
                    $all_posttypes[$title] = $slug;
                    // fields for lat lon
                    $all_fields[$slug] = array();
                    $pt = helper::get_dynamic_posttype_by_slug($slug);
                    if ($pt && isset($pt["fields"])) {
                        // Custom Fields
                        $fields = (array) $pt["fields"];
                        // debug($fields);
                        if (count($fields) > 0) {
                            foreach ($fields as $field) {
                                $field = (array)$field;
                                $all_fields[$slug][$field["label"]] = $field["name"];
                            }

                        }
                    }
                    // taxes for filter
                    $all_taxonomies[$slug] = array();
                    $cat = helper::get_category_slug($slug);
                    if ($cat) $all_taxonomies[$slug][__('Kategorie', 'core')] = $cat;
                    $tag = helper::get_tag_slug($slug);
                    if ($tag) $all_taxonomies[$slug][__('Schlagwort', 'core')] = $tag;
                    $taxes = helper::get_custom_taxonomies($slug);
                    if ($taxes) {
                        foreach ($taxes as $tax_slug => $tax_title) 
                            $all_taxonomies[$slug][$tax_title] = $tax_slug;
                    }
                    // terms for filter
                    foreach ($all_taxonomies[$slug] as $tax_slug) {
                        $all_terms[$tax_slug] = array();
                        foreach (helper::get_all_terms($tax_slug) as $term)
                            $all_terms[$tax_slug][$term->title." (".$term->count.")"] = $term->id;
                    }
                }
            }
        }

        // debug(array(
        //     'all_posttypes' => $all_posttypes,
        //     'all_fields' => $all_fields,
        //     'all_taxonomies' => $all_taxonomies,
        //     'all_terms' => $all_terms,
        // ));

        foreach (array('vc_posts_overview', 'vc_maps') as $shortcode) {

            $group = $group_filter = '';
            $default = array( _x('bitte auswählen', 'small', 'core') => "" );

            if ($shortcode == 'vc_posts_overview') {
                $group = __('Google Maps', 'core');
                $group_filter = __('Filter', 'core');
                // add maps and filter params to post overview module
                vc_add_params('vc_posts_overview', self::get_params(true));
            }
            else {
                // extend maps module
                $map = \WPBMap::getShortCode( $shortcode );
                // add all posttypes to dropdown
                foreach ((array) $map['params'] as $params) {
                    if ($params['param_name'] == 'pt') {
                        $params['options'] = array( 'default' => array_merge($default, $all_posttypes));
                        vc_update_shortcode_param( $shortcode, $params );
                    }
                }
            }

            // add fields dropdowns for lat lon
            foreach ($all_fields as $pt => $fields) {
                vc_add_params($shortcode, array(
                    array(
                        "type"        => 'dropdown',
                        "heading"     => __('Latitude', 'core'),
                        "param_name"  => $pt.'_lat',
                        'edit_field_class' => 'vc_col-xs-3',
                        "value" 	  => array_merge($default, $fields),
                        'dependency'  => array(
                            'element' => 'pt',
                            'value' => array($pt)
                        ),
                        'group'       => $group,
                        "weight"        => 3,
                    ),
                    array(
                        "type"        => 'dropdown',
                        "heading"     => __('Longitude', 'core'),
                        "param_name"  => $pt.'_lon',
                        'edit_field_class' => 'vc_col-xs-3',
                        "value" 	  => array_merge($default, $fields),
                        'dependency'  => array(
                            'element' => 'pt',
                            'value' => array($pt)
                        ),
                        'group'       => $group,
                        "weight"        => 3,
                    ),
                ));
            }
        
            // add tax dropdown for filter
            foreach ($all_taxonomies as $pt => $taxes) {
                $all_taxes = array( _x('kein Filter', 'small', 'core') => "" );
                // add term dropdown for tax filter
                foreach ($taxes as $tax_title => $tax) {
                    $all_taxes[$tax_title." (".count($all_terms[$tax]).")"] = $tax;
                    if (isset($all_terms[$tax]) && count($all_terms[$tax]) > 0) {
                        vc_add_params($shortcode, array(
                            array(
                                "type"        => 'dropdown',
                                "heading"     => __('Initialer Filter', 'core'),
                                "param_name"  => $tax.'_initial',
                                'edit_field_class' => 'vc_col-xs-3',
                                "value" 	  => array_merge(array( _x('alle', 'small', 'core') => "" ), $all_terms[$tax]),
                                'dependency'  => array(
                                    'element' => $pt.'_filter',
                                    'value' => array($tax)
                                ),
                                'group'       => $group_filter,
                                "weight"        => 1,
                            ),
                        ));

                    }
                }
                // debug($all_taxes);
                vc_add_params($shortcode, array(
                    array(
                        "type"        => 'dropdown',
                        "heading"     => __('Filtermöglichkeit nach', 'core'),
                        "param_name"  => $pt.'_filter',
                        'edit_field_class' => 'vc_col-xs-3',
                        "value" 	  => $all_taxes,
                        'dependency'  => array(
                            'element' => 'pt',
                            'value' => array($pt)
                        ),
                        'group'       => $group_filter,
                        "weight"        => 2,
                    ),
                ));
            }
            
        }

    }

    /* rendering */

    /* enqueue */
    public function load_scripts() {

		if ( defined( 'GREYD_ENABLE_MAPS' ) && constant( 'GREYD_ENABLE_MAPS' ) ) {
			// enable this feature...
		} else if ( is_greyd_blocks() ) {
			return;
		}

        /**
         * Fix fatal error on VC pages after dynamic modularisation.
         */
        // if (check_enqueue(['vc_maps', "vc_posts_overview"])) {
            /* style */
            wp_process_style('default_style', get_template_directory().'/inc/vc/maps/assets/maps.css');
            /* javascript */
            wp_register_script("maps_js_default", get_template_directory_uri().'/inc/vc/maps/assets/maps.js', array('jquery'), '1.0', false);
            wp_enqueue_script("maps_js_default");
        // }
    }

    /* shortcode */
    public static function maps_sc($atts=[], $content='') {
        // debug($atts);

        // get data
        $is_embeded  = is_array($content); // embeded in post overview
        $loc_slug    = isset($atts['pt']) ? esc_attr($atts['pt']) : '';
        $loc_lat     = isset($atts[$loc_slug.'_lat']) ? esc_attr($atts[$loc_slug.'_lat']) : 'lat';
        $loc_lon     = isset($atts[$loc_slug.'_lon']) ? esc_attr($atts[$loc_slug.'_lon']) : 'lon';
        $loc_filter  = isset($atts[$loc_slug.'_filter']) ? esc_attr($atts[$loc_slug.'_filter']) : '';
        $loc_initial = isset($atts[$loc_filter.'_initial']) ? intval($atts[$loc_filter.'_initial']) : -1;

        // get locations
        $locations = array();
        $location_links = array();
        if ($loc_slug != '') {
            // either from $content or get_posts
            $locs = ($is_embeded) ? $content : get_posts(array(
                'numberposts'       => -1,
                'post_type'         => $loc_slug,
                'post_status'       => 'publish',
                'suppress_filters'  => false,
            ));
            if ($locs) foreach ($locs as $loc) {
                // debug($loc);
                $tags = helper::get_dynamic_posttype_tags($loc);
                if (isset($tags[$loc_lat]) && isset($tags[$loc_lon])) {
                    // get terms for filtering
                    $terms = array();
                    if ($loc_filter != "") {
                        $loc_terms = get_the_terms($loc->ID, $loc_filter);
                        if ( $loc_terms && is_array($loc_terms) ) {
                            foreach ($loc_terms as $term) {
                                array_push($terms, $term->term_id);
                            }
                        }
                    }
                    // make location object
                    $location = array(
                        "ID" => $loc->ID,
                        "title" => $loc->post_title,
                        "lat" => $tags[$loc_lat], "lon" => $tags[$loc_lon],
                        "filter" => $terms,
                        "content" => self::makeContent($atts, array(
                            "ID" => $loc->ID, "lat" => $loc_lat, "lon" => $loc_lon, "blank" => true
                        ), $tags)
                    );
                    array_push($locations, $location);
                    array_push($location_links, "<a onclick='map.open_marker(".$loc->ID.")'>".$loc->post_title."</a>"); // debug
                }
            }

        }

        // filter dropdown
        $style = '';
        $select = '';
        if ($loc_filter != "" && !$is_embeded) {
            // debug($loc_filter);
            $pre = "filter_";
            $dropdown = self::makeFilterDropdown($atts, $pre);
            $style = $dropdown["style"];
            $select = $dropdown["content"];
            $sel_position = explode(' ', isset($atts[$pre.'position']) ? esc_attr($atts[$pre.'position']) : "flex-start top");
        }

        // infobox colors
        $txt_color = helper::process_color(helper::get_color($atts, 'body_text_', '', 'color_21'));
        $bg_color = helper::process_color(helper::get_color($atts, 'body_background_', '', 'color_62'));
        $header_txt_color = helper::process_color(helper::get_color($atts, 'header_text_', '', $txt_color));
        $header_bg_color = helper::process_color(helper::get_color($atts, 'header_background_', '', $bg_color));

        // styles
        $height = isset($atts['height']) ? helper::force_units($atts['height'], ['px'], 'px') : '715px';
        $margin_bottom = isset($atts['margin_bottom']) ? helper::force_units($atts['margin_bottom'], ['px'], 'px') : '30px';
        $height_mobile = isset($atts['height_mobile']) ? helper::force_units($atts['height_mobile'], ['px'], 'px') : '315px';

        $id = "gMap_".uniqid();
        $style .= "#".$id." { height: ".$height."; margin-bottom: ".$margin_bottom."; } ";
        $style .= "#".$id." .infoBox { color: ".$txt_color."; background: ".$bg_color."; } ";
        $style .= "#".$id." .infoBox:after { border-right-color: ".$bg_color."; } ";
        $style .= "#".$id." .infoBox .header { color: ".$header_txt_color."; background: ".$header_bg_color."; } ";
        // $style .= "#".$id." .infoBox .header .close { color: ".$header_bg_color."; background: ".$header_txt_color."; } ";
        $style .= "@media (max-width: var(grid_md)) { #".$id." { height: ".$height_mobile."; } } ";

        // icons for pin and cluster
        $icon       = isset($atts['icon']) ? esc_attr($atts['icon']) : -1;
        $pin        = is_numeric($icon) && $icon != -1 ? wp_get_attachment_url($icon) : "";
        $cluster    = get_template_directory_uri().'/inc/vc/maps/assets/icons/m';

        // make data
        $key = isset($atts['key']) ? esc_attr($atts['key']) : '';
        $data = "data-locations='".rawurlencode(json_encode($locations))."' data-filter='".$loc_initial."' data-pin='".$pin."' data-cluster='".$cluster."'";

        // render
        ob_start();
            // styles
            \enqueue::add_custom_style($style);
            // scripts
            echo '<script src="https://maps.googleapis.com/maps/api/js?key='.$key.'&callback=maps_init"></script>';
            echo '<script src="'.get_template_directory_uri().'/inc/vc/maps/assets/maps_infobox.js"></script>';
            echo '<script src="'.get_template_directory_uri().'/inc/vc/maps/assets/maps_markerclusterer.js"></script>';
            // filter top
            if ($select != "" && $sel_position[1] == 'top') echo $select;
            // map
            echo "<div id='".$id."' class='gMaps' ".$data."></div>";
            // filter bottom
            if ($select != "" && $sel_position[1] == 'bottom') echo $select;
            // location links for debugging
            // echo '<div style="margin: 30px 0">'.implode('<br>', $location_links).'</div>';
        $return = ob_get_contents();
        ob_end_clean();

        return $return;
    }

    /* infoBox */
	public static function makeContent($atts, $location, $tags) {
        // get header and body
        // debug(htmlspecialchars($atts["header_content"]));
        // debug(htmlspecialchars($atts["body_content"]));
        $header  = isset($atts['header_content']) ? $atts['header_content'] : '_title_';
        $content = isset($atts['body_content']) ? $atts['body_content'] : '<a href="_route_">Route</a>';
        // render
		$return =   '<div class="content">
                        <div class="header">
                            <div class="title">'.$header.'</div>
                            <div class="close" onclick="map.infoBox.close();">✕</div>
                        </div>
                        <div>'.$content.'</div>
                    </div>';

        // trim and prepare
        $return = preg_replace('/\s+/', ' ', $return);
        $return = str_replace(array('<p>', '</p>', "'"), array("", "<br><br>", '"'), $return);
        // match tags
        $post = get_post($location["ID"]);
        $return = self::match_tags($post, $location, $return);
        if ( method_exists( '\Greyd\Dynamic\Render', 'match_tags' ) ) {
            $return = \Greyd\Dynamic\Render::match_tags($post, $tags, $return);
            $return = \Greyd\Dynamic\Render::match_tags($post, \Greyd\Dynamic\Dynamic_Helper::get_dynamic_tags('single'), $return);
        } else if ( method_exists( '\dynamic', 'match_tags' ) ) {
            $return = \dynamic::match_tags($post, $tags, $return);
            $return = \dynamic::match_tags($post, helper::get_dynamic_tags('single'), $return);
        }

        return $return;
	}

    /* dynamic tags */
    public static function match_tags($post, $location, $content) {
        $content = str_replace('_route_', self::makeRouteLink($post, $location), $content);
        $content = str_replace('_focus_', self::makeFocusLink($post, $location), $content);
        return $content;
    }
    public static function makeRouteLink($post, $location) {
        $target = (isset($location['blank']) && $location['blank']) ? '" target="_blank' : '';
        return 'http://maps.google.com/maps?daddr=_'.$location['lat'].'_,_'.$location['lon'].'_&maptype=roadmap'.$target;
    }
    public static function makeFocusLink($post, $location) {
        return 'javascript:map.open_marker('.$post->ID.')';
    }

    /* filter */
    public static function makeFilterDropdown($atts, $pre) {
        
        $loc_slug    = isset($atts['pt']) ? esc_attr($atts['pt']) : '';
        $loc_filter  = isset($atts[$loc_slug.'_filter']) ? esc_attr($atts[$loc_slug.'_filter']) : '';
        $loc_initial = isset($atts[$loc_filter.'_initial']) ? intval($atts[$loc_filter.'_initial']) : -1;

        $style = '';
        $select = '';
        if (isset($atts[$pre.'dropdown_frontend']) && $atts[$pre.'dropdown_frontend'] === 'show' ) {
            // get dropdown data
            $sel_id = $pre.uniqid();
            $sel_width          = isset($atts[$pre.'width']) ? helper::force_units( esc_attr($atts[$pre.'width']), ['px','%'] ) : "300px";
            $sel_margin_top     = isset($atts[$pre.'margin_top']) ? helper::force_units( esc_attr($atts[$pre.'margin_top']), ['px','%'] ) : "30px";
            $sel_margin_bottom  = isset($atts[$pre.'margin_bottom']) ? helper::force_units( esc_attr($atts[$pre.'margin_bottom']), ['px','%'] ) : "30px";
            $sel_class          = isset($atts[$pre.'style']) ? str_replace( array("_input", "_"), "", esc_attr($atts[$pre.'style']) ) : "";
            $sel_inline_style   = $sel_class === 'custom' ? "style='".helper::make_custom_element($atts, $pre)."'" : "";
            $sel_position       = explode(' ', isset($atts[$pre.'position']) ? esc_attr($atts[$pre.'position']) : "flex-start top");
            $sel_align          = isset($sel_position[0]) ? esc_attr($sel_position[0]) : "";
            $sel_text_all       = isset($atts[$pre.'text_all']) ? $atts[$pre.'text_all']  : __('Alle anzeigen', 'core');
            // get dropdown options
            $opts = '';
            foreach (helper::get_all_terms($loc_filter) as $opt) {
                $selected = ($opt->id === $loc_initial) ? 'selected="selected"' : '';
                $opts .= '<option value="'.$opt->id.'" '.$selected.'>'.$opt->title.'</option>';
            }
            if ($opts != '') {
                // dropdown styles
                $style .= "#".$sel_id." { display: flex; justify-content: ".$sel_align."; } "; 
                $style .= "#".$sel_id." .custom-select { max-width: ".$sel_width."; } "; 
                $style .= "#".$sel_id." .custom-select { margin-top: ".$sel_margin_top."; } "; 
                $style .= "#".$sel_id." .custom-select { margin-bottom: ".$sel_margin_bottom."; } "; 
                $style .= "@media (max-width: var(grid_sm)) { #".$sel_id." .custom-select { max-width: 100%; } } "; 
                // render dropdown
                $select =   '<div id="'.$sel_id.'"><div class="custom-select '.$sel_class.'">
                                <select '.$sel_inline_style.'>
                                    <option value="-1">'.$sel_text_all.'</option>
                                    '.$opts.'
                                </select>
                            </div></div>';
            }
        }

        return array(
            "style" => $style, 
            "content" => $select
        );
    }
}
