package javakurs.uebung02.aufgabe1;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * {@link TypedFeatStruct} is a data wrapper that represents a typed features
 * structure (TFS). A TFS consists of a type and a sorted list of
 * feature-value-pairs that are instances of {@link FeatValPair}.
 *
 * @author Joerg Steffen, DFKI
 * @version $Id: TypedFeatStruct.java,v 1.1 2010/11/11 16:51:25 steffen Exp $
 */
public class TypedFeatStruct {

  /**
   * This contains the type of the TFS.
   */
  private String type;

  /**
   * This contains the list of feature-value-pairs of the TFS.
   */
  private List<FeatValPair> featValPairs;


  /**
   * This creates a new instance of {@link TypedFeatStruct} with the given type.
   *
   * @param type
   *          the type
   */
  public TypedFeatStruct(String type) {

    this.type = type;
    this.featValPairs = null;
  }


  /**
   * This creates a new instance of {@link TypedFeatStruct} for the given type
   * that contains the given feature-value-pairs.
   *
   * @param type
   *          the type
   * @param featValPairs
   *          a list of feature value pairs
   */
  public TypedFeatStruct(String type, List<FeatValPair> featValPairs) {

    this.type = type;
    this.featValPairs = featValPairs;
  }


  /**
   * This returns the type of the TFS.
   *
   * @return the type
   */
  public String getType() {

    return this.type;
  }


  /**
   * This returns the feature-value-pairs of the TFS.
   *
   * @return a list of feature-value-pairs, {@code null} if there are no
   *         feature-value-pairs
   */
  public List<FeatValPair> getFeatValPairs() {

    return this.featValPairs;
  }


  /**
   * This adds the given feature-value-pair at the end of the list of
   * feature-value-pairs.
   *
   * @param pair
   *          a feature-value-pair
   */
  public void addFeatValPair(FeatValPair pair) {

    // only create a list when it's really needed
    if (this.getFeatValPairs() == null) {
      this.featValPairs = new ArrayList<FeatValPair>();
    }
    this.getFeatValPairs().add(pair);
  }


  /**
   * This adds the given feature-value-pair to the list of feature-value-pairs.
   * If the list already contains a FVP with this feature, its value is updated.
   *
   * @param pair
   *          a feature-value-pair
   */
  public void updateFeatValPair(FeatValPair pair) {

    // check if there is already a FVP list
    if (this.getFeatValPairs() == null) {
      this.featValPairs = new ArrayList<FeatValPair>();
    }
    else {
      // iterate over the list and check if the feature is already known
      for (FeatValPair onePair : this.getFeatValPairs()) {
        if (onePair.getFeature().equals(pair.getFeature())) {
          // update value
          onePair.setValue(pair.getValue());
          return;
        }
      }
    }
    // feature not found; just add FVP at the end of the list
    this.getFeatValPairs().add(pair);
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public String toString() {

    return this.toString(0);
  }


  /**
   * This returns a string representation of this feature structure with the
   * given indentation string.
   *
   * @param indent
   *          the indentation to use
   * @return the string representation
   */
  String toString(int indent) {

    // init result
    StringBuilder strRep = new StringBuilder();
    // get OS dependent end-of-line String
    String newline = System.getProperties().getProperty("line.separator");

    // add type
    strRep.append(this.getType());
    // increase indentation by length of type
    indent = indent + this.getType().length();
    if (this.featValPairs != null) {
      // if there are FVPs, add a blank and an opening bracket and increase the
      // indentation accordingly
      strRep.append(" [");
      indent = indent + 2;
      // iterate over FVPs and add their string representation
      Iterator<FeatValPair> it = this.getFeatValPairs().iterator();
      while (it.hasNext()) {
        FeatValPair oneFvp = it.next();
        strRep.append(oneFvp.toString(indent));
        if (it.hasNext()) {
          // if there is another FVP, add a comma, a line break and the current
          // indentation
          strRep.append(",")
            .append(newline)
            .append(String.format("%" + indent + "s", " "));
        }
      }
      strRep.append("]");
    }

    return strRep.toString();
  }
}
