<?php

// Exit if accessed directly
if (!defined('ABSPATH'))
	exit;

class WRE_Related_Query {

	public $order = '';
	public $count = '';
	public $include_address = '';
	public $include_price = '';
	public $price_range = '';
	public $distance = '';
	public $measurement = '';

	/**
	 * Get things going
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		$this->init();
	}

	/**
	 * Init
	 *
	 */
	public function init() {
		if (!is_single_wre())
			return;
		$this->setup();
		$this->query();
	}

	/**
	 * Setup our options
	 *
	 */
	public function setup() {
		$this->order = wre_option('rl_order') ? wre_option('rl_order') : 'rand';
		$this->count = wre_option('rl_max_listings') ? wre_option('rl_max_listings') : 3;

		$this->include_address = wre_option('rl_address_filter') ? wre_option('rl_address_filter') : '';

		$this->include_price = wre_option('rl_price_filter') ? wre_option('rl_price_filter') : 'no';
		$this->price_range = wre_option('rl_price_range') ? wre_option('rl_price_range') : 20000;

		$this->distance = wre_option('rl_search_radius') ? wre_option('rl_search_radius') : 20;
		$measurement = wre_option('rl_distance_measurement') ? wre_option('rl_distance_measurement') : 'kilometers';
		$this->measurement = apply_filters('wre_distance_measurement', $measurement);
	}

	/**
	 * Run the entire query
	 *
	 * @access public
	 * @return array
	 */
	public function query() {

		$args = array(
			'post_type' => 'listing',
			'post_status' => 'publish',
			'post__not_in' => array(get_the_ID()),
			'posts_per_page' => $this->count,
		);

		$args = $this->get_radius_args($args);
		$args = $this->get_price_args($args);
		$args = $this->get_ordering_args($args);

		$query = new WP_Query(apply_filters('wre_related_args', $args));

		return $query;
	}

	/**
	 * Run the radius query
	 *
	 * @access public
	 * @return array
	 */
	public function get_radius_args($args) {

		$lat = wre_meta('lat'); // get the lat of the current listing
		$lng = wre_meta('lng'); // get the lng of the current listing
		// stop here if we don't have lat or lng
		if (!$lat || !$lng)
			return $args;

		// we'll want everything within, say, 10km distance
		$distance = $this->distance;

		// earth's radius in km = ~6371
		$radius = $this->measurement == 'kilometers' ? 6371 : 3950;

		// latitude boundaries
		$maxlat = $lat + rad2deg($distance / $radius);
		$minlat = $lat - rad2deg($distance / $radius);

		// longitude boundaries (longitude gets smaller when latitude increases)
		$maxlng = $lng + rad2deg($distance / $radius / cos(deg2rad($lat)));
		$minlng = $lng - rad2deg($distance / $radius / cos(deg2rad($lat)));

		// build the meta query array
		$radius_array = array(
			'relation' => 'AND',
		);

		$radius_array[] = array(
			'key' => '_wre_listing_lat',
			'value' => array($minlat, $maxlat),
			'type' => 'DECIMAL',
			'compare' => 'BETWEEN',
		);
		$radius_array[] = array(
			'key' => '_wre_listing_lng',
			'value' => array($minlng, $maxlng),
			'type' => 'DECIMAL',
			'compare' => 'BETWEEN',
		);

		$radius_array = $this->get_city_state_zip_args($radius_array);

		$args['meta_query'][] = $radius_array;

		return apply_filters('wre_related_radius_args', $args);
	}

	/**
	 * Returns an array of arguments for city,state,zip based related listings.
	 *
	 * @access public
	 * @return array
	 */
	public function get_city_state_zip_args($args) {

		// address
		$city = wre_meta('city'); // get the city of the current listing
		$state = wre_meta('state'); // get the state of the current listing
		$zip = wre_meta('zip'); // get the zip of the current listing

		if (is_array($this->include_address) && !empty($this->include_address)) {

			if (in_array('city', $this->include_address)) {
				$args[] = array(
					'key' => '_wre_listing_city',
					'value' => $city,
					'compare' => 'LIKE'
				);
			}
			if (in_array('state', $this->include_address)) {
				$args[] = array(
					'key' => '_wre_listing_state',
					'value' => $state,
					'compare' => 'LIKE'
				);
			}
			if (in_array('zip', $this->include_address)) {
				$args[] = array(
					'key' => '_wre_listing_zip',
					'value' => $zip,
					'compare' => 'LIKE'
				);
			}
		}

		return $args;
	}

	/**
	 * Returns an array of arguments for ordering listings based on the selected values.
	 *
	 * @access public
	 * @return array
	 */
	public function get_ordering_args($args) {

		// set the order and orderby
		$orderby = $this->order;
		$order = 'DESC';

		switch ($orderby) {
			case 'date-desc':
				$orderby = 'date';
				$order = 'DESC';
				break;
			case 'date':
				$orderby = 'date';
				$order = 'ASC';
				break;
			case 'price-asc':
				$orderby = 'meta_value_num';
				$args['meta_key'] = '_wre_listing_price';
				$order = 'ASC';
				break;
			case 'price-desc':
				$orderby = 'meta_value_num';
				$args['meta_key'] = '_wre_listing_price';
				break;
			case 'title-asc':
				$orderby = 'title';
				$order = 'ASC';
				break;
			case 'title':
				$orderby = 'title';
				$order = 'DESC';
				break;
		}

		$args['order'] = $order;
		$args['orderby'] = $orderby;

		return apply_filters('wre_related_ordering_args', $args);
	}

	/**
	 * Returns an array of arguments for price based related listings.
	 *
	 * @access public
	 * @return array
	 */
	public function get_price_args($args) {

		// price
		$price = wre_meta('price'); // get the price of the current listing

		if ($this->include_price == 'yes' && $price != '') {
			$args['meta_query'][] = array(
				'key' => '_wre_listing_price',
				'value' => array($price - $this->price_range, $price + $this->price_range),
				'type' => 'numeric',
				'compare' => 'BETWEEN',
			);
			$args['meta_query']['relation'] = 'AND';
		}

		return apply_filters('wre_related_price_args', $args);
	}

}