<?php

/**
 * @file
 * Admin page callbacks for the GPX Track & Elevation module.
 */

define("MAP_IMAGE_MAX_SIZE", 128);

/**
 * Function to create the administrative form for the module.
 *
 * Callback for drupal_get_form
 * for details look at:
 * https://api.drupal.org/api/drupal/includes%21form.inc/group/form_api/7.
 */
function gpx_track_elevation_settings_form($form, &$form_state) {

  $form['general_configuration'] = array(
    '#type' => 'fieldset',
    '#title' => t('General configuration'),
    '#collapsible' => FALSE,
  );
  $form['general_configuration']['gpx_track_elevation_bilink'] = array(
    '#type' => 'checkbox',
    '#default_value' => variable_get('gpx_track_elevation_bilink', 0),
    '#title' => t('Enable bidirectional link'),
    '#required' => FALSE,
    '#description' => t('Use with caution: enabling bidirectional link between map and elevation profile uses a lot of browser resources and highly reduces site performances.'),
  );

  $form['general_configuration']['gpx_track_elevation_trcolor'] = array(
    '#type' => 'textfield',
    '#default_value' => variable_get('gpx_track_elevation_trcolor', '#006CAB'),
    '#title' => t('Track color'),
    '#required' => TRUE,
    '#description' => t('Select the track color.'),
    '#element_validate' => array('_gpx_track_elevation_validate_color'),
  );

  $form['general_configuration']['gpx_track_elevation_epcolor'] = array(
    '#type' => 'textfield',
    '#default_value' => variable_get('gpx_track_elevation_epcolor', '#006CAA'),
    '#title' => t('Elevation profile color'),
    '#required' => TRUE,
    '#description' => t('Select the track color.'),
    '#element_validate' => array('_gpx_track_elevation_validate_color'),
  );

  $form['general_configuration']['gpx_track_elevation_trstroke'] = array(
    '#type' => 'textfield',
    '#default_value' => variable_get('gpx_track_elevation_trstroke', 2),
    '#title' => t('Track stroke'),
    '#required' => TRUE,
    '#description' => t('Select the track stroke weight.'),
    '#element_validate' => array('element_validate_integer_positive'),
  );

  $form['general_configuration']['gpx_track_elevation_maptype'] = array(
    '#type' => 'select',
    '#default_value' => variable_get('gpx_track_elevation_maptype', 'TERRAIN'),
    '#title' => t('Map Type'),
    '#required' => TRUE,
    '#options' => array(
      'TERRAIN' => t('Terrain'),
      'ROAD' => t('Road'),
      'HYBRID' => t('Hybrid'),
      'SATELLITE' => t('Satellite'),
    ),
    '#description' => t('Select the map default type'),
  );

  $form['node_types_configuration'] = array(
    '#type' => 'fieldset',
    '#title' => t('Configuration for entity types'),
    '#collapsible' => FALSE,
  );

  // Create the form element for any allowed entity type
  // (fieldable, not user and not comments).
  foreach (entity_get_info() as $entity_name => $entity_data) {
    if ($entity_data['fieldable'] && $entity_name <> 'comment' && $entity_name <> 'user') {
      $form['node_types_configuration'][$entity_name] = array(
        '#type' => 'fieldset',
        '#title' => check_plain($entity_name),
        '#collapsible' => FALSE,
      );
      // For each entity type we have to create select field for any bundle:
      // field name will be the bundle name.
      foreach ($entity_data['bundles'] as $bundle_name => $bundle_data) {
        $gpx_file = '';
        $form['node_types_configuration'][$entity_name][$bundle_name] = array(
          '#type' => 'select',
          '#options' => gpx_track_elevation_get_valid_field($entity_name, $bundle_name, TRUE, $gpx_file),
          '#default_value' => $gpx_file,
          '#title' => check_plain($bundle_name),
          '#required' => FALSE,
          '#description' => t('Select field to get the GPX from'),
        );
      }
    }
  }

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save settings'),
  );
  return $form;
}

/**
 * Function to validate color input.
 *
 * Callback for element_validatation of gpx_track_elevation_settings_form.
 *
 * @param bool $element
 *   Return value populated with current setting.
 * @param bool $form_state
 *   Unused by this implementation.
 * @param bool $form
 *   Unused by this implementation.
 *
 *   for details look at:
 *   https://api.drupal.org/api/drupal/developer%21topics%21forms_api_reference.html/7#element_validate.
 */
function _gpx_track_elevation_validate_color($element, &$form_state, $form) {
  if (!(preg_match("/^#([a-f0-9]{3}|[a-f0-9]{6})$/i", $element['#value']))) {
    form_error($element, t('The color must be a valid color code in the form #xxyyzz or #xyz'));
  }
}

/**
 * Form submission handler for gpx_track_elevation_settings_form().
 */
function gpx_track_elevation_settings_form_submit($form, &$form_state) {
  // Set system variables.
  // Save configuration settings for GPX Track & Elevation module.
  // Cannot use system_settings_form because not all field are module settings.
  variable_set('gpx_track_elevation_bilink', $form_state['values']['gpx_track_elevation_bilink']);
  variable_set('gpx_track_elevation_trcolor', $form_state['values']['gpx_track_elevation_trcolor']);
  variable_set('gpx_track_elevation_epcolor', $form_state['values']['gpx_track_elevation_epcolor']);
  variable_set('gpx_track_elevation_trstroke', $form_state['values']['gpx_track_elevation_trstroke']);
  variable_set('gpx_track_elevation_maptype', $form_state['values']['gpx_track_elevation_maptype']);

  // Clear the cache to be sure having real time info about fields.
  field_cache_clear();

  // Get info about our field: we need to know if it exists or not.
  $field_gpx_track_elevation = field_info_field('field_gpx_track_elevation');

  // If it does not we create it.
  if (is_null($field_gpx_track_elevation)) {
    $field = array(
      'field_name' => 'field_gpx_track_elevation',
      'type' => 'gpxElevation',
    );
    field_create_field($field);
  }

  // For each bundle (fieldable, not comment, not user) we look for changes.
  $all_entity = entity_get_info();
  foreach ($all_entity as $entity_name => $entity_data) {
    if ($entity_data['fieldable'] && $entity_name <> 'comment' && $entity_name <> 'user') {
      foreach ($entity_data['bundles'] as $bundle_name => $bundle_data) {
        $current_value = '';
        // Call to gpx_track_elevation_get_valid_field will write in
        // $current_value the current setting of our field:
        // the only setting is the field where the gpx has to be retrieved.
        gpx_track_elevation_get_valid_field($entity_name, $bundle_name, TRUE, $current_value);
        // User is asking to disable our field_gpx_track_elevation
        // field for the bundle.
        if ($form_state['values'][$bundle_name] == '') {
          // Check to see if old settings is different
          // (otherwise there is nothing to do).
          if ($current_value <> '') {
            $instance = field_info_instance($entity_name, 'field_gpx_track_elevation', $bundle_name);
            // Delete instance, but do not delete the field in case
            // no more instances: we could still need it in other bundles.
            field_delete_instance($instance, FALSE);
          }
        }
        // User want to enable our field_gpx_track_elevation for the bundle.
        else {
          // Check to see if old settings is different
          // (otherwise there is nothing to do).
          if ($form_state['values'][$bundle_name] <> $current_value) {
            // In case old settings are different from nothing we need to
            // change the instance settings.
            if ($current_value <> '') {
              $instance = field_info_instance($entity_name, 'field_gpx_track_elevation', $bundle_name);
              $instance['settings']['gpx_field'] = $form_state['values'][$bundle_name];
              field_update_instance($instance);
            }
            // Otherwise we need to create a new instance.
            else {
              $instance = array(
                'field_name' => 'field_gpx_track_elevation',
                'entity_type' => $entity_name,
                'bundle' => $bundle_name,
                'label' => t('Elevation profile'),
                'settings' => array('gpx_field' => $form_state['values'][$bundle_name]),
                'display' => array(
                  'default' => array('label' => 'hidden', 'type' => 'gpx_track_elevation_default'),
                ),
              );
              field_create_instance($instance);
            }
          }
        }
      }
    }
  }
  // If the field has no instances left, delete it.
  field_cache_clear();
  $field_gpx_track_elevation = field_info_field('field_gpx_track_elevation');
  if (empty($field_gpx_track_elevation['bundles'])) {
    field_delete_field('field_gpx_track_elevation');
    field_purge_batch(1);
  }
}

/**
 * Waipoint types list tab.
 *
 * Callback for drupal_get_form
 * for details look at:
 * https://api.drupal.org/api/drupal/includes%21form.inc/group/form_api/7.
 */
function gpx_track_elevation_waypoint_types_list() {
  $header = array(
    t('Type'),
    t('Image url'),
    array('data' => t('Operations'), 'colspan' => 2),
  );
  $rows = array();

  $wpt_types = db_select('gpx_track_elevation', 'w')
    ->fields('w', array('wid', 'type', 'url'))
    ->orderBy('weight')
    ->orderBy('type')
    ->execute()
    ->fetchAll();

  foreach ($wpt_types as $wpt_type) {
    $rows[] = array(
      check_plain($wpt_type->type),
      check_url($wpt_type->url),
      l(t('Edit'), 'admin/config/services/GPXtrackele/waypoints/edit/' . $wpt_type->wid),
      l(t('Delete'), 'admin/config/services/GPXtrackele/waypoints/delete/' . $wpt_type->wid),
    );
  }

  if (!$rows) {
    $rows[] = array(
      array(
        'data' => t('No types defined.'),
        'colspan' => 4,
      ),
    );
  }

  $build['types_table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
  );
  return $build;
}

/**
 * Deletion of waypoint type.
 *
 * Callback for drupal_get_form
 * for details look at:
 * https://api.drupal.org/api/drupal/includes%21form.inc/group/form_api/7.
 * extra parameter:
 *
 * @param string $wpt_type
 *   The waypoint type id of the type to delete.
 */
function gpx_track_elevation_waypoint_type_delete_form($form, &$form_state, $wpt_type) {
  $form['waypoint_types'] = array(
    '#type' => 'value',
    '#value' => $wpt_type,
  );

  return confirm_form(
    $form,
    t('Are you sure you want to delete waypoint type "%wpt_type"?', array('%wpt_type' => $wpt_type['type'])),
    'admin/config/services/GPXtrackele/waypoints',
    t('This action cannot be undone.'),
    t('Delete'),
    t('Cancel')
  );
}

/**
 * Form submission handler for gpx_track_elevation_waypoint_type_delete_form().
 */
function gpx_track_elevation_waypoint_type_delete_form_submit($form, &$form_state) {
  $wpt_type = $form['waypoint_types']['#value'];

  db_delete('gpx_track_elevation')
    ->condition('wid', $wpt_type['wid'])
    ->execute();

  drupal_set_message(t('Waypoint type %wpt_type has been deleted.', array('%wpt_type' => $wpt_type['type'])));
  watchdog('contact', 'Waypoint type %wpt_type has been deleted.', array('%wpt_type' => $wpt_type['type']), WATCHDOG_NOTICE);

  $form_state['redirect'] = 'admin/config/services/GPXtrackele/waypoints';
}

/**
 * Form constructor for the waypoint type edit form.
 *
 * Callback for drupal_get_form.
 *
 * @param array $wpt_type
 *   An array describing the waypoint type. May be empty for new types.
 *   Recognized array keys are:
 *   - wid: The wpt type ID for which the form is to be displayed.
 *   - type: The name of the waypoint type.
 *   - url: the link to the waypoint type image.
 *   - weight: The weight of the type.
 *
 * @see waypoint_type_edit_form_validate()
 * @see waypoint_type_edit_form_submit()
 */
function gpx_track_elevation_waypoint_type_edit_form($form, &$form_state, array $wpt_type = array()) {
  // If this is a new wpt type, add the default values.
  $wpt_type += array(
    'wid' => NULL,
    'type' => '',
    'url' => '',
    'weight' => 0,
  );

  $form['type'] = array(
    '#type' => 'textfield',
    '#title' => t('Waypoint type name'),
    '#maxlength' => 255,
    '#default_value' => $wpt_type['type'],
    '#description' => t("Insert the type name. It is the string expected in the <type> tag of the gpx waypoint."),
    '#required' => TRUE,
  );
  $form['url'] = array(
    '#type' => 'textfield',
    '#title' => t('Image url'),
    '#maxlength' => 255,
    '#default_value' => $wpt_type['url'],
    '#description' => t("Insert the url of the image to be used to show this waypoint type on the map. Only square images are allowed. Max size: @max_size x @max_size px", array('@max_size' => MAP_IMAGE_MAX_SIZE)),
    '#required' => TRUE,
  );
  $form['weight'] = array(
    '#type' => 'weight',
    '#title' => t('Weight'),
    '#default_value' => $wpt_type['weight'],
    '#description' => t('When listing categories, those with lighter (smaller) weights get listed before categories with heavier (larger) weights. Categories with equal weights are sorted alphabetically.'),
  );
  $form['wid'] = array(
    '#type' => 'value',
    '#value' => $wpt_type['wid'],
  );
  $form['actions'] = array('#type' => 'actions');
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );

  return $form;
}

/**
 * Form validation handler for gpx_track_elevation_waypoint_type_edit_form().
 *
 * @see waypoint_type_edit_form_submit()
 */
function gpx_track_elevation_waypoint_type_edit_form_validate($form, &$form_state) {
  // When creating a new wpt type, or renaming the wpèt type on an existing
  // one, make sure that the given wpt type is unique.
  $wpt_type = $form_state['values']['type'];
  $query = db_select('gpx_track_elevation', 'w')->condition('w.type', $wpt_type, '=');
  if (!empty($form_state['values']['wid'])) {
    $query->condition('w.wid', $form_state['values']['wid'], '<>');
  }
  if ($query->countQuery()->execute()->fetchField()) {
    form_set_error('wpt_type', t('A waypoint type form with category %wpt_type already exists.', array('%wpt_type' => $wpt_type)));
  }

  $wpt_url = check_url($form_state['values']['url']);
  if (valid_url($wpt_url, TRUE) <> TRUE) {
    form_set_error('wpt_url', t('%wpt_url is an invalid url address.', array('%wpt_url' => $wpt_url)));
  }
  if ($image_size = @getimagesize($wpt_url)) {
    if ($image_size[0] > MAP_IMAGE_MAX_SIZE || $image_size[1] > MAP_IMAGE_MAX_SIZE) {
      form_set_error('wpt_url', t('Image is to big (max %max_size * %max_size pixel)', array('%max_size' => MAP_IMAGE_MAX_SIZE)));
    }
    if ($image_size[0] <> $image_size[1]) {
      form_set_error('wpt_url', t('Only square image are allowed'));
    }
  }
  else {
    form_set_error('wpt_url', t('Cannot load image at %wpt_url.', array('%wpt_url' => $wpt_url)));
  }
}

/**
 * Form submission handler for gpx_track_elevation_waypoint_type_edit_form().
 *
 * @see waypoint_type_edit_validate()
 */
function gpx_track_elevation_waypoint_type_edit_form_submit($form, &$form_state) {

  if (empty($form_state['values']['wid'])) {
    drupal_write_record('gpx_track_elevation', $form_state['values']);
  }
  else {
    drupal_write_record('gpx_track_elevation', $form_state['values'], array('wid'));
  }

  drupal_set_message(t('Waypoint type %wpt_type has been saved.', array('%wpt_type' => $form_state['values']['type'])));
  $form_state['redirect'] = 'admin/config/services/GPXtrackele/waypoints';
}

/**
 * Admin page callbacks for the track settings.
 *
 * Callback for drupal_get_form
 * for details look at:
 * https://api.drupal.org/api/drupal/includes%21form.inc/group/form_api/7.
 */
function gpx_track_elevation_track_settings_form($form, &$form_state) {
  $form['gpx_track_elevation_start_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Image for track start point'),
    '#maxlength' => 255,
    '#default_value' => variable_get('gpx_track_elevation_start_url', ''),
    '#description' => t("Insert the url of the image to be used to show starting points. Max size: @max_size x @max_size px", array('@max_size' => MAP_IMAGE_MAX_SIZE)),
  );
  $form['gpx_track_elevation_end_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Image for track end point'),
    '#maxlength' => 255,
    '#default_value' => variable_get('gpx_track_elevation_end_url', ''),
    '#description' => t("Insert the url of the image to be used to show ending points. Max size: @max_size x @max_size px", array('@max_size' => MAP_IMAGE_MAX_SIZE)),
  );

  $form['gpx_track_elevation_last_url'] = array(
    '#type' => 'textfield',
    '#title' => t('Image for track end point of last track'),
    '#maxlength' => 255,
    '#default_value' => variable_get('gpx_track_elevation_last_url', ''),
    '#description' => t("Insert the url of the image to be used to show ending points of the last Track. Max size: @max_size x @max_size px", array('@max_size' => MAP_IMAGE_MAX_SIZE)),
  );

  $form['actions'] = array('#type' => 'actions');
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );

  return system_settings_form($form);
}

/**
 * Form validation handler for gpx_track_elevation_track_settings_form().
 */
function gpx_track_elevation_track_settings_form_validate($form, &$form_state) {

  $start_url = check_url($form_state['values']['gpx_track_elevation_start_url']);
  if ((valid_url($start_url, TRUE) <> TRUE) && !(is_null($start_url) || $start_url == '')) {
    form_set_error('start_url', t('%start_url is an invalid url address.', array('%start_url' => $start_url)));
  }

  $end_url = check_url($form_state['values']['gpx_track_elevation_end_url']);
  if ((valid_url($end_url, TRUE) <> TRUE) && !(is_null($end_url) || $end_url == '')) {
    form_set_error('end_url', t('%end_url is an invalid url address.', array('%end_url' => $end_url)));
  }

  $last_url = check_url($form_state['values']['gpx_track_elevation_end_url']);
  if ((valid_url($last_url, TRUE) <> TRUE) && !(is_null($last_url) || $last_url == '')) {
    form_set_error('last_url', t('%last_url is an invalid url address.', array('%last_url' => $last_url)));
  }

  if (!(is_null($start_url) || $start_url == '')) {
    if ($image_size = @getimagesize($start_url)) {
      if ($image_size[0] > MAP_IMAGE_MAX_SIZE || $image_size[1] > MAP_IMAGE_MAX_SIZE) {
        form_set_error('start_url', t('Image is to big (max %max_size * %max_size pixel)', array('%max_size' => MAP_IMAGE_MAX_SIZE)));
      }
    }
    else {
      form_set_error('start_url', t('Cannot load image at %start_url.', array('%start_url' => $start_url)));
    }
  }

  if (!(is_null($end_url) || $end_url == '')) {
    if ($image_size = @getimagesize($end_url)) {
      if ($image_size[0] > MAP_IMAGE_MAX_SIZE || $image_size[1] > MAP_IMAGE_MAX_SIZE) {
        form_set_error('end_url', t('Image is to big (max %max_size * %max_size pixel)', array('%max_size' => MAP_IMAGE_MAX_SIZE)));
      }
    }
    else {
      form_set_error('end_url', t('Cannot load image at %end_url.', array('%end_url' => $end_url)));
    }
  }

  if (!(is_null($last_url) || $last_url == '')) {
    if ($image_size = @getimagesize($last_url)) {
      if ($image_size[0] > MAP_IMAGE_MAX_SIZE || $image_size[1] > MAP_IMAGE_MAX_SIZE) {
        form_set_error('last_url', t('Image is to big (max %max_size * %max_size pixel)', array('%max_size' => MAP_IMAGE_MAX_SIZE)));
      }
    }
    else {
      form_set_error('last_url', t('Cannot load image at %last_url.', array('%last_url' => $last_url)));
    }
  }

}
