'', 'chado_column' => '', 'base_table' => '', ); // Set this to the name of the storage backend that by default will support // this field. public static $default_storage = 'field_chado_storage'; /** * @see TripalField::formatterView() */ public function formatterView(&$element, $entity_type, $entity, $langcode, $items, $display) { $element[0] = array( // We create a render array to produce the desired markup, '#type' => 'markup', '#markup' => '', ); $num_bases = 50; foreach ($items as $delta => $item) { // If there are no residues then skip this one. if (!is_array($item['value']) or !array_key_exists('residues', $item['value'])) { continue; } $residues = $item['value']['residues']; $label = $item['value']['label']; $defline = $item['value']['defline']; $content = '
' . $label . '
'; $content .= '
';
      $content .= '>' . $defline . "
";
      $content .= wordwrap($residues, $num_bases, "
", TRUE);
      $content .= '';
      $element[$delta] = array(
        // We create a render array to produce the desired markup,
        '#type' => 'markup',
        '#markup' => $content,
      );
    }
  }
  /**
   * @see TripalField::widgetForm()
   */
  public function widgetForm(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
    parent::widgetForm($widget, $form, $form_state, $langcode, $items, $delta, $element);
    $settings = $this->field['settings'];
    $field_name = $this->field['field_name'];
    $field_type = $this->field['type'];
    $field_table = $this->instance['settings']['chado_table'];
    $field_column = $this->instance['settings']['chado_column'];
    // Get the field defaults.
    $residues = '';
    if (count($items) > 0 and array_key_exists('chado-feature__residues', $items[0])) {
      $residues = $items[0]['chado-feature__residues'];
    }
    if (array_key_exists('values', $form_state)) {
      //$residues = tripal_chado_get_field_form_values($field_name, $form_state, 0, 'feature__residues');
    }
    $widget['value'] = array(
      '#type' => 'value',
      '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
    );
    $widget['chado-feature__residues'] = array(
      '#type' => 'textarea',
      '#title' => $element['#title'],
      '#description' => $element['#description'],
      '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
      '#default_value' => $residues,
      '#delta' => $delta,
      '#cols' => 30,
    );
  }
  /**
   * @see TripalField::widgetFormSubmit()
   */
  public function widgetFormSubmit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
    $field_name = $this->field['field_name'];
    // Remove any white spaces.
    $residues = isset($form_state['values'][$field_name][$langcode][$delta]['chado-feature__residues']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-feature__residues'] : '';
    if ($residues) {
      $residues = preg_replace('/\s/', '', $residues);
      $form_state['values'][$field_name][$langcode][$delta]['chado-feature__residues'] = $residues;
    }
  }
  /**
   * @see TripalField::load()
   */
  public function load($entity, $details = array()) {
    $field_name = $this->field['field_name'];
    $feature = $details['record'];
    $num_seqs = 0;
    // We don't want to get the sequence for traditionally large types. They are
    // too big,  bog down the web browser, take longer to load and it's not
    // reasonable to print them on a page.
    if(strcmp($feature->type_id->name,'scaffold') == 0 or
       strcmp($feature->type_id->name,'chromosome') == 0 or
       strcmp($feature->type_id->name,'supercontig') == 0 or
       strcmp($feature->type_id->name,'pseudomolecule') == 0) {
      $entity->{$field_name}['und'][$num_seqs]['value'] = array(
        '@type' => 'SO:0000110',
        'type' => 'sequence_feature',
        'label' => 'Residues',
        'defline' => ">This sequence is too large for this display.",
        'residues' => '',
      );
      $entity->{$field_name}['und'][$num_seqs]['chado-feature__residues'] = '';
    }
    else {
      $feature = chado_expand_var($feature,'field','feature.residues');
      if ($feature->residues) {
        $entity->{$field_name}['und'][$num_seqs]['value'] = array(
          '@type' => 'SO:0000110',
          'type' => 'sequence_feature',
          'label' => 'Raw Sequence',
          'defline' => tripal_get_fasta_defline($feature, '', NULL, '', strlen($feature->residues)),
          'residues' => $feature->residues,
        );
        $entity->{$field_name}['und'][$num_seqs]['chado-feature__residues'] = $feature->residues;
      }
      else {
        $entity->{$field_name}['und'][$num_seqs]['value'] = array();
        $entity->{$field_name}['und'][$num_seqs]['chado-feature__residues'] = '';
      }
    }
    $num_seqs++;
    // Add in the protein sequences. It's faster to provide the SQL rather than
    // to use chado_generate_var based on the type.
    $sql = "
      SELECT F.*
      FROM {feature_relationship} FR
        INNER JOIN {feature} F on FR.subject_id = F.feature_id
        INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
        INNER JOIN {cvterm} RCVT on RCVT.cvterm_id = FR.type_id
      WHERE
        FR.object_id = :feature_id and
        CVT.name = 'polypeptide' and
        RCVT.name = 'derives_from'
      ORDER BY FR.rank ASC
    ";
    $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
    while ($protein = $results->fetchObject()) {
      if ($protein->residues) {
        $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
          '@type' => 'SO:0000104',
          'type' => 'polypeptide',
          'label' => 'Protein Sequence',
          'defline' => tripal_get_fasta_defline($protein, '', NULL, '', strlen($protein->residues)),
          'residues' => $protein->residues,
        );
      }
    }
    // Add in sequences from alignments.
    $options = array(
      'return_array' => 1,
      'include_fk' => array(
        'srcfeature_id' => array(
          'type_id' => 1
        ),
        'feature_id' => array(
          'type_id' => 1
        ),
      ),
    );
    $feature = chado_expand_var($feature, 'table', 'featureloc', $options);
    $featureloc_sequences = $this->get_featureloc_sequences($feature->feature_id, $feature->featureloc->feature_id);
    // Add in the coding sequences. It's faster to provide the SQL rather than
    // to use chado_generate_var based on the type.
    $sql = "
      SELECT F.*
      FROM {feature_relationship} FR
        INNER JOIN {feature} F on FR.subject_id = F.feature_id
        INNER JOIN {cvterm} CVT on CVT.cvterm_id = F.type_id
        INNER JOIN {cvterm} RCVT on RCVT.cvterm_id = FR.type_id
        INNER JOIN {featureloc} FL on FL.feature_id = F.feature_id
      WHERE
        FR.object_id = :feature_id and
        CVT.name = 'CDS' and
        RCVT.name = 'part_of'
      ORDER BY FR.rank ASC
    ";
    $results = chado_query($sql, array(':feature_id' => $feature->feature_id));
    $coding_seq = '';
    while ($CDS = $results->fetchObject()) {
      if ($CDS->residues) {
        $coding_seq .= $CDS->residues;
      }
    }
    if ($coding_seq) {
      $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
        '@type' => 'SO:0000316',
        'type' => 'coding_sequence',
        'label' => 'Coding sequence (CDS)',
        'defline' => tripal_get_fasta_defline($feature, 'CDS', NULL, '', strlen($coding_seq)),
        'residues' => $coding_seq,
      );
    }
    foreach($featureloc_sequences as $src => $attrs){
      // the $attrs array has the following keys
      //   * id:  a unique identifier combining the feature id with the cvterm id
      //   * type: the type of sequence (e.g. mRNA, etc)
      //   * location:  the alignment location
      //   * defline: the definition line
      //   * formatted_seq: the formatted sequences
      //   * featureloc:  the feature object aligned to
      $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
        'residues' => $attrs['residues'],
        '@type' => 'SO:0000110',
        'type' => 'sequence_feature',
        'defline' => tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', strlen($attrs['residues'])),
        'label' => 'Sequence from alignment at ' . $attrs['location'],
      );
      // check to see if this alignment has any CDS. If so, generate a CDS sequence
      $cds_sequence = tripal_get_feature_sequences(
        array(
          'feature_id' => $feature->feature_id,
          'parent_id' => $attrs['featureloc']->srcfeature_id->feature_id,
          'name' => $feature->name,
          'featureloc_id' => $attrs['featureloc']->featureloc_id,
        ),
        array(
          'derive_from_parent' => 1, // CDS are in parent-child relationships so we want to use the sequence from the parent
          'aggregate' => 1, // we want to combine all CDS for this feature into a single sequence
          'sub_feature_types' => array('CDS'), // we're looking for CDS features
          'is_html' => 0
        )
      );
      if (count($cds_sequence) > 0) {
        // the tripal_get_feature_sequences() function can return multiple sequences
        // if a feature is aligned to multiple places. In the case of CDSs we expect
        // that one mRNA is only aligned to a single location on the assembly so we
        // can access the CDS sequence with index 0.
        if ($cds_sequence[0]['residues']) {
          $entity->{$field_name}['und'][$num_seqs++]['value'] = array(
            'residues' => $cds_sequence[0]['residues'],
            '@type' => 'SO:0000316',
            'type' => 'coding_sequence',
            'defline' => tripal_get_fasta_defline($feature, '', $attrs['featureloc'], 'CDS', $cds_sequence[0]['length']),
            'label' => 'Coding sequence (CDS) from alignment at  ' . $attrs['location'],
          );
        }
      }
    }
  }
  /**
   *
   * @param unknown $feature_id
   * @param unknown $featurelocs
   * @return multitype:|Ambigous