<?php
// $Id:
/**
 * Argument handler to accept proximity
 */
class location_handler_argument_location_distance extends views_handler_argument {
  /**
   * Default value options.
   */
  function options(&$options) {
    parent::options($options);
    $options['search_units'] = 'mile';
    $options['search_method'] = 'mbr';
    $options['type'] = 'postal';
    $options['separator'] = 'r';
  }
  /**
   * Add a form elements to select options for this argument.
   */
  function options_form(&$form, &$form_state) {
    parent::options_form($form, $form_state);
    $options = array('postal' => t('Postal Code (Zipcode)'), 'latlon' => t('Decimal Lattitude and Longitude coordinates'));
    $form['type'] = array(
      '#title' => t('Coordinate Description'),
      '#type' => 'radios',
      '#options' => $options,
      '#default_value' => $this->options['coordinates'],
      '#description' => t('Type of center point'),
     );
    $form['separator'] = array(
      '#title' => t('Separator'),
      '#type' => 'textfield',
      '#default_value' => $this->options['separator'],
      '#description' => t('Separator for coordinates and distance.  Must not occur in the postal code.'),
    ); 
    $options = array('mile' => 'Miles', 'km' => 'Kilometers');
    $form['search_units'] = array(
      '#title' => t('Units'),
      '#type' => 'radios',
      '#options' => $options,
      '#default_value' => $this->options['search_units'],
      '#multiple' => TRUE,
      '#description' => t("Select the units of distance"),
    );      
    $form['search_method'] = array(
      '#title' => t('Method'),
      '#type' => 'radios',
      '#options' => array('dist' => t('Circular Proximity'), 'mbr' => t('Rectangular Proximity')),
      '#default_value' => $this->options['search_method'],
      '#description' => t('Method of determining proximity'),
     );    
  } 

  
  function options_validate($form, &$form_state) {
    // It is very important to call the parent function here:
    parent::options_validate($form, $form_state);
    // must escape * + ? . ( ) [ ] { } / | ^ $ in regex
    if (preg_match('[\$|&|\+|,|\/|:|;|=|\?|@|#]', $form_state['values']['options']['separator'])) {
       form_error($form['separator'], t('The characters $ & + , / : ; = ? @ # are reserved or unsafe and must be encoded'));	
    }
  }  
  
  // Used from the distance field.
  function calculate_coords() {
    if (!empty($this->value['latitude']) && !empty($this->value['longitude'])) {
      // If there are already coordinates, there's no work for us.
      return TRUE;
    }
    // @@@ Switch to mock location object and rely on location more?

    if ($this->options['type'] == 'postal') {
      $this->value['country'] = variable_get('location_default_country', 'us');
      // Zip code lookup.
      
      if (!empty($this->value['postal_code']) && !empty($this->value['country'])) {
      	location_load_country('us');
        $coord = location_get_postalcode_data($this->value);
        if ($coord) {
          $this->value['latitude'] = $coord['lat'];
          $this->value['longitude'] = $coord['lon'];
        }        
      }
      else {
          return false;
      }
    }

    return true;
  }  
  
   /**
   * Set up the query for this argument.
   *
   * The argument sent may be found at $this->argument.
   */
  function query() {   
  	//get and process argument
  	if ($this->options['type'] == 'postal') {
	    foreach ($this->view->argument as $argument) {
	      if ($argument->field == 'distance') {
	        list($this->value['postal_code'], $this->value['search_distance']) = split($this->options['separator'], $this->view->args[$argument->position]);
	        break;
	      }
	    }
  	} else if ($this->options['type'] == 'latlon') {
  		foreach ($this->view->argument as $argument) {
	      if ($argument->field == 'distance') {
	        list($coords, $this->value['search_distance']) = split($this->options['separator'], $this->view->args[$argument->position]);
	        list($this->value['latitude'], $this->value['longitude']) = split(',', $coords);
	        break;
	      }
	    }  	  
  	}
    // Coordinates available?
    if (!$this->calculate_coords()) {
      // Distance set?
      if (!empty($this->value['search_distance'])) {
        // Hmm, distance set but unable to resolve coordinates.
        // Force nothing to match.
        $this->query->add_where($this->options['group'], "0");
      }
      return;
    }

    $this->ensure_my_table();

    $lat = $this->value['latitude'];
    $lon = $this->value['longitude'];
    
    /*****FIX BEFORE COMMIT ****/
    //what is group and why do I need to set this to work??
    $this->options['group'] = 0;
    
    
    $distance_meters = _location_convert_distance_to_meters($this->value['search_distance'], $this->options['search_units']);    
    $latrange = earth_latitude_range($lon, $lat, $distance_meters);
    $lonrange = earth_longitude_range($lon, $lat, $distance_meters);
    // Add MBR check (always.)
    $this->query->add_where($this->options['group'], "$this->table_alias.latitude > %f AND $this->table_alias.latitude < %f AND $this->table_alias.longitude > %f AND $this->table_alias.longitude < %f", $latrange[0], $latrange[1], $lonrange[0], $lonrange[1]);

    if ($this->options['search_method'] == 'dist') {
      // Add radius check.
      $this->query->add_where($this->options['group'], earth_distance_sql($lon, $lat, $this->table_alias) .' < %f', $distance_meters);
    }
  }
}