<?php
if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly.
}

/**
 * VC KIT Shortcode Interactive Grid class.
 *
 * @since 1.0
 * @package Visual Composer KIT
 */

class Vckit_Shortcode_Grid extends Vckit_Shortcode_Base {

  /**
   * Grid
   *
   * @var String
   * @since  1.0
   */
  protected $grid = null;

  /**
   * Grid params
   *
   * @var Array
   * @since 1.0
   */
  protected $basicGrid;

  /**
   * @see WPBakeryShortCode_VC_Basic_Grid
   */
  public $post_id;
  public $excluded_ids = array();
  protected static $default_max_items = 1000;

  /**
   * Constructor
   *
   * @since  1.0
   * @param  VCAddonsKIT $plugin Main plugin object.
   * @return void
   */
  public function __construct( $plugin ) {
    $this->shortcode = 'vckit_grid_' . $this->grid;
    parent::__construct( $plugin );
  }

  /**
   * Initial Shortcode
   *
   * @since 2.0
   */
  public function init() {

    // Check shortcode enabled
    $enabled = vckit_get_option( $this->shortcode );
    $enabled = is_null( $enabled ) ? $this->default_enabled : $enabled;

    if ( $enabled ) {
      // Register CSS and JS
      add_action( 'template_redirect', array( $this, 'registerScripts' ) );
      // Maps
      if ( ! is_admin() ) {
        add_action( 'vc_before_init', array( $this, 'maps' ) );
      } else {
        add_action( 'admin_init', array( $this, 'maps' ), 20 );
      }

      if ( $this->shortcode && ! shortcode_exists( $this->shortcode ) ) {
        add_shortcode( $this->shortcode, array( $this, 'renderShortcode' ) );
      }
    }
  }

  /**
   * Hooks
   *
   * @since  1.0
   * @return void
   */
  function hooks() {
    parent::hooks();

    /**
     * Handle ajax
     * @see config/lean-map.php
     */
    add_filter(
      'vc_autocomplete_' . $this->shortcode . '_taxonomies_callback',
      array( $this, 'autocomplete_taxonomies_field_search' ),
      10,
      1
    );
    add_filter(
      'vc_autocomplete_' . $this->shortcode . '_include_callback',
      array( $this, 'include_field_search' ),
      10,
      1
    );
    add_filter(
      'vc_autocomplete_' . $this->shortcode . '_exclude_callback',
      array( $this, 'exclude_field_search' ),
      10,
      1
    );
  }

  public function getGridColsList() {
    return array(
      array(
        'label' => '6',
        'value' => 2,
      ),
      array(
        'label' => '4',
        'value' => 3,
      ),
      array(
        'label' => '3',
        'value' => 4,
      ),
      array(
        'label' => '2',
        'value' => 6,
      ),
      array(
        'label' => '1',
        'value' => 12,
      ),
    );
  }

  public function getPostTypeList() {
    $postTypes = get_post_types( array() );
    $postTypesList = array();
    $excludedPostTypes = array(
      'revision',
      'nav_menu_item',
      'vc_grid_item',
      'wpcf7_contact_form',
    );
    if ( is_array( $postTypes ) && ! empty( $postTypes ) ) {
      foreach ( $postTypes as $postType ) {
        if ( ! in_array( $postType, $excludedPostTypes ) ) {
          $label = ucfirst( $postType );
          $postTypesList[] = array(
            $postType,
            $label,
          );
        }
      }
    }

    return $postTypesList;
  }

  /**
   * Common
   *
   * @see js_composer/config/grids/class-vc-grids-common.php
   */
  public function getBasicAtts() {
    if ( $this->basicGrid ) {
      return $this->basicGrid;
    }

    $postTypesList = $this->getPostTypeList();

    $postTypesList[] = array(
      'custom',
      __( 'Custom query', 'legocreative' ),
    );
    $postTypesList[] = array(
      'ids',
      __( 'List of IDs', 'legocreative' ),
    );

    $taxonomiesForFilter = array();

    if ( 'vc_edit_form' === vc_post_param( 'action' ) ) {
      $vcTaxonomiesTypes = vc_taxonomies_types();
      if ( is_array( $vcTaxonomiesTypes ) && ! empty( $vcTaxonomiesTypes ) ) {
        foreach ( $vcTaxonomiesTypes as $t => $data ) {
          if ( 'post_format' !== $t && is_object( $data ) ) {
            $taxonomiesForFilter[ $data->labels->name . '(' . $t . ')' ] = $t;
          }
        }
      }
    }

    $this->basicGrid = array(
      array(
        'type' => 'dropdown',
        'heading' => __( 'Data source', 'legocreative' ),
        'param_name' => 'post_type',
        'value' => $postTypesList,
        'save_always' => true,
        'description' => __( 'Select content type for your grid.', 'legocreative' ),
        'admin_label' => true,
      ),
      array(
        'type' => 'autocomplete',
        'heading' => __( 'Include only', 'legocreative' ),
        'param_name' => 'include',
        'description' => __( 'Add posts, pages, etc. by title.', 'legocreative' ),
        'settings' => array(
          'multiple' => true,
          'sortable' => true,
          'groups' => true,
        ),
        'dependency' => array(
          'element' => 'post_type',
          'value' => array( 'ids' ),
        ),
      ),
      // Custom query tab
      array(
        'type' => 'textarea_safe',
        'heading' => __( 'Custom query', 'legocreative' ),
        'param_name' => 'custom_query',
        'description' => __( 'Build custom query according to <a href="http://codex.wordpress.org/Function_Reference/query_posts">WordPress Codex</a>.', 'legocreative' ),
        'dependency' => array(
          'element' => 'post_type',
          'value' => array( 'custom' ),
        ),
      ),
      array(
        'type' => 'attach_images',
        'heading' => __( 'Images', 'legocreative' ),
        'param_name' => 'grid_images',
        'dependency' => array(
          'element' => 'post_type',
          'value' => array( 'media' ),
        ),
      ),
      array(
        'type' => 'autocomplete',
        'heading' => __( 'Narrow data source', 'legocreative' ),
        'param_name' => 'taxonomies',
        'settings' => array(
          'multiple' => true,
          'min_length' => 1,
          'groups' => true,
          // In UI show results grouped by groups, default false
          'unique_values' => true,
          // In UI show results except selected. NB! You should manually check values in backend, default false
          'display_inline' => true,
          // In UI show results inline view, default false (each value in own line)
          'delay' => 500,
          // delay for search. default 500
          'auto_focus' => true,
          // auto focus input, default true
        ),
        'param_holder_class' => 'vc_not-for-custom',
        'description' => __( 'Enter categories, tags or custom taxonomies.', 'legocreative' ),
        'dependency' => array(
          'element' => 'post_type',
          'value_not_equal_to' => array(
            'ids',
            'custom',
            'media',
          ),
        ),
      ),
      array(
        'type' => 'textfield',
        'heading' => __( 'Total items', 'legocreative' ),
        'param_name' => 'max_items',
        'value' => 50,
        // default value
        'param_holder_class' => 'vc_not-for-custom',
        'description' => __( 'Set max limit for items in grid or enter -1 to display all (limited to 1000).', 'legocreative' ),
        'dependency' => array(
          'element' => 'post_type',
          'value_not_equal_to' => array(
            'ids',
            'custom',
            'media',
          ),
        ),
      ),
      array(
        'type' => 'dropdown',
        'heading' => __( 'Grid elements per row', 'legocreative' ),
        'param_name' => 'element_width',
        'value' => $this->getGridColsList(),
        'std' => '4',
        'edit_field_class' => 'vc_col-sm-6',
        'description' => __( 'Select number of elements per row.', 'legocreative' ),
      ),
      array(
        'type' => 'dropdown',
        'heading' => __( 'Gap', 'legocreative' ),
        'param_name' => 'gap',
        'value' => array(
          '0px' => '0',
          '1px' => '1',
          '2px' => '2',
          '3px' => '3',
          '4px' => '4',
          '5px' => '5',
          '10px' => '10',
          '15px' => '15',
          '20px' => '20',
          '25px' => '25',
          '30px' => '30',
          '35px' => '35',
        ),
        'std' => '30',
        'description' => __( 'Select gap between grid elements.', 'legocreative' ),
        'edit_field_class' => 'vc_col-sm-6',
      ),
      // Data settings
      array(
        'type' => 'dropdown',
        'heading' => __( 'Order by', 'legocreative' ),
        'param_name' => 'orderby',
        'value' => array(
          __( 'Date', 'legocreative' ) => 'date',
          __( 'Order by post ID', 'legocreative' ) => 'ID',
          __( 'Author', 'legocreative' ) => 'author',
          __( 'Title', 'legocreative' ) => 'title',
          __( 'Last modified date', 'legocreative' ) => 'modified',
          __( 'Post/page parent ID', 'legocreative' ) => 'parent',
          __( 'Number of comments', 'legocreative' ) => 'comment_count',
          __( 'Menu order/Page Order', 'legocreative' ) => 'menu_order',
          __( 'Meta value', 'legocreative' ) => 'meta_value',
          __( 'Meta value number', 'legocreative' ) => 'meta_value_num',
          __( 'Random order', 'legocreative' ) => 'rand',
        ),
        'description' => __( 'Select order type. If "Meta value" or "Meta value Number" is chosen then meta key is required.', 'legocreative' ),
        'group' => __( 'Data Settings', 'legocreative' ),
        'param_holder_class' => 'vc_grid-data-type-not-ids',
        'dependency' => array(
          'element' => 'post_type',
          'value_not_equal_to' => array(
            'ids',
            'custom',
            'media',
          ),
        ),
      ),
      array(
        'type' => 'dropdown',
        'heading' => __( 'Sort order', 'legocreative' ),
        'param_name' => 'order',
        'group' => __( 'Data Settings', 'legocreative' ),
        'value' => array(
          __( 'Descending', 'legocreative' ) => 'DESC',
          __( 'Ascending', 'legocreative' ) => 'ASC',
        ),
        'param_holder_class' => 'vc_grid-data-type-not-ids',
        'description' => __( 'Select sorting order.', 'legocreative' ),
        'dependency' => array(
          'element' => 'post_type',
          'value_not_equal_to' => array(
            'ids',
            'custom',
            'media',
          ),
        ),
      ),
      array(
        'type' => 'textfield',
        'heading' => __( 'Meta key', 'legocreative' ),
        'param_name' => 'meta_key',
        'description' => __( 'Input meta key for grid ordering.', 'legocreative' ),
        'group' => __( 'Data Settings', 'legocreative' ),
        'param_holder_class' => 'vc_grid-data-type-not-ids',
        'dependency' => array(
          'element' => 'orderby',
          'value' => array(
            'meta_value',
            'meta_value_num',
          ),
        ),
      ),
      //array(
        //'type' => 'textfield',
        //'heading' => __( 'Offset', 'legocreative' ),
        //'param_name' => 'offset',
        //'description' => __( 'Number of grid elements to displace or pass over.', 'legocreative' ),
        //'group' => __( 'Data Settings', 'legocreative' ),
        //'param_holder_class' => 'vc_grid-data-type-not-ids',
        //'dependency' => array(
          //'element' => 'post_type',
          //'value_not_equal_to' => array(
            //'ids',
            //'custom',
            // 'media',
          //),
        //),
      //),
      array(
        'type' => 'autocomplete',
        'heading' => __( 'Exclude', 'legocreative' ),
        'param_name' => 'exclude',
        'description' => __( 'Exclude posts, pages, etc. by title.', 'legocreative' ),
        'group' => __( 'Data Settings', 'legocreative' ),
        'settings' => array(
          'multiple' => true,
        ),
        'param_holder_class' => 'vc_grid-data-type-not-ids',
        'dependency' => array(
          'element' => 'post_type',
          'value_not_equal_to' => array(
            'ids',
            'custom',
            'media',
          ),
          'callback' => 'vc_grid_exclude_dependency_callback',
        ),
      ),
      array(
        'type' => 'vckit_id',
        'param_name' => 'grid_id',
      ),
      array(
        'type' => 'textfield',
        'heading' => __( 'Extra class name', 'legocreative' ),
        'param_name' => 'el_class',
        'description' => __( 'Style particular content element differently - add a class name and refer to it in custom CSS.', 'legocreative' ),
      ),
      array(
        'type' => 'css_editor',
        'heading' => __( 'CSS box', 'legocreative' ),
        'param_name' => 'css',
        'group' => __( 'Design Options', 'legocreative' ),
      ),
    );

    $this->basicGrid = array_merge( $this->basicGrid );

    return $this->basicGrid;
  }

  /**
   * Autocomplete taxonomies search
   * @see config/grids/vc-grids-functions.php
   *
   * @param $search_string
   *
   * @return array|bool
   */
  function autocomplete_taxonomies_field_search( $search_string ) {
    $data = array();
    $vc_filter_by = vc_post_param( 'vc_filter_by', '' );
    $vc_taxonomies_types = strlen( $vc_filter_by ) > 0 ? array( $vc_filter_by ) : array_keys( vc_taxonomies_types() );
    $vc_taxonomies = get_terms( $vc_taxonomies_types, array(
      'hide_empty' => false,
      'search' => $search_string,
    ) );
    if ( is_array( $vc_taxonomies ) && ! empty( $vc_taxonomies ) ) {
      foreach ( $vc_taxonomies as $t ) {
        if ( is_object( $t ) ) {
          $data[] = vc_get_term_object( $t );
        }
      }
    }

    return $data;
  }

  /**
   * @param $search_string
   *
   * @return array
   *
   * @see config/grids/vc-grids-functions.php
   */
  function include_field_search( $search_string ) {
    $query = $search_string;
    $data = array();
    $args = array(
      's' => $query,
      'post_type' => 'any',
    );
    $args['vc_search_by_title_only'] = true;
    $args['numberposts'] = - 1;
    if ( 0 === strlen( $args['s'] ) ) {
      unset( $args['s'] );
    }
    add_filter( 'posts_search', 'vc_search_by_title_only', 500, 2 );
    $posts = get_posts( $args );
    if ( is_array( $posts ) && ! empty( $posts ) ) {
      foreach ( $posts as $post ) {
        $data[] = array(
          'value' => $post->ID,
          'label' => $post->post_title,
          'group' => $post->post_type,
        );
      }
    }

    return $data;
  }

  public function postID() {
    if ( false == $this->post_id ) {
      $this->post_id = get_the_ID();
    }

    return $this->post_id;
  }

  public function addExcludedId( $id ) {
    $this->excluded_ids[] = $id;
  }

  public function excludedIds() {
    return $this->excluded_ids;
  }

  /**
   * @param $data_arr
   *
   * @return array
   */
  function exclude_field_search( $data_arr ) {
    $query = isset( $data_arr['query'] ) ? $data_arr['query'] : null;
    $term = isset( $data_arr['term'] ) ? $data_arr['term'] : '';
    $data = array();
    $args = ! empty( $query ) ? array(
      's' => $term,
      'post_type' => $query,
    ) : array(
      's' => $term,
      'post_type' => 'any',
    );
    $args['vc_search_by_title_only'] = true;
    $args['numberposts'] = - 1;
    if ( 0 === strlen( $args['s'] ) ) {
      unset( $args['s'] );
    }
    add_filter( 'posts_search', 'vckit_search_by_title_only', 500, 2 );
    $posts = get_posts( $args );
    if ( is_array( $posts ) && ! empty( $posts ) ) {
      foreach ( $posts as $post ) {
        $data[] = array(
          'value' => $post->ID,
          'label' => $post->post_title,
          'group' => $post->post_type,
        );
      }
    }

    return $data;
  }

  // TODO: setter & getter to attributes
  // @see js_composer/include/classes/shortcodes/vc-basic-grid.php
  public function buildQuery( $atts ) {
    // Set include & exclude
    if ( 'ids' !== $atts['post_type'] && ! empty( $atts['exclude'] ) ) {
      $atts['exclude'] .= ',' . implode( ',', $this->excludedIds() );
    } else {
      $atts['exclude'] = implode( ',', $this->excludedIds() );
    }

    $query_items = $atts['max_items'] > 0 ? $atts['max_items'] : apply_filters( 'vckit_grid_max_items', self::$default_max_items );

    if ( ! isset( $atts['orderby'] ) ) {
      $atts['orderby'] = 'date';
    }

    if ( ! isset( $atts['order'] ) ) {
      $atts['order'] = 'DESC';
    }

    if ( 'ids' === $atts['post_type'] ) {

      if ( empty( $atts['include'] ) ) {
        $atts['include'] = - 1;
      } elseif ( ! empty( $atts['exclude'] ) ) {
        $include = array_map( 'trim', explode( ',', $atts['include'] ) );
        $exclude = array_map( 'trim', explode( ',', $atts['exclude'] ) );
        $diff = array_diff( $include, $exclude );
        $atts['include'] = implode( ', ', $diff );
      }

      $settings = array(
        'include' => $atts['include'],
        'posts_per_page' => $query_items,
        // 'offset' => $atts['query_offset'],
        'post_type' => 'any',
        'orderby' => 'post__in',
      );

    } else if ( 'media' === $atts['post_type'] ) {

      if ( empty( $atts['grid_images'] ) ) {
        $atts['grid_images'] = - 1;
      }

      $settings = array(
        'include' => $atts['grid_images'],
        'post_type' => 'attachment',
        'orderby' => 'post__in',
      );

    } else {

      $settings = array(
        'posts_per_page' => $query_items,
        // 'offset' => $atts['query_offset'],
        'orderby' => $atts['orderby'],
        'order' => $atts['order'],
        'meta_key' => in_array( $atts['orderby'], array(
          'meta_value',
          'meta_value_num',
        ) ) ? $atts['meta_key'] : '',
        'post_type' => $atts['post_type'],
        'exclude' => $atts['exclude'],
      );

      if ( ! empty( $atts['taxonomies'] ) ) {
        $vc_taxonomies_types = get_taxonomies( array(
          'public' => true,
        ) );
        $terms = get_terms( array_keys( $vc_taxonomies_types ), array(
          'hide_empty' => false,
          'include' => $atts['taxonomies'],
        ) );
        $settings['tax_query'] = array();
        $tax_queries = array(); // List of taxnonimes
        foreach ( $terms as $t ) {
          if ( ! isset( $tax_queries[ $t->taxonomy ] ) ) {
            $tax_queries[ $t->taxonomy ] = array(
              'taxonomy' => $t->taxonomy,
              'field' => 'id',
              'terms' => array( $t->term_id ),
              'relation' => 'IN',
            );
          } else {
            $tax_queries[ $t->taxonomy ]['terms'][] = $t->term_id;
          }
        }
        $settings['tax_query'] = array_values( $tax_queries );
        $settings['tax_query']['relation'] = 'OR';
      }
    } // End if().

    return $settings;
  }

  public function filterQuerySettings( $args ) {
    $defaults = array(
      'numberposts' => 5,
      'offset' => 0,
      'category' => 0,
      'orderby' => 'date',
      'order' => 'DESC',
      'include' => array(),
      'exclude' => array(),
      'meta_key' => '',
      'meta_value' => '',
      'post_type' => 'post',
      'suppress_filters' => apply_filters( 'vckit_grid_filter_query_suppress_filters', true ),
      'public' => true,
    );

    $r = wp_parse_args( $args, $defaults );
    if ( empty( $r['post_status'] ) ) {
      $r['post_status'] = ( 'attachment' === $r['post_type'] ) ? 'inherit' : 'publish';
    }
    if ( ! empty( $r['numberposts'] ) && empty( $r['posts_per_page'] ) ) {
      $r['posts_per_page'] = $r['numberposts'];
    }
    if ( ! empty( $r['category'] ) ) {
      $r['cat'] = $r['category'];
    }
    if ( ! empty( $r['include'] ) ) {
      $incposts = wp_parse_id_list( $r['include'] );
      $r['posts_per_page'] = count( $incposts );  // only the number of posts included
      $r['post__in'] = $incposts;
    } elseif ( ! empty( $r['exclude'] ) ) {
      $r['post__not_in'] = wp_parse_id_list( $r['exclude'] );
    }

    $r['ignore_sticky_posts'] = true;
    $r['no_found_rows'] = true;

    return $r;
  }

  /**
   * Render shortcode
   *
   * @since  1.0
   *
   * @param $atts
   * @param null $content
   * @param null $tag
   *
   * @return string
   */
  public function output( $atts, $content = null, $base = '' ) {
    $output = parent::output( $atts, $content, $base );

    // FIXME Reset query when grid loop
    wp_reset_query();
    return $output;
  }

  public function registerScripts() {
  }

  public function enqueueScripts() {
    wp_enqueue_script( 'isotope' );
  }
}
