package com.pengyifan.bioc;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

public abstract class BioCStructure implements BioCInfons {

  private Map<String, String> infons;
  private List<BioCAnnotation> annotations;
  private List<BioCRelation> relations;

  /**
   * Constructs an empty structure.
   */
  public BioCStructure() {
    infons = Maps.newHashMap();
    annotations = Lists.newArrayList();
    relations = Lists.newArrayList();
  }

  /**
   * Constructs a structure containing the information of the specified structure.
   *
   * @param structure the structure whose information is to be placed into this structure
   */
  public BioCStructure(BioCStructure structure) {
    this();
    infons.putAll(structure.infons);
    annotations.addAll(structure.annotations);
    relations.addAll(structure.relations);
  }

  /**
   * Adds annotation in this structure.
   *
   * @param annotation annotation
   */
  public void addAnnotation(BioCAnnotation annotation) {
    checkNotNull(annotation, "annotation cannot be null");
    checkArgument(!getAnnotation(annotation.getID()).isPresent(),
        "Duplicated annotation: %s", annotation);
    this.annotations.add(annotation);
  }


  /**
   * Adds relation in this structure.
   *
   * @param relation relation
   */
  public void addRelation(BioCRelation relation) {
    checkNotNull(relation, "relation cannot be null");
    checkArgument(!getRelation(relation.getID()).isPresent(), "Duplicated relation: %s", relation);
    this.relations.add(relation);
  }

  /**
   * Clears all annotations.
   */
  public void clearAnnotations() {
    annotations.clear();
  }


  /**
   * Clears all ie.
   */
  public void clearRelations() {
    relations.clear();
  }


  /**
   * Returns the annotation at the specified position in this structure.
   *
   * @param annotationID id of a specified annotation
   * @return the annotation of the specified ID in this document
   */
  public Optional<BioCAnnotation> getAnnotation(String annotationID) {
    return annotations.stream()
        .filter(a -> a.getID().equals(annotationID))
        .findFirst();
  }

  /**
   * Annotations on the text of the structure.
   *
   * @return annotations on the text of the structure
   */
  public Collection<BioCAnnotation> getAnnotations() {
    return annotations;
  }


  /**
   * Returns the information in the structure.
   *
   * @return the information in the structure
   */
  public Map<String, String> getInfons() {
    return infons;
  }

  /**
   * Returns the relation at the specified position in this structure.
   *
   * @param relationID id of a specified relation
   * @return the relation of the specified ID in this structure
   */
  public Optional<BioCRelation> getRelation(String relationID) {
    return relations.stream()
        .filter(r -> r.getID().equals(relationID))
        .findAny();
  }

  /**
   * Relations between the annotations and possibly other ie on the text
   * of the document.
   *
   * @return ie of the structure
   */
  public Collection<BioCRelation> getRelations() {
    return relations;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == this) {
      return true;
    }
    if (!(obj instanceof BioCStructure)) {
      return false;
    }
    BioCStructure rhs = (BioCStructure) obj;
    return Objects.equals(infons, rhs.infons)
        && Objects.equals(annotations, rhs.annotations)
        && Objects.equals(relations, rhs.relations);
  }

  @Override
  public int hashCode() {
    return Objects.hash(infons, annotations, relations);
  }
}

@@ -123,116 +123,9 @@
 til.
-Collection;%0Aimport java.util.List;%0Aimport java.util.Map;%0Aimport java.util.Objects;%0Aimport java.util.Optional
+*
 ;%0A%0Ai
@@ -1958,32 +1958,26 @@
 e specified 
-position
+ID
  in this str
@@ -2099,24 +2099,25 @@
 in this 
-document
+structure
 %0A   */%0A 
@@ -2263,32 +2263,32 @@
 (annotationID))%0A
-
         .findFir
@@ -2290,32 +2290,724 @@
 ndFirst();%0A  %7D%0A%0A
+  /**%0A   * Returns the annotation of the specified role of the relation in this structure.%0A   *%0A   * @param relation the specified relation%0A   * @param role     the specified role in the relation%0A   * @return the annotation of the specified role of the relation in this structure%0A   * @throws NoSuchElementException if there is no role in the relation%0A   */%0A  public Optional%3CBioCAnnotation%3E getAnnotation(BioCRelation relation, String role) %7B%0A    try %7B%0A      return getAnnotation(relation.getNode(role).get().getRefid());%0A    %7D catch (NoSuchElementException e) %7B%0A      throw new NoSuchElementException(%0A          String.format(%22Cannot find %25s in relation %5B%25s%5D%22, relation, role));%0A    %7D%0A  %7D%0A%0A
   /**%0A   * Annot

get the annotation given the role of a relation