<?php
/**
 * @file
 * Support file for the CCK Content Taxonomy module
 *
 * NOTE: If you have numeric terms, precede them in your import file with a #. If you need to actually start a string
 * with the # sign, then double it up like ##string and it will be converted into #string.
 */


/**
 * Implementation of hook_node_import_fields()
 */
function content_taxonomy_node_import_fields($type) {
  $fields = array();

  foreach (node_import_cck_fields($type, 'content_taxonomy') as $fieldname => $fieldinfo) {
    foreach ($fieldinfo['columns'] as $colname => $colinfo) {
      $cck_fieldname          = node_import_cck_name($fieldname, $colname);
      $fields[$cck_fieldname] = node_import_cck_field_defaults($fieldinfo);

      switch ($colname) {
        case 'value':
          $fields[$cck_fieldname]['title']        = $fieldinfo['widget']['label'];
          $fields[$cck_fieldname]['map_required'] = $fieldinfo['required'];
          break;
        default:
          $fields[$cck_fieldname]['title'] = t('Unsupported: ') . $fieldinfo['widget']['label'] .' - '. $colname;
      }
    }
  }
  return $fields;
}

/**
 * Implementation of hook_node_import_values_alter()
 */
function content_taxonomy_node_import_values_alter(&$values, $type, $defaults, $options, $fields, $preview) {
  // Place the following line in the validation function on the content_taxonomy module in order to determine
  // what the widget is expecting:
  //
  //   drupal_set_message( '<pre>Element: ' . print_r( $element, TRUE ) . '</pre>' );
  //
  // For example, I placed the above line in the content_taxonomy_tree_validate function in order to discover
  // the data structure that the validator expects. I assume the other widgets expect different structures.

  foreach (node_import_cck_fields($type, 'content_taxonomy') as $fieldname => $fieldinfo) {
    $vid = $fieldinfo['vid'];
    //***************************************tree widget***************************************
    if ($fieldinfo['widget']['type'] == 'content_taxonomy_tree') {
      $terms   = array();
      $results = array();
      foreach ($values[$fieldname] as $i => $value) {
        if (is_numeric($value['value'])) {
          $foundterms = taxonomy_get_term(intval($value['value']));
        }
        else {
          $value['value'] = content_taxonomy_node_import_check_numeric($value['value']);
          $foundterms = taxonomy_get_term_by_name($value['value']);
        }
        foreach ($foundterms as $index => $termfound) {
          if ($termfound->vid == $vid) {
            $tid = $termfound->tid;
            $terms[$tid] = (array)$termfound;
            $children = taxonomy_get_children($tid, $vid);
            $terms[$tid]['children'] = $children;
            $parents = taxonomy_get_parents($tid);
            $terms[$tid]['parents'] = $parents;
          }
        }
      }

      foreach ($terms as $term_id => $data) {
        if (empty($data['parents'])) {
          // We only want top-level terms here
          $results['value'][$term_id] = array('checkbox' => $term_id);

          if (!empty($data['children'])) {
            // Handle the children terms
            content_taxonomy_node_import_tree_adjust($terms, $data, $results['value'][$term_id]['children']);
          }
          else {
            unset($terms[$term_id]);
          }
        }
      }
      $values[$fieldname] = $results;
    }
    //***************************************options widget***************************************
    elseif ($fieldinfo['widget']['type'] == 'content_taxonomy_options') {
      // Content taxonomy checkboxes
      $results = array();
      foreach ($values[$fieldname] as $i => $value) {
        if (is_numeric($value['value'])) { // Using TID...
          $sql = "SELECT tid FROM {term_data} WHERE vid = %d AND tid = %d";
          if ($tid = db_result(db_query($sql, $vid, intval($value['value'])))) {
            $results[$tid] = $tid;
          }
        }
        else { // Using term name...
          $value['value'] = content_taxonomy_node_import_check_numeric($value['value']);
          $sql = "SELECT tid FROM {term_data} WHERE vid = %d AND LOWER(name) = '%s'";
          if ($tid = db_result(db_query($sql, $vid, drupal_strtolower($value['value'])))) {
            $results[$tid] = $tid;
          }
        }
      }
      $values[$fieldname]['value'] = $results;
    }
    //***************************************hierarchical select widget***************************************
    elseif ($fieldinfo['widget']['type'] == 'content_taxonomy_hs') {
      $terms   = array();
      $results = array();
      foreach ($values[$fieldname] as $i => $value) {
        $position = stripos($value['value'], '>>');
        if ($position) {//using the delimiter, we are given the explicit parentage of the term. we can therefore have duplicate terms.
          $lineage = explode('>>', $value['value']);
          $terms = content_taxonomy_node_import_get_children($lineage, $vid);
        }
        else {//we have just one term, hopefully there are no duplicates, so let's find the parents
          if (is_numeric($value['value'])) {
            $foundterms = taxonomy_get_term(intval($value['value']));
          }
          else {
            $value['value'] = content_taxonomy_node_import_check_numeric($value['value']);
            $foundterms = taxonomy_get_term_by_name($value['value']);
          }
          foreach ($foundterms as $index => $termfound) {
            if ($termfound->vid == $vid) {
              $tid = $termfound->tid;
              $terms[$tid] = (array)$termfound;
              $children = taxonomy_get_children($tid, $vid);
              $terms[$tid]['children'] = $children;
              $parents = taxonomy_get_parents($tid);
              $terms[$tid]['parents'] = $parents;
            }
          }
        }
      }

      //We now have our list of hierarchical terms in order of parent>>child>>child, etc. Now let's arrange them how
      //hierarchical select expects them to be.
      if (!empty($terms)) {
        foreach ($terms as $index => $data) {
          $results[] = $data['tid'];
        }
        $values[$fieldname]['tids'] = $results;
      }
      else {
        $values[$fieldname]['tids'] = NULL;
      }
    }
    //***************************************other widgets***************************************
    else {
      foreach ($values[$fieldname] as $i => $value) {
        if (is_numeric($value['value'])) { // Using TID...
          $sql = "SELECT tid FROM {term_data} WHERE vid = %d AND tid = %d";
          if ($tid = db_result(db_query($sql, $vid, intval($value['value'])))) {
            $values[$fieldname][$i]['value'] = $tid;
          }
          else {
            $value['value'] = content_taxonomy_node_import_check_numeric($value['value']);
            if (trim($value['value']) != '') {
              $edit = array('vid' => $vid, 'name' => $value['value']);
              taxonomy_save_term($edit);
              $sql = "SELECT tid FROM {term_data} WHERE vid = %d AND tid = %d";
              if ($tid = db_result(db_query($sql, $vid, intval($value['value'])))) {
                $values[$fieldname][$i]['value'] = $tid;
              }
            }
          }
        }
        else { // Using term name...
          $sql = "SELECT tid FROM {term_data} WHERE vid = %d AND LOWER(name) = '%s'";
          if ($tid = db_result(db_query($sql, $vid, drupal_strtolower($value['value'])))) {
            $values[$fieldname][$i]['value'] = $tid;
          }
          else {
            $value['value'] = content_taxonomy_node_import_check_numeric($value['value']);
            if (trim($value['value']) != '') {
              $edit = array('vid' => $vid, 'name' => $value['value']);
              taxonomy_save_term($edit);
              $sql = "SELECT tid FROM {term_data} WHERE vid = %d AND LOWER(name) = '%s'";
              if ($tid = db_result(db_query($sql, $vid, drupal_strtolower($value['value'])))) {
                $values[$fieldname][$i]['value'] = $tid;
              }
            }
          }
        }
      }
    }
  }
}

/**
 * Used to contruct the lineage of terms for use by hierarchical select widget.
 * 
 * @param <type> $lineage
 * @param <type> $vid
 * @param <type> $parent_tid
 * @return <type>
 */
function content_taxonomy_node_import_get_children($lineage, $vid, $parent_tid = NULL) {
  $top = array_shift($lineage);
  $remainder = $lineage;
  if (is_numeric($top)) {
    $foundterms = taxonomy_get_term(intval($top));
  }
  else {
    $top = content_taxonomy_node_import_check_numeric($top);
    $foundterms = taxonomy_get_term_by_name($top);
  }
  //first, let's clear out any terms in other vocabularies
  foreach ($foundterms as $index => $termfound) {
    if ($termfound->vid != $vid) {
      unset($foundterms[$index]);
    }
  }
  if (empty($foundterms)) {
    node_import_input_error(t("The term %value was not found at the expected level in your taxonomy hierarchy. Please check your import file and try again.", array('%value' => $top)));
    return NULL;
  }
  //let's take what we have left and make sure we found the right child - there should just be one term left after the parent sifting that follows
  $current_tid = 0;
  foreach ($foundterms as $index => $termfound) {
    $tid = $termfound->tid;
    $parents = taxonomy_get_parents($tid);
    if (($parent_tid != NULL && !isset($parents[$parent_tid])) || ($parent_tid == NULL && !empty($parents))) {
      unset($foundterms[$index]);//we found a term whose text matched, but isn't in the right spot of the hierarchy
      continue;
    }
    else {
      $current_tid = $tid;
    }
    //drupal_set_message('<pre>Parents: ' . print_r($parents, TRUE) . '</pre>');
    $terms[$tid] = (array)$termfound;
    $children = taxonomy_get_children($tid, $vid);
    $terms[$tid]['children'] = $children;    
    $terms[$tid]['parents'] = $parents;
  }
  if (empty($terms)) {
    node_import_input_error(t("The term %value was not found at the expected level in your taxonomy hierarchy, but a match was found at a different level. Please check your import file and try again.", array('%value' => $top)));
    return NULL;
  }
  if (count($terms) > 1) {
    node_import_input_error(t("The term %value was found MORE THAN ONCE as children of the same term. Please check your import file and try again.", array('%value' => $top)));
    return NULL;
  }
  if (is_array($remainder) && !empty($remainder)) {
    //drupal_set_message('<pre>Terms inside: ' . print_r($terms, TRUE) . '</pre>');
    $child_terms = content_taxonomy_node_import_get_children($remainder, $vid, $current_tid);
    if ($child_terms != NULL) {
      $terms = array_merge($terms, $child_terms);
    }
  }
  return $terms;
}

/**
 * This is for using numeric values as terms. Normally, numeric values are treated as TIDs. Using a # in front of your
 * number will make sure it is treated as a value.
 * 
 * @param <type> $value
 * @return <type>
 */
function content_taxonomy_node_import_check_numeric($value) {
  $pos = strpos($value, "#");
  if ($pos === 0) {
    $value = substr($value, 1);
  }
  return $value;
}

/**
 * This is for fixing the output of the tree widget type.
 *
 * @param <type> $terms
 * @param <type> $data
 * @param <type> $results
 */
function content_taxonomy_node_import_tree_adjust(&$terms, &$data, &$results) {
  foreach ($data['children'] as $id => $contents) {
    if (key_exists($id, $terms)) {
      $results[$id] = array('checkbox' => $id);
      if (!empty($terms[$id]['children'])) {
        content_taxonomy_node_import_tree_adjust($terms, $terms[$id], $results[$id]['children']);
      }
      else {
        // Unset the item from the terms list; this should be a leaf term
        unset($terms[$id]);
      }
    }
  }
}
