Project

General

Profile

Download (31.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/**
3
 * @file
4
 * Name theming functions.
5
 *
6
 * @copyright
7
 *   (C) 2007-2012 EDIT
8
 *   European Distributed Institute of Taxonomy
9
 *   http://www.e-taxonomy.eu
10
 *
11
 *   The contents of this module are subject to the Mozilla
12
 *   Public License Version 1.1.
13
 * @see http://www.mozilla.org/MPL/MPL-1.1.html
14
 */
15

    
16
/**
17
 * Return HTML for the lectotype citation with the correct layout.
18
 *
19
 * This function prints the lectotype citation with the correct layout.
20
 * Lectotypes are renderized in the synonymy tab of a taxon if they exist.
21
 *
22
 * @param mixed $typeDesignation
23
 *   Object containing the lectotype citation to print.
24
 *
25
 * @return string
26
 *   Valid html string.
27
 */
28
function type_designation_citation_layout($typeDesignation, $footnote_separator = ',') {
29
  $res = '';
30
  $citation = $typeDesignation->citation;
31
  $pages = $typeDesignation->citationMicroReference;
32
  if(isset($typeDesignation->typeStatus->uuid) && isset($typeDesignation->typeStatus->representation_L10n)) {
33
    if ( $typeDesignation->typeStatus->uuid == UUID_NTD_ORIGINAL_DESIGNATION || $typeDesignation->typeStatus->uuid == UUID_NTD_MONOTYPY) {
34
      $res = ' (' . $typeDesignation->typeStatus->representation_L10n . ')';
35
      return $res;
36
    }
37
  }
38

    
39
  if ($citation) {
40
    // $type = $typeDesignation_citation->type;
41
    $year = isset($citation->datePublished->start) ? substr($citation->datePublished->start, 0, 4) : '';
42
    $author = isset($citation->authorTeam->titleCache) ? $citation->authorTeam->titleCache : '';
43
    $res .= ' (designated by ';
44
    $res .= $author;
45
    $res .= ($year ? ' ' . $year : '');
46
    $res .= ($pages ? ': ' . $pages : '');
47
    // $res .= ')';
48

    
49
    // footnotes should be rendered in the parent element so we
50
    // are relying on the FootnoteListKey set there
51
    $fkey_typeDesignation = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $typeDesignation->citation->titleCache);
52
    $res .= theme('cdm_footnote_key', array(
53
      'footnoteKey' => $fkey_typeDesignation,
54
      'separator' => $footnote_separator,
55
      'highlightable' => TRUE,
56
      'separator_off' => TRUE,
57
    )) . ')';
58
  }
59
  return $res;
60
}
61

    
62
/**
63
 * Searches the $collection for the cdm entitiy given as $element.
64
 *
65
 * The elements are compared by their UUID.
66
 *
67
 * @param $element
68
 *  the CDM entitiy to search for
69
 * @param $collection
70
 *  the list of CDM entities to search in
71
 *
72
 * @return boolean TRUE if the $collection contains the $element, otheriwse FALSE
73
 *
74
 * TODO move into module file
75
 */
76
function contains_cdm_entitiy($element, $collection) {
77
  $result = FALSE;
78
  foreach ($collection as $a) {
79
    if ($a->uuid == $element->uuid) {
80
      $result = TRUE;
81
    }
82
  }
83
  return $result;
84
}
85

    
86
/**
87
 * Fiters the array $entity_list of CDM entities by the list
88
 * of $excludes. Any element contained in the $excludes will be removed
89
 * from included int the retuned list.
90
 *
91
 * If the $entity_list is not an array the $excludes will be returned.
92
 */
93
function filter_cdm_entity_list($entity_list, $excludes) {
94
  if (is_array($entity_list)) {
95
    $result = $entity_list;
96
    if ($excludes) {
97
      foreach ($excludes as $exclude) {
98
        if (!contains_cdm_entitiy($exclude, $entity_list)) {
99
          $result[] = $exclude;
100
        }
101
      }
102
    }
103
  }
104
  else {
105
    $result = $excludes;
106
  }
107
  return $result;
108
}
109

    
110
/**
111
 * Renders and array of CDM TypeDesignations
112
 *
113
 * @param array $variables
114
 *   - typeDesignations: an array of cdm TypeDesignation entities to render
115
 */
116
function theme_cdm_typedesignations($variables) {
117
  $typeDesignations = $variables['typeDesignations'];
118

    
119
  // need to add element to render path since type designations
120
  // need other name render template
121
  RenderHints::pushToRenderStack('typedesignations');
122

    
123
  $out = '<ul class="typeDesignations">';
124
  $typeDesignation_footnotes = FALSE;
125
  $is_lectotype = FALSE;
126
  $specimenTypeDesignations = array();
127
  $separator = ',';
128
  foreach ($typeDesignations as $typeDesignation) {
129
    if ($typeDesignation->class == 'SpecimenTypeDesignation') {
130
      // SpecimenTypeDesignations should be ordered. Collect theme here only.
131
      $specimenTypeDesignations[] = $typeDesignation;
132
    }
133
    // It is a lectotype?
134
    else {
135
      if (isset($typeDesignation->typeStatus->uuid) && $typeDesignation->typeStatus->uuid == UUID_NTD_LECTOTYPE) {
136
        $is_lectotype = TRUE;
137
      }
138
      // It's a NameTypeDesignation.
139
      if ($typeDesignation->notDesignated) {
140
        $out .= '<li class="nameTypeDesignation"><span class="status">' . ($is_lectotype ? 'Lectotype' : 'Type') . '</span>: ' . t('not designated') . '</li>';
141
      }
142
      elseif ($typeDesignation->typeName) {
143
        $link_to_name_page = '?q=' . path_to_name($typeDesignation->typeName->uuid);
144
        $out .= '<li class="nameTypeDesignation"><span class="status">' . ($is_lectotype ? 'Lectotype' : 'Type') . '</span>';
145

    
146
        if ($typeDesignation->citation) {
147
          $out .= type_designation_citation_layout($typeDesignation, $separator);
148

    
149
        }
150
        $referenceUri = '';
151
        if (isset($typeDesignation->typeName->nomenclaturalReference)) {
152
          $referenceUri = url(path_to_reference($typeDesignation->typeName->nomenclaturalReference->uuid));
153
        }
154
        $out .= ': ' . theme('cdm_taxonName', array(
155
          'taxonName' => $typeDesignation->typeName,
156
          'nameLink' => $link_to_name_page,
157
          'refenceLink' => $referenceUri,
158
          'show_annotations' => TRUE,
159
          'is_type_designation' => TRUE,
160
          ));
161
      }
162
    }
163
  }
164

    
165
  if (!empty($specimenTypeDesignations)) {
166
    // Sorting might be different for dataportals so this has to be
167
    // parameterized.
168
    usort($specimenTypeDesignations, "compare_specimenTypeDesignationStatus");
169
    foreach ($specimenTypeDesignations as $std) {
170
      $typeReference = '';
171
      if (!empty($std->citation)) {
172
        $author_team = cdm_ws_get(CDM_WS_REFERENCE_AUTHORTEAM, $std->citation->uuid);
173
        $shortCitation = $author_team->titleCache;
174

    
175
        $shortCitation .= (strlen($shortCitation) > 0 ? ' ' : '') . partialToYear($std->citation->datePublished->start);
176
        $missingShortCitation = FALSE;
177
        if (strlen($shortCitation) == 0) {
178
          $shortCitation = theme('cdm_reference', array('reference' => $std->citation));
179
          $missingShortCitation = TRUE;
180
        }
181

    
182
        $typeReference .= '&nbsp;(' . t('designated by');
183
        $typeReference .= '&nbsp;<span class="typeReference ' . ($missingShortCitation ? '' : 'cluetip') . ' no-print" title="' . htmlspecialchars('|' . theme('cdm_reference', array('reference' => $std->citation)) . '|') . '">';
184
        $typeReference .= $shortCitation . '</span>';
185
        if (!empty($std->citationMicroReference)) {
186
          $typeReference .= ':' . $std->citationMicroReference;
187
        }
188
        $typeReference .= ')';
189

    
190
        // footnotes should be rendered in the parent element so we
191
        // are relying on the FootnoteListKey set there
192
        $_fkey2 = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $std->citation->titleCache);
193
        $typeReference .= theme('cdm_footnote_key', array(
194
          'footnoteKey' => $_fkey2,
195
          'separator' => $separator,
196
          'highlightable' => TRUE,
197
          'separator_off' => TRUE,
198
         ));
199
      }
200

    
201
      $derivedUnitFacadeInstance = null;
202

    
203
      $out .= '<li class="specimenTypeDesignation">';
204
      $out .= '<span class="status">'
205
        . ((isset($std->typeStatus->representation_L10n)) ? $std->typeStatus->representation_L10n : t('Type'))
206
        . $typeReference
207
        . '</span>: ';
208

    
209

    
210
      if (isset($std->typeSpecimen)) {
211
        $derivedUnitFacadeInstance = cdm_ws_get(CDM_WS_DERIVEDUNIT_FACADE, $std->typeSpecimen->uuid);
212
      }
213
      if ( isset($derivedUnitFacadeInstance ) ){
214
        $out .= $derivedUnitFacadeInstance->titleCache; // . ': ' . theme('cdm_specimen', array('specimenTypeDesignation' => $derivedUnitFacadeInstance));
215
      }
216

    
217
      // Footnotes for collection acronyms.
218
      // footnotes should be rendered in the parent element so we
219
      // are relying on the FootnoteListKey set there
220
      $_fkey = FootnoteManager::addNewFootnote(
221
          RenderHints::getFootnoteListKey(),
222
          (isset($derivedUnitFacadeInstance->collection->titleCache) ? $derivedUnitFacadeInstance->collection->titleCache : FALSE)
223
        );
224
      $out .= theme('cdm_footnote_key', array('footnoteKey' => $_fkey, 'separator' => $separator));
225
      $out .= '</li>';
226

    
227
    }
228
  }
229

    
230
  $out .= '</ul>';
231

    
232
  RenderHints::popFromRenderStack();
233

    
234
  return $out;
235
}
236

    
237
/**
238
 * FIXME this definitively has to be in another spot.
239
 * just didn't know where to put it right now.
240
 * Compares the status of two SpecimenTypeDesignations
241
 *
242
 * @param string $a
243
 *   A SpecimenTypeDesignations.
244
 * @param string $b
245
 *   SpecimenTypeDesignations.
246
 */
247
function compare_specimenTypeDesignationStatus($a, $b) {
248
  /*
249
  This is the desired sort order as of now: Holotype Isotype Lectotype
250
  Isolectotype Syntype.
251
  TODO Basically, what we are trying to do is, we define
252
  an ordered array of TypeDesignation-states and use the index of this array
253
  for comparison. This array has to be filled with the cdm- TypeDesignation
254
  states and the order should be parameterisable inside the dataportal.
255
  */
256
  // Make that static for now.
257
  $typeOrder = array(
258
    'Holotype',
259
    'Isotype',
260
    'Lectotype',
261
    'Isolectotype',
262
    'Syntype',
263
  );
264

    
265
  $aQuantifier = FALSE;
266
  $bQuantifier = FALSE;
267
  if (isset($a->typeStatus->label) && isset($b->typeStatus->label)) {
268
    $aQuantifier = array_search($a->typeStatus->label, $typeOrder);
269
    $bQuantifier = array_search($b->typeStatus->label, $typeOrder);
270
  }
271
  if ($aQuantifier == $bQuantifier) {
272
    // Sort alphabetically.
273
    return (isset($a->typeStatus->label) && isset($b->typeStatus->label) && $a->typeStatus->label < $b->typeStatus->label) ? -1 : 1;
274
  }
275
  return ($aQuantifier < $bQuantifier) ? -1 : 1;
276
}
277

    
278
/**
279
 * @todo Please document this function.
280
 * @see http://drupal.org/node/1354
281
 */
282
function theme_cdm_homotypicSynonymLine($variables) {
283
  $taxon = $variables['taxon'];
284
  $out = '';
285
  $out .= '<li class="synonym">' . cdm_related_taxon($taxon, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
286

    
287
  return $out;
288
}
289

    
290
/**
291
 * @todo Please document this function.
292
 * @see http://drupal.org/node/1354
293
 */
294
function theme_cdm_heterotypicSynonymyGroup($variables) {
295
  $homotypicalGroup = $variables['homotypicalGroup'];
296
  RenderHints::pushToRenderStack('heterotypicSynonymyGroup');
297

    
298
  $out = '';
299
  $out = '<div class="heterotypic-synonymy-group"><ul class="heterotypicSynonymyGroup">';
300
  $footnoteListKey = (isset($homotypicalGroup[0]) ? $homotypicalGroup[0]->uuid : 'NULL');
301
  RenderHints::setFootnoteListKey($footnoteListKey);
302

    
303
  $is_first_entry = TRUE;
304
  $typeDesignations = NULL;
305
  foreach ($homotypicalGroup as $synonym) {
306
    if ($is_first_entry) {
307
      $is_first_entry = FALSE;
308
      $typeDesignations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $synonym->name->uuid);
309
      // Is first list entry.
310
      $out .= '<li class="firstentry synonym">' . cdm_related_taxon($synonym, UUID_HETEROTYPIC_SYNONYM_OF) . '</li>';
311
    }
312
    else {
313
      $out .= '<li class="synonym">' . cdm_related_taxon($synonym, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
314
    }
315
  }
316

    
317
  if ($typeDesignations) {
318
    $out .= theme('cdm_typedesignations', array('typeDesignations' => $typeDesignations));
319
  }
320
  $out .= '</ul>';
321

    
322
  // ------- footnotes ------- //
323
  $out .= '<ul class="footnotes">';
324
  $out .= theme('cdm_annotation_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
325
  $out .= theme('cdm_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
326
  $out .= '</ul>';
327

    
328
  $out .= '</div>';
329

    
330
  RenderHints::popFromRenderStack();
331
  return $out;
332
}
333

    
334
/**
335
 * Renders the homotypic synonymy group for the accepted taxon in the synonymy.
336
 *
337
 * Foonotes of the accepted taxon will also be rendered here in the
338
 * homotypic synonymy group even if the synonymList or prependedSynonyms are
339
 * empty. Therefore  the homotypic group and accepted taxon share the  same
340
 * footnote key.
341
 *
342
 * @param $variables
343
 *   an associative array:
344
 *   - synonymList: the list of cdm Synonym entities
345
 *   - accepted_taxon_uuid: the uuid of the accepted taxon
346
 *   - prependedSynonyms: further synonyms which should be prepended
347
 *      before the actual list of synonyms
348
 */
349
function theme_cdm_homotypicSynonymyGroup($variables) {
350
  $synonymList = $variables['synonymList'];
351
  $accepted_taxon_name_uuid = $variables['accepted_taxon_name_uuid'];
352
  $prependedSynonyms = $variables['prependedSynonyms'];
353

    
354
  RenderHints::pushToRenderStack('homotypicSynonymyGroup');
355

    
356
  $homonym_typeDesignations = NULL;
357

    
358
  // TODO improve typeDesignations retrieval: wouldn't it be suffcient to retrieve all typeDesignations
359
  // only from the accepted taxon?
360
  $accepted_typeDesignations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $accepted_taxon_name_uuid);
361

    
362
  $out = '<div class="homotypic-synonymy-group">';
363

    
364
  if (isset ($accepted_typeDesignations) || is_array($prependedSynonyms) || is_array($synonymList)) {
365
    $out .= '<ul class="homotypicSynonyms">';
366
  if (!empty($prependedSynonyms)) {
367
    foreach ($prependedSynonyms as $taxon) {
368
      $out .= '<li class="synonym">' . cdm_related_taxon($taxon, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
369
    }
370
  }
371

    
372
  $homonym_typeDesignations = NULL;
373
  if (isset($synonymList[0])) {
374
    foreach ($synonymList as $synonym) {
375
      $out .= '<li class="synonym">' . cdm_related_taxon($synonym, UUID_HOMOTYPIC_SYNONYM_OF) . '</li>';
376
    }
377
    $homonym_typeDesignations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $synonymList[0]->name->uuid);
378
  }
379

    
380
  // type designations
381
  if ($accepted_typeDesignations) {
382
    $type_designations = filter_cdm_entity_list($homonym_typeDesignations, $accepted_typeDesignations);
383
  }
384
  else {
385
    $type_designations = $homonym_typeDesignations;
386
  }
387

    
388
  if ($type_designations) {
389
    $out .= theme('cdm_typedesignations', array('typeDesignations' => $type_designations));
390
  }
391

    
392
  }
393

    
394
  $out .= '</ul>';
395

    
396
  // ------- footnotes ------- //
397

    
398
  // all foonotes of the homotypic group and also of the accepted taxon are
399
  // rendered here, both should have the same footnote key
400
  $out .= '<ul class="footnotes">';
401
  $out .= theme('cdm_annotation_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
402
  $out .= theme('cdm_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey(), 'enclosingTag' => 'li'));
403
  $out .= '</ul>';
404

    
405
  $out .= '</div>';
406

    
407

    
408
  RenderHints::popFromRenderStack();
409
  return $out;
410
}
411

    
412
/**
413
 * Provides the name render template to be used within the page elements identified the the $renderPath.
414
 *
415
 * The render templates arrays contains one or more name render template to be used within the page elements identified the the
416
 * renderPath. The renderPath is the key of the subelements whereas the value is the name render template.
417
 * The following keys are curretly recogized:
418
 *
419
 *   - list_of_taxa:
420
 *   - acceptedFor:
421
 *   - taxon_page_synonymy
422
 *   - typedesignations
423
 *   - taxon_page_title
424
 *   - polytomousKey
425
 *   - na: name + authorship
426
 *   - nar:name + authorship + reference
427
 *   - #DEFAULT
428
 *
429
 * A single render template can be used for multiple render paths. In this case the according key of the render templates
430
 * array element should be the list of these render paths concatenated by ONLY a comma character without any whitespace.
431
 *
432
 * A render template is an associative array. The keys of this array are referring to the keys as defined in the part
433
 * definitions array.
434
 * @see get_partDefinition($taxonNameType) for more information
435
 *
436
 * The value of the render template element must be set to TRUE in order to let this part being rendered.
437
 * The namePart, nameAuthorPart and referencePart can also hold an associative array with a single
438
 * element: array('#uri' => TRUE). The value of the #uri element will be replaced by the according
439
 * links if the paramters $nameLink or $refenceLink are set.
440
 *
441
 * @param string $renderPath
442
 *   The render path can consist of multiple dot separated elements
443
 *   @see RenderHints::getRenderPath()
444
 * @param string $nameLink
445
 *   The link path ot URL to be used for name parts if a link is forseen in the template
446
 *   matching the given $renderPath.
447
 * @param string $referenceLink
448
 *   The link path ot URL to be used for nomencaltural reference parts if a link is forseen
449
 *   in the template matching the given $renderPath.
450
 * @return array
451
 *   An assciative array, the render template
452
 */
453
function get_nameRenderTemplate($renderPath, $nameLink = NULL, $refenceLink = NULL) {
454

    
455
  $template = NULL;
456

    
457
  static $default_render_templates = NULL;
458
  if (!isset($default_render_templates)) {
459
    $default_render_templates = unserialize(CDM_NAME_RENDER_TEMPLATES_DEFAULT);
460
  }
461
  static $render_templates = NULL;
462
  if($render_templates == NULL) {
463
      $render_templates = variable_get(CDM_NAME_RENDER_TEMPLATES, $default_render_templates);
464
      // needs to be converted to an array
465
      $render_templates = convert_to_array($render_templates);
466
  }
467

    
468
  // get the base element of the renderPath
469
  if (($separatorPos = strpos($renderPath, '.')) > 0) {
470
    $renderPath_base = substr($renderPath, 0, $separatorPos);
471
  } else {
472
    $renderPath_base = $renderPath;
473
  }
474

    
475
  // 1. try to find a template using the render path base element
476
  if(array_key_exists($renderPath_base, $render_templates)){
477
    $template = (array)$render_templates[$renderPath_base];
478
  }
479

    
480
  // 2. Find best matching default RenderTemplate in theme
481
  // by stripping the dot separated render path element by element
482
  // is no matching template is found the DEFAULT will be used.
483
  while (!is_array($template) && strlen($renderPath) > 0) {
484

    
485
    foreach ($render_templates as $k => $t) {
486
      if (strpos(',' . $k . ',', $renderPath ) !== FALSE) {
487
        $template = $t;
488
        break;
489
      }
490
    }
491

    
492
    // shorten by one element
493
    $renderPath = substr($renderPath, 0, strrpos($renderPath, '.'));
494
    /*
495
    if(!is_array($template)){
496
      echo "<br/>->".$renderPath;
497
    }
498
    */
499
  }
500

    
501
  // 3. Otherwise get default RenderTemplate from theme.
502
  if (!is_array($template)) {
503
      $template = $render_templates['#DEFAULT'];
504
  }
505

    
506
  // --- set the link uris to the according template fields if they exist
507
  if(isset($template['nameAuthorPart']) && isset($template['nameAuthorPart']['#uri'])) {
508
    if ($nameLink) {
509
      $template['nameAuthorPart']['#uri'] = $nameLink;
510
    }
511
    else {
512
      unset($template['nameAuthorPart']['#uri']);
513
    }
514
  }
515

    
516
  if ($nameLink && isset($template['namePart']['#uri'])) {
517
    $template['namePart']['#uri'] = $nameLink;
518
  }
519
  else {
520
    unset($template['namePart']['#uri']);
521
  }
522

    
523
  if ($refenceLink && isset($template['referencePart']['#uri'])) {
524
    $template['referencePart']['#uri'] = $refenceLink;
525
  }
526
  else {
527
    unset($template['referencePart']['#uri']);
528
  }
529

    
530
  return $template;
531
}
532

    
533
/**
534
 * The part definitions define the specific parts of which a rendered taxon name plus additional information will consist.
535
 *
536
 * A full taxon name plus additional information can consist of the following elements:
537
 *
538
 *   - name: the taxon name inclugin rank nbut without author
539
 *   - authorTeam:  The authors of a reference, also used in taxon names
540
 *   - authors:  The authors of a reference, also used in taxon names
541
 *   - reference: the nomenclatural reference,
542
 *   - microreference:  Volume, page number etc.
543
 *   - status:  The nomenclatural status of a name
544
 *   - description: name descriptions like protologues etc ...
545
 *
546
 * These elements are combined in the part definitions array to from the specific parts to be rendered.
547
 * Usually the following parts are formed:
548
 *
549
 * The name "Lapsana communis L., Sp. Pl.: 811. 1753" shall be an example here:
550
 *  - namePart: the name and rank (in example: "Lapsana communis")
551
 *  - authorshipPart: the author (in example: "L.")
552
 *  - nameAuthorPart: the combination of name and author part (in example: "Lapsana communis L.").
553
 *     This is useful for zoological names where the authorshipPart belongs to the name and both should
554
 *     be combined when a link to the taxon is rendered.
555
 *  - referencePart: the nomencaltural reference (in example: "Sp. Pl. 1753")
556
 *  - microreferencePart: usually the page number (in example ": 811.")
557
 *  - statusPart: the nomenclatorical status
558
 *  - descriptionPart:
559
 *
560
 * Each set of parts is dedicated to render a specific TaxonName type, the type names are used as keys for the
561
 * specific parts part definitions:
562
 *
563
 *  - BotanicalName
564
 *  - ZoologicalName
565
 *  - #DEFAULT:  covers ViralNames and general NonViralNames
566
 *
567
 * An example:
568
 * @code
569
 * array(
570
 *    'ZoologicalName' => array(
571
 *        'namePart' => array('name' => TRUE),
572
 *        'referencePart' => array('authorTeam' => TRUE),
573
 *        'microreferencePart' => array('microreference' => TRUE),
574
 *        'statusPart' => array('status' => TRUE),
575
 *        'descriptionPart' => array('description' => TRUE),
576
 *    ),
577
 *    'BotanicalName' => array(
578
 *        'namePart' => array(
579
 *            'name' => TRUE,
580
 *            'authors' => TRUE,
581
 *        ),
582
 *        'referencePart' => array(
583
 *            'reference' => TRUE,
584
 *            'microreference' => TRUE,
585
 *        ),
586
 *        'statusPart' => array('status' => TRUE),
587
 *        'descriptionPart' => array('description' => TRUE),
588
 *    ),
589
 *  );
590
 * @endcode
591
 *
592
 * @todo document this function.
593
 */
594
function get_partDefinition($taxonNameType) {
595

    
596
  static $default_part_definitions = null;
597
  if (!isset($default_part_definitions)) {
598
    $default_part_definitions= unserialize(CDM_PART_DEFINITIONS_DEFAULT);
599
  }
600

    
601
  static $part_definitions = null;
602
  if (!isset($part_definitions)) {
603
     $part_definitions = convert_to_array(variable_get(CDM_PART_DEFINITIONS, $default_part_definitions));
604
  }
605

    
606
  if (array_key_exists($taxonNameType, $part_definitions)) {
607
    return $part_definitions[$taxonNameType];
608
  } else {
609
    return $part_definitions['#DEFAULT']; // covers ViralNames and general NonViralNames
610
  }
611

    
612
}
613

    
614
/**
615
 * @param $variables
616
 *    - taxonName : cdm TaxonNameBase instance
617
 *    - nameLink: URI to the taxon, @see path_to_taxon(), must be processed by uri() before passing to this method
618
 *    - refenceLink: URI to the reference, @see path_to_reference(), must be processed by uri() before passing to this method
619
 *    - show_annotations: ...
620
 *    - is_type_designation: ...
621
 *    - skiptags: an array of tags to skip ....
622
 *
623
 * @todo Please document this function.
624
 * @see http://drupal.org/node/1354
625
 */
626
function theme_cdm_taxonName($variables) {
627

    
628
  $taxonName = $variables['taxonName'];
629
  $nameLink = $variables['nameLink'];
630
  $refenceLink = $variables['refenceLink'];
631
  $show_annotations = $variables['show_annotations'];
632
  $is_type_designation = $variables['is_type_designation'];
633
  $skiptags = $variables['skiptags'];
634

    
635
  $renderTemplate = get_nameRenderTemplate(RenderHints::getRenderPath(), $nameLink, $refenceLink);
636
  $partDefinition = get_partDefinition($taxonName->class);
637

    
638
  // Apply definitions to template.
639
  foreach ($renderTemplate as $part => $uri) {
640

    
641
    if (isset($partDefinition[$part])) {
642
      $renderTemplate[$part] = $partDefinition[$part];
643
    }
644
    if (is_array($uri) && isset($uri['#uri'])) {
645
      $renderTemplate[$part]['#uri'] = $uri['#uri'];
646
    }
647
  }
648

    
649
  normalize_TaggedName($taxonName->taggedName);
650

    
651
  $firstEntryIsValidNamePart = isset($taxonName->taggedName) && is_array($taxonName->taggedName) && isset($taxonName->taggedName[0]->text) && is_string($taxonName->taggedName[0]->text) && $taxonName->taggedName[0]->text != '' && isset($taxonName->taggedName[0]->type) && $taxonName->taggedName[0]->type == 'name';
652
  $lastAuthorElementString = FALSE;
653

    
654
  // Got to use second entry as first one, see ToDo comment below ...
655
  if ($firstEntryIsValidNamePart) {
656

    
657
    $taggedName = $taxonName->taggedName;
658
    $hasNamePart_with_Authors = isset($renderTemplate['namePart']) && isset($renderTemplate['namePart']['authors']);
659
    $hasNameAuthorPart_with_Authors = isset($renderTemplate['nameAuthorPart']) && isset($renderTemplate['nameAuthorPart']['authors']);
660

    
661
    if (!(($hasNamePart_with_Authors) || ($hasNameAuthorPart_with_Authors))) {
662
      // Find author and split off from name.
663
      // TODO expecting to find the author as the last element.
664
      /*
665
      if($taggedName[count($taggedName)- 1]->type == 'authors'){
666
        $authorTeam = $taggedName[count($taggedName)- 1]->text;
667
        unset($taggedName[count($taggedName)- 1]);
668
      }
669
      */
670

    
671
      // Remove all authors.
672
      $taggedNameNew = array();
673
      foreach ($taggedName as $element) {
674
        if ($element->type != 'authors') {
675
          $taggedNameNew[] = $element;
676
        }
677
        else {
678
          $lastAuthorElementString = $element->text;
679
        }
680
      }
681
      $taggedName = $taggedNameNew;
682
    }
683
    $name = '<span class="' . $taxonName->class . '">' . theme('cdm_taggedtext2html', array(
684
      'taggedtxt' => $taggedName,
685
      'tag' => 'span',
686
      'glue' => ' ',
687
      'skiptags' => $skiptags,
688
      )) . '</span>';
689
  }
690
  else {
691
    $name = '<span class="' . $taxonName->class . '_titleCache">' . $taxonName->titleCache . '</span>';
692
  }
693

    
694
  // Fill name into $renderTemplate.
695
  array_setr('name', $name, $renderTemplate);
696

    
697
  // Fill with authorTeam.
698
  /*
699
  if($authorTeam){
700
    $authorTeamHtml = ' <span class="authorTeam">'.$authorTeam.'</span>';
701
    array_setr('authorTeam', $authorTeamHtml, $renderTemplate);
702
  }
703
  */
704

    
705
  // Fill with reference.
706
  if (isset($renderTemplate['referencePart']) && !$is_type_designation) {
707

    
708
    // default separator
709
    $separator = '';
710

    
711
    // [Eckhard]:"Komma nach dem Taxonnamen ist grunsätzlich falsch,
712
    // Komma nach dem Autornamen ist überall dort falsch, wo ein "in" folgt."
713
    if (isset($renderTemplate['referencePart']['reference']) && isset($taxonName->nomenclaturalReference)) {
714
      $microreference = NULL;
715
      if (isset($renderTemplate['referencePart']['microreference'])&& isset($taxonName->nomenclaturalMicroReference)) {
716
        $microreference = $taxonName->nomenclaturalMicroReference;
717
      }
718
      $citation = cdm_ws_getNomenclaturalReference($taxonName->nomenclaturalReference->uuid, $microreference);
719

    
720
      // Find preceding element of the reference.
721
      $precedingKey = get_preceding_contentElementKey('reference', $renderTemplate);
722
      if (str_beginsWith($citation, ", in")) {
723
        $citation = substr($citation, 2);
724
        $separator = ' ';
725
      }
726
      elseif (!str_beginsWith($citation, "in") && $precedingKey == 'authors') {
727
        $separator = ', ';
728
      } else {
729
        $separator = ' ';
730
      }
731

    
732

    
733
      $referenceArray['#separator'] = $separator;
734
      $referenceArray['#html'] = '<span class="reference">' . $citation . '</span>';
735
      array_setr('reference', $referenceArray, $renderTemplate);
736
    }
737

    
738
    // If authors have been removed from the name part the last named authorteam
739
    // should be added to the reference citation, otherwise, keep the separator
740
    // out of the reference.
741
    if (isset($renderTemplate['referencePart']['authors']) && $lastAuthorElementString) {
742
      // If the nomenclaturalReference citation is not included in the
743
      // reference part but diplay of the microreference
744
      // is wanted, append the microreference to the authorTeam.
745
      $citation = '';
746
      if (!isset($renderTemplate['referencePart']['reference']) && isset($renderTemplate['referencePart']['microreference'])) {
747
        $separator = ": ";
748
        $citation = $taxonName->nomenclaturalMicroReference;
749
      }
750
      $referenceArray['#html'] = ' <span class="reference">' . $lastAuthorElementString . $separator . $citation . '</span>';
751
      array_setr('authors', $referenceArray, $renderTemplate);
752
    }
753
  }
754
  if (isset($renderTemplate['referenceYearPart']['reference.year'])) {
755
    if(isset($taxonName->nomenclaturalReference->datePublished)){
756
      $referenceArray['#html'] = ' <span class="reference">' . timePeriodToString($taxonName->nomenclaturalReference->datePublished) . '</span>';
757
      array_setr('reference.year', $referenceArray, $renderTemplate);
758
    }
759
  }
760

    
761
  // Fill with status.
762
  $statusHtml = '';
763
  if (isset($taxonName->status) && is_array($taxonName->status)) {
764
    if (array_setr('status', TRUE, $renderTemplate)) {
765
      if (isset($taxonName->status[0])) {
766
        foreach ($taxonName->status as $status) {
767
          $statusHtml .= ', ' . $status->type->representation_L10n_abbreviatedLabel;
768
        }
769
      }
770
      array_setr('status', '<span class="nomenclatural_status">' . $statusHtml . '</span>', $renderTemplate);
771
    }
772
  }
773

    
774
  // Fill with protologues etc...
775
  $descriptionHtml = '';
776
  if (array_setr('description', TRUE, $renderTemplate)) {
777
    $descriptions = cdm_ws_get(CDM_WS_PORTAL_NAME_DESCRIPTIONS, $taxonName->uuid);
778
    foreach ($descriptions as $description) {
779
      if (!empty($description)) {
780
        foreach ($description->elements as $description_element) {
781
          $second_citation = '';
782
          if (isset($description_element->multilanguageText_L10n) && $description_element->multilanguageText_L10n->text) {
783
            $second_citation = '[& ' . $description_element->multilanguageText_L10n->text . '].';
784
          }
785
          $descriptionHtml .= $second_citation;
786
          $descriptionHtml .= theme("cdm_media", array(
787
              'descriptionElement' => $description_element,
788
              'mimeTypePreference' => array(
789
                  'application/pdf',
790
                  'image/png',
791
                  'image/jpeg',
792
                  'image/gif',
793
                  'text/html',
794
                )
795
              )
796
            );
797

    
798
        }
799
      }
800
    }
801
    array_setr('description', $descriptionHtml, $renderTemplate);
802
  }
803

    
804
  // Render.
805
  $out = '<span data-cdm-ref="/name/' . $taxonName->uuid . '">';
806

    
807
  foreach ($renderTemplate as $partName => $part) {
808
    $separator = '';
809
    $partHtml = '';
810
    $uri = FALSE;
811
    if (!is_array($part)) {
812
      continue;
813
    }
814
    if (isset($part['#uri']) && is_string($part['#uri'])) {
815
      $uri = $part['#uri'];
816
      unset($part['#uri']);
817
    }
818
    foreach ($part as $key => $content) {
819
      $html = '';
820
      if (is_array($content)) {
821
        $html = $content['#html'];
822
        if(isset($content['#separator'])) {
823
          $separator = $content['#separator'];
824
        }
825
      }
826
      elseif (is_string($content)) {
827
        $html = $content;
828
      }
829
      $partHtml .= '<span class="' . $key . '">' . $html . '</span>';
830
    }
831
    if ($uri) {
832
      // cannot use l() here since the #uri aleady should have been processed through uri() at this point
833
      $out .= $separator . '<a href="' . $uri . '" class="' . $partName . '">' . $partHtml . '</a>';
834

    
835
    }
836
    else {
837
      $out .= $separator . $partHtml;
838
    }
839
  }
840
  $out .= '</span>';
841
  if ($show_annotations) {
842
    // $out .= theme('cdm_annotations_as_footnotekeys', $taxonName);
843
  }
844
  return $out;
845
}
846

    
847
/**
848
 * Recursively searches the array for the $key and sets the given value.
849
 *
850
 * @param mixed $key
851
 *   Key to search for.
852
 * @param mixed $value
853
 *   Value to set.'
854
 * @param array $array
855
 *   Array to search in.
856
 *
857
 * @return bool
858
 *   True if the key has been found.
859
 */
860
function &array_setr($key, $value, array &$array) {
861
  $res = NULL;
862
  foreach ($array as $k => &$v) {
863
    if ($key == $k) {
864
      $v = $value;
865
      return $array;
866
    }
867
    elseif (is_array($v)) {
868
      $innerArray = array_setr($key, $value, $v);
869
      if ($innerArray) {
870
        return $array;
871
      }
872
    }
873
  }
874
  return $res;
875
}
876

    
877
/**
878
 * @todo Please document this function.
879
 * @see http://drupal.org/node/1354
880
 */
881
function &get_preceding_contentElement($contentElementKey, array &$renderTemplate) {
882
  $res = NULL;
883
  $precedingElement = NULL;
884
  foreach ($renderTemplate as &$part) {
885
    foreach ($part as $key => &$element) {
886
      if ($key == $contentElementKey) {
887
        return $precedingElement;
888
      }
889
      $precedingElement = $element;
890
    }
891
  }
892
  return $res;
893
}
894

    
895
/**
896
 * @todo Please document this function.
897
 * @see http://drupal.org/node/1354
898
 */
899
function &get_preceding_contentElementKey($contentElementKey, array &$renderTemplate) {
900
  $res = NULL;
901
  $precedingKey = NULL;
902
  foreach ($renderTemplate as &$part) {
903
    if (is_array($part)) {
904
      foreach ($part as $key => &$element) {
905
        if ($key == $contentElementKey) {
906
          return $precedingKey;
907
        }
908
        if (!str_beginsWith($key, '#')) {
909
          $precedingKey = $key;
910
        }
911
      }
912
    }
913
  }
914
  return $res;
915
}
(4-4/9)