<?php

/**
 * Implements hook_feeds_processor_targets_alter().
 */
function feeds_term_reference_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name){
  foreach(field_info_instances($entity_type, $bundle_name) as $name => $instance){
    $info = field_info_field($name);
    if($info['type'] == 'taxonomy_term_reference'){
      $targets[$name . ":guid"] = array(
        'name' => $instance['label'] . ' (Term reference by Feeds GUID)',
        'callback' => 'feeds_term_reference_feeds_set_target',
        'description' => t('The Feeds GUID for the @name field.', array(
          '@name' => $instance['label']
        )),
        'real_target' => $name
      );
      $targets[$name . ":tid"] = array(
        'name' => $instance['label'] . ' (Term reference by Term ID)',
        'callback' => 'feeds_term_reference_feeds_set_target',
        'description' => t('The Term ID for the @name field.', array(
          '@name' => $instance['label']
        )),
        'real_target' => $name
      );
    }
  }
}

/**
 * Callback for mapping.
 * Here is where the actual mapping happens.
 *
 * When the callback is invoked, $target contains the name of the field the
 * user has decided to map to and $value contains the value of the feed item
 * element the user has picked as a source.
 * Implementation of hook_feeds_set_target().
 *
 * @param $source A
 *          FeedsSource object.
 * @param $entity The
 *          entity to map to.
 * @param $target The
 *          target key on $entity to map to.
 * @param $value The
 *          value to map. Can be an array or a string.
 */
function feeds_term_reference_feeds_set_target(FeedsSource $source, $entity, $target, $value){
  if(empty($value)){return;}
  // Handle non-multiple value fields.
  if(!is_array($value)){
    $value = array(
      $value
    );
  }
  // Guess the entity type.
  $entity_type = strtolower(get_class($source->importer->processor));
  if(($processor_location = strpos($entity_type, 'processor')) > 0){
    $entity_type = substr($entity_type, 0, $processor_location);
  }
  if(substr($entity_type, 0, 5) == 'feeds'){
    $entity_type = substr($entity_type, 5);
  }
  switch($entity_type){
    case 'term':
      $entity_type = 'taxonomy_term';
      break;
  }
  if(!entity_get_info($entity_type)){
    $entity_type = 'node';
  }
  // Determine the field we are matching against, and whether duplicates are
  // allowed.
  $target_info = explode(':', $target);
  list($target, $match_key) = $target_info; // matchkey=guid or tid
  $info = field_info_field($target);
  $i = 0;
  $entity->$target = isset($entity->$target) ? $entity->$target : array();
  foreach($value as $v){
    if(trim($v)){
      $id = 0;
      switch($match_key){
        case 'guid':
          $error_label = 'Feeds GUID';
          $id = db_select('feeds_item', 'f')->fields('f', array(
            'entity_id'
          ))->condition('entity_type', 'taxonomy_term')->condition('guid', $v)->execute()->fetchField();
          break;
        case 'tid':
          $error_label = 'Term ID';
          if($v instanceof FeedsTermElement){
            $id = $v->tid;
          }elseif(is_numeric($v)){
            $is_valid_tid = taxonomy_term_load($v);
            if($is_valid_tid){
              $id = $v;
            }
          }elseif(is_string($v)){
            drupal_set_message(t(' The term ID %v must be a number.', array(
              '%v' => $v
            )));
          }
          break;
      }
      if($id){
        $lang = field_language($entity_type, $entity, $target);
        $entity->{$target}[$lang][$i]['tid'] = $id;
      }else{
        drupal_set_message(t('%missing_value does not match any existing %match_key.', array(
          '%missing_value' => $v,
          '%match_key' => $error_label
        )));
      }
      if($info['cardinality'] == 1){
        break;
      }
    }
    $i++;
  }
}