<?php

/**
 * @file
 * Tests for geofield.module.
 */

class GeofieldBaseTestCase extends FieldTestCase {
  function _testWKTFormatter($id, $geometry, $label) {
    $entity = field_test_entity_test_load($id);
    $entity->content = field_attach_view('test_entity', $entity, 'full');
    $this->content = drupal_render($entity->content);
    $value = $geometry->out('wkt');
    $this->assertText($value, 'WKT output for ' . $label . ' widget is correct.');
  }

  /**
   * Helper function for testGeofieldWidgets().
   */
  function _testGeoFieldAPISetup($widget_type, $display_type) {
    // Setup a field and instance
    $entity_type = 'test_entity';
    $this->field_name = drupal_strtolower($this->randomName());
    $this->field = array('field_name' => $this->field_name, 'type' => 'geofield');
    field_create_field($this->field);
    $this->instance = array(
      'field_name' => $this->field_name,
      'entity_type' => 'test_entity',
      'bundle' => 'test_bundle',
      'label' => $this->randomName() . '_label',
      'settings' => array(
      ),
      'widget' => array(
        'type' => $widget_type,
      ),
      'display' => array(
        'full' => array(
          'type' => $display_type,
        ),
      ),
    );
    field_create_instance($this->instance);
  }
}

class GeofieldWidgetTestCase extends GeofieldBaseTestCase {

  public static function getInfo() {
    return array(
      'name'  => 'Geofield - Widgets',
      'description'  => "Test the creation of geofields.",
      'group' => 'Geofield'
    );
  }

  function setUp() {
    parent::setUp(array('geofield', 'field_test'));

    $this->admin_user = $this->drupalCreateUser(array('administer filters'));
    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer modules'));
    $this->drupalLogin($this->web_user);
  }

  // Test fields.

  /**
   * Test lat/lon Input.
   */
  function testGeofieldFieldLatLonWidget() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_latlon', 'geofield_wkt');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom][lat]", '', t('Lat/lon widget [lat] is displayed'));
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom][lon]", '', t('Lat/lon widget [lon] is displayed'));

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    $point = $generator->random_point();
    geophp_load();
    $geometry = new Point($point[0], $point[1]);
    
    $edit = array(
      "{$this->field_name}[$langcode][0][geom][lat]" => $geometry->getY(),
      "{$this->field_name}[$langcode][0][geom][lon]" => $geometry->getX(),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Lat/lon entity was created'));
    $this->assertFieldByName($this->field_name . '[und][0][geom][lat]', $geometry->getY(), 'Lat field widget set correctly');
    $this->assertFieldByName($this->field_name . '[und][0][geom][lon]', $geometry->getX(), 'Lon field widget set correctly');

    $this->_testWKTFormatter($id, $geometry, 'lat/lon');    

    // Edge case, submit with 0,0 value.
    $this->drupalGet('test-entity/add/test-bundle');
    $edit = array(
      "{$this->field_name}[$langcode][0][geom][lat]" => '0',
      "{$this->field_name}[$langcode][0][geom][lon]" => '0',
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Lat/lon entity was created with 0,0 value.'));
    $geometry = new Point(0, 0);
    $this->_testWKTFormatter($id, $geometry, 'lat/lon');

    // Edge case, no geometry submitted.
    $this->drupalGet('test-entity/add/test-bundle');
    $edit = array(
      "{$this->field_name}[$langcode][0][geom][lat]" => '',
      "{$this->field_name}[$langcode][0][geom][lon]" => '',
    );

    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Lat/lon entity was created with null value.'));
  }

  /**
   * Test WKT Input.
   */
  function testGeofieldFieldWKTWidget() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_wkt', 'geofield_wkt');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom]", '', t('WKT widget is displayed'));

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    $wkt = $generator->wkt_generate();
    $geometry = geoPHP::load($wkt, 'wkt');
    
    $edit = array(
      "{$this->field_name}[$langcode][0][geom]" => $geometry->out('wkt'),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('WKT entity was created'));

    $this->_testWKTFormatter($id, $geometry, 'wkt');
  }

  /**
   * Test GeoJSON Input.
   */
  function testGeofieldFieldGeoJSONWidget() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_geojson', 'geofield_wkt');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom]", '', t('GeoJSON widget is displayed'));

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    $wkt = $generator->wkt_generate();
    $geometry = geoPHP::load($wkt, 'wkt');
    
    $edit = array(
      "{$this->field_name}[$langcode][0][geom]" => $geometry->out('json'),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('GeoJSON entity was created'));

    $this->_testWKTFormatter($id, $geometry, 'json');
  }

  /**
   * Test Bounds Input.
   */
  function testGeofieldFieldBoundsWidget() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_bounds', 'geofield_wkt');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom][top]", '', t('Bounds widget field "top" is displayed.'));
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom][bottom]", '', t('Bounds widget field "bottom" is displayed.'));
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom][left]", '', t('Bounds widget field "left" is displayed.'));
    $this->assertFieldByName("{$this->field_name}[$langcode][0][geom][right]", '', t('Bounds widget field "right" is displayed.'));

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    // Instead of calculating 4 separate points, calculate a center point and
    // distance from it.
    list($lon, $lat) = $generator->random_point();
    $lat_diff = $generator->dd_generate(2, 10) / 100;
    $lon_diff = $generator->dd_generate(2, 10) / 100;

    $edit = array(
      "{$this->field_name}[$langcode][0][geom][top]" => $lat + $lat_diff,
      "{$this->field_name}[$langcode][0][geom][bottom]" => $lat - $lat_diff,
      "{$this->field_name}[$langcode][0][geom][right]" => $lon + $lon_diff,
      "{$this->field_name}[$langcode][0][geom][left]" => $lon - $lon_diff,
    );

    $this->drupalPost(NULL, $edit, t('Save'));

    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Bounds entity was created'));

    $top = $lat + $lat_diff;
    $bottom = $lat - $lat_diff;
    $left = $lon - $lon_diff;
    $right = $lon + $lon_diff;

    $wkt = 'POLYGON ((' . $right . ' ' . $bottom . ', ' . $left . ' ' . $bottom . ', ' . $left . ' ' . $top . ', ' . $right . ' ' . $top . ', ' . $right . ' ' . $bottom . '))';
    $geometry = geoPHP::load($wkt, 'wkt');
    $this->_testWKTFormatter($id, $geometry, 'wkt');

    // Edge case, create with 0, 0, 0, 0.
    $this->drupalGet('test-entity/add/test-bundle');
    $edit = array(
      "{$this->field_name}[$langcode][0][geom][top]" => 0,
      "{$this->field_name}[$langcode][0][geom][bottom]" => 0,
      "{$this->field_name}[$langcode][0][geom][right]" => 0,
      "{$this->field_name}[$langcode][0][geom][left]" => 0,
    );
    
    $this->drupalPost(NULL, $edit, t('Save'));

    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];
    $this->assertRaw(t('test_entity @id has been created.', array('@id' => $id)), t('Bounds entity was created with values of 0, 0, 0, 0'));
  }
}

class GeoFieldElementTestCase extends DrupalWebTestCase {

  public static function getInfo() {
    return array(
      'name' => 'Geofield FormAPI Elements',
      'description' => "Test Geofield FormAPI elements.",
      'group' => 'Geofield',
    );
  }

  function setUp() {
    parent::setUp(array('geofield', 'geofield_test', 'geocoder'));

    $this->web_user = $this->drupalCreateUser(array('access content'));
    $this->drupalLogin($this->web_user);
  }

  function testGeofieldLatLonElement() {
    // Test form element rendering
    $this->drupalGet('geofield-latlon-element');
    $this->assertFieldById('edit-geofield-latlon-simple-lat', '', 'Latitude element for simple geofield exists.');
    $this->assertFieldById('edit-geofield-latlon-simple-lon', '', 'Longitude element for simple geofield exists.');

    $this->assertFieldById('edit-geofield-latlon-verbose-lat', 41, 'Latitude element for verbose geofield exists.');
    $this->assertFieldById('edit-geofield-latlon-verbose-lon', -86, 'Longitude element for verbose geofield exists.');

    // Test form element submission.
    $edit = array();
    $edit['geofield_latlon_simple[lat]'] = 41;
    $edit['geofield_latlon_simple[lon]'] = -86;
    $edit['geofield_latlon_verbose[lat]'] = 25;
    $edit['geofield_latlon_verbose[lon]'] = 54;
    $this->drupalPost('geofield-latlon-element', $edit, t('Save'));
    $this->assertText('Simple - Lat: 41 Lon: -86', "Simple Geofield saved data as expected");
    $this->assertText('Verbose - Lat: 25 Lon: 54', "Verbose Geofield saved data as expected");
  }
}

class GeofieldFormatterTestCase extends GeofieldBaseTestCase {

  public static function getInfo() {
    return array(
      'name'  => 'Geofield - Formatters',
      'description'  => "Test the various display formatters of geofields.",
      'group' => 'Geofield'
    );
  }

  function setUp() {
    parent::setUp(array('geofield', 'field_test'));

    $this->admin_user = $this->drupalCreateUser(array('administer filters'));
    $this->web_user = $this->drupalCreateUser(array('access field_test content', 'administer field_test content', 'administer modules'));
    $this->drupalLogin($this->web_user);
  }

  function testGeofieldWKTFormatter() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_wkt', 'geofield_wkt');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    $wkt = $generator->wkt_generate();
    geophp_load();
    $geometry = geoPHP::load($wkt, 'wkt');
    
    $edit = array(
      "{$this->field_name}[$langcode][0][geom]" => $geometry->out('wkt'),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];

    $this->_testWKTFormatter($id, $geometry, 'wkt');
  }

  function testGeofieldGeoJSONFormatter() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_wkt', 'geofield_geojson');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    $wkt = $generator->wkt_generate();
    geophp_load();
    $geometry = geoPHP::load($wkt, 'wkt');
    
    $edit = array(
      "{$this->field_name}[$langcode][0][geom]" => $geometry->out('wkt'),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];

    // Test GeoJSON output
    $entity = field_test_entity_test_load($id);
    $entity->content = field_attach_view('test_entity', $entity, 'full');
    $this->content = drupal_render($entity->content);
    $value = $geometry->out('json');
    $this->assertText($value, 'GeoJSON output is correct.');
  }

  function testGeofieldDefFormatter() {
    // Test lat/lon widget
    $this->_testGeoFieldAPISetup('geofield_wkt', 'geofield_def_list');
    // Display creation form.
    $langcode = LANGUAGE_NONE;
    $this->drupalGet('test-entity/add/test-bundle');

    // Submit with some value.
    include_once(drupal_get_path('module', 'geofield') . '/includes/GeoGenerator.php');
    $generator = new GeoGenerator();
    $wkt = $generator->wkt_generate();
    geophp_load();
    $geometry = geoPHP::load($wkt, 'wkt');
    
    $edit = array(
      "{$this->field_name}[$langcode][0][geom]" => $geometry->out('wkt'),
    );
    $this->drupalPost(NULL, $edit, t('Save'));
    preg_match('|test-entity/manage/(\d+)/edit|', $this->url, $match);
    $id = $match[1];

    // Test GeoJSON output
    $entity = field_test_entity_test_load($id);
    $entity->content = field_attach_view('test_entity', $entity, 'full');
    $this->content = drupal_render($entity->content);
    // @TODO: Actually test output... :-/
  }
}