// file: $isip/class/mmedia/AnnotationGraph/AnnotationGraph.h
// version: $Id: AnnotationGraph.h 10675 2009-07-21 01:13:30Z tm334 $
//

// make sure definitions are only made once
//
#ifndef ISIP_ANNOTATION_GRAPH
#define ISIP_ANNOTATION_GRAPH

#ifndef ISIP_STRING
#include <String.h>
#endif

#ifndef ISIP_DOUBLE_LINKED_LIST
#include <DoubleLinkedList.h>
#endif

#ifndef ISIP_PAIR
#include <Pair.h>
#endif

#ifndef ISIP_TRIPLE
#include <Triple.h>
#endif

#ifndef ISIP_HASH_TABLE
#include <HashTable.h>
#endif

#ifndef ISIP_HASH_KEY
#include <HashKey.h>
#endif

#ifndef ISIP_IDENTIFIER
#include <Identifier.h>
#endif

#ifndef ISIP_ANNOTATION
#include <Annotation.h>
#endif

#ifndef ISIP_ANCHOR
#include <Anchor.h>
#endif

#ifndef ISIP_ANNOTATION_INDEX
#include <AnnotationIndex.h>
#endif

// AnnotationGraph: a class used to represent a set of annotations with
// different levels of annotations (sentence, word and phone) of a signal.
//
// Reference:
//
// [1] S. Bird, M. Liberman, A Formal Framework for Linguistic Annotation,
// Linguistic Data Consortium, University of Pennsylvania, Philadelphia,
// Pennsylvania, USA, 2000.
//
// [2] K. Maeda, X. Ma, H. Lee, S. Bird, The Annotation Graph Toolkit:
// Application Developer's Manual (Draft), Linguistic Data Consortium,
// University of Pennsylvania, Philadelphia, Pennsylvania, USA, 2001.
//
class AnnotationGraph {
  
  //--------------------------------------------------------------------------
  //
  // public constants
  //
  //--------------------------------------------------------------------------
public:
  
  // define the class name
  //
  static const String CLASS_NAME;

  // i/o related constants
  //
  static const String DEF_PARAM;
  static const String DEF_ANCHOR;
  static const String DEF_ANNOTATION;    
  static const String PARAM_ID;
  static const String PARAM_TYPE;
  static const String PARAM_ANCHORS;
  static const String PARAM_ANNOTATIONS;  
  static const String PARAM_SEARCH_LEVEL;
  static const String PARAM_SEARCH_LEVEL_INDEX;
  static const String PARAM_SCORE;
  static const String PARAM_FRAME;
  
  //----------------------------------------
  //
  // default values and arguments
  //
  //----------------------------------------

  static const long DEF_INDEX = -1;  
  static const float DEF_OFFSET = 0.0;
  static const float DEF_EPSILON = 0.0;  
  
  //---------------------------------------------------------------------------
  //
  // protected data
  //
  //---------------------------------------------------------------------------
  protected:

  // define the annotation graph id
  //
  String id_d;

  // define the annotation graph type
  //
  String type_d;

  // define the index structure
  //
  AnnotationIndex index_d;

  // define the anchor id issuer
  //
  Identifier* anchorids_d;
  
  // define the annotation id issuer
  //
  Identifier* annotationids_d;

  // define the annotation sequence
  //
  DoubleLinkedList<Annotation> annoseq_d;

  // declare a static debug level for all class instantiations
  //
  static Integral::DEBUG debug_level_d;
  
  // a static memory manager
  //
  static MemoryManager mgr_d;
  
  //---------------------------------------------------------------------------
  //
  // required public methods
  //
  //---------------------------------------------------------------------------
public:
  
  // method: name
  //
  static const String& name() {
    return CLASS_NAME;
  }
  
  static boolean diagnose(Integral::DEBUG debug_level);
  
  // debug methods
  //
  boolean debug(const unichar* msg) const;

  // method: setDebug
  //
  static boolean setDebug(Integral::DEBUG arg) {
    debug_level_d = arg;
    return true;
  }
  
  // method: destructor
  //
  ~AnnotationGraph();

  // method: default constructor
  //
  AnnotationGraph();

  // method: copy constructor
  //
  AnnotationGraph(const AnnotationGraph& arg);

  // method: assign
  //
  boolean assign(const AnnotationGraph& arg);

  // method: operator=
  //
  AnnotationGraph& operator= (const AnnotationGraph& arg) {
    assign(arg);
    return *this;
  }
  
  // method to determine the object size
  //
  long sofSize() const;

  // method: read
  //
  boolean read(Sof& sof, long tag) {
    return read(sof, tag, name());
  }

  // other read methods
  //
  boolean read(Sof& sof, long tag, const String& name);
  boolean readData(Sof& sof, const String& pname = DEF_PARAM,
		   long size = SofParser::FULL_OBJECT, boolean param = true,
		   boolean nested = false);
  
  // method: write
  //
  boolean write(Sof& sof, long tag) const {
    return write(sof, tag, name());
  }

  // other write methods
  //
  boolean write(Sof& sof, long tag, const String& name) const; 
  boolean writeData(Sof& sof, const String& pname =  DEF_PARAM) const;
  
  // method: eq
  //
  boolean eq(const AnnotationGraph& arg) const;

  // method: new
  //
  static void* operator new(size_t arg) {
    return mgr_d.get();
  }

  // method: new[]
  //
  static void* operator new[](size_t arg) {
    return mgr_d.getBlock(arg);
  }

  // method: delete
  //
  static void operator delete(void* arg) {
    mgr_d.release(arg);
  }

  // method: delete[]
  //
  static void operator delete[](void* arg) {
    mgr_d.releaseBlock(arg);
  }

  // method: setGrowSize
  //
  static boolean setGrowSize(long arg) {
    return mgr_d.setGrow(arg);
  }

  // method: clear
  //
  boolean clear(Integral::CMODE cmode = Integral::DEF_CMODE);

  //---------------------------------------------------------------------------
  //
  // class-specific public methods
  //
  //---------------------------------------------------------------------------

  // method: constructor
  //  
  AnnotationGraph(String& id, String& type);

  // method: getId
  //
  String getId() const {
    return id_d;
  }

  // method: setType
  //
  boolean setType(String& type) {
    type_d = type;
    return true;
  }

  // method: getType
  //
  String getType() const {
    return type_d;
  }  

  // method to get the annotation graph
  //
  boolean get(DoubleLinkedList<Pair<Long, Anchor> >& ancrs,
	      DoubleLinkedList<Triple<Long, Long, Annotation> >& annos);
  
  // method to set the annotation graph
  //  
  boolean set(DoubleLinkedList<Pair<Long, Anchor> >& ancrs,
	      DoubleLinkedList<Triple<Long, Long, Annotation> >& annos);
  
  // method that creates and anchor with specified offset and unit
  //
  String createAnchor(String& id, float offset, String& unit);
  String createAnchor(String& id, String& unit);
  
  // method to add an anchor to the graph
  //
  boolean addAnchor(Anchor* ancr);

  // method to delete an anchor from the graph
  //
  boolean deleteAnchor(Anchor* ancr);

  // method that gets the anchor reference by its id
  //
  Anchor* getAnchorById(const String& id);

  // method that create a new annotation
  //
  String createAnnotation(String& id, Anchor* ancr1,
			  Anchor* ancr2, String& type,
			  long channel = Annotation::DEF_CHANNEL_INDEX);
  
  // method that adds a new annotation to the graph
  //
  boolean add(Annotation* anno);

  // method that deletes the annotation from the graph
  //
  boolean deleteAnnotation(Annotation* anno);  

  // method that gets the annotation reference by its id
  //
  Annotation* getById(const String& id);
  
  // method that sets an anchors offset to the specified value
  //
  boolean setAnchorOffset(Anchor* ancr, float offset);

  // method that returns the offset of the specified anchor
  //
  float getAnchorOffset(Anchor* ancr);

  // method that unsets the offset of the specified anchor
  //
  boolean unsetAnchorOffset(Anchor* ancr);

  // method that gets the incoming annotations to the specified node
  //
  boolean getIncomingAnnotationSet(Anchor* ancr,
				   DoubleLinkedList<Annotation>& annos);

  // method that gets the outgoing annotations from the specified node
  //
  boolean getOutgoingAnnotationSet(Anchor* ancr,
				   DoubleLinkedList<Annotation>& annos);

  // method that splits an anchor a in two, creating a new anchor a'
  // having the same offset as the original one. anchor a has all the
  // incoming annotations, while anchor a' has all the outgoing annotations.
  // the new anchor a' is returned.
  //
  Anchor* splitAnchor(Anchor* ancr);

  // method that split an annotation a in two creating a new annotation a'
  // having the same label data as the original one. the two annotations a,
  // a' connect head-to-tail at a new anchor. the new annotation and anchor
  // have identifiers taken from the specified identifier spaces. the new
  // anchor is unanchored, i.e. has no offset.
  //
  Annotation* splitAnnotation(Annotation* anno);

  // method that split an annotation to n annotations. aversion of split
  // which does the split operation n-1 times, i.e. splits the original
  // annotation into n annotations.
  //
  boolean nSplitAnnotation(Annotation* anno,
			   long num_split,
			   DoubleLinkedList<Annotation>& annos);

  // metod that gets the set of anchors, sorted by offsets
  //
  boolean getAnchorSet(DoubleLinkedList<Anchor>& ancrs);

  // method that gets anchors with the specified offset
  //
  boolean getAnchorSetByOffset(float offset,
			       DoubleLinkedList<Anchor>& ancrs,
			       double epsilon = DEF_EPSILON);

  // method that gets the annotations using the type
  //
  boolean getAnnotationSetByType(const String& type,
				 DoubleLinkedList<Annotation>& annos);

  // method that gets the annotations that overlap a particular time offset.
  // gets all annotations whose start anchor offset is smaller than or
  // equal to the given offset AND end anchor offset is greater than 
  // or equal to the given offet
  //
  boolean getAnnotationSetByOffset(float offset,
				   DoubleLinkedList<Annotation>& annos);

    
  // method that get all annotations with its start anchor offset in between
  // the specified values. gets all annotations with its start anchor offset
  // in between the specified values. if both values are 0, return all
  // annotations in the graph
  //
  boolean getAnnotationSeqByOffset(DoubleLinkedList<Annotation>& annos, float begin = DEF_OFFSET, float end = DEF_OFFSET);

  // method that gets one of the annotations which overlap a particular time
  // offset. same as getByOffset except that getAnnotationByOffset returns only
  // one qualified annotation while getByOffset returns all of them
  //
  Annotation* getAnnotationByOffset(float offset);

  // method that gets the nearest used offset to the specified offset
  //
  float getNearestOffset(float arg);
  
  // method that gets all anchors whose offset is the nearest to the
  // specified offset
  //
  boolean getAnchorSetNearestOffset(float offset,
				    DoubleLinkedList<Anchor>& ancrs);

  // method sets the feature value of the annotation
  //
  boolean setFeature(String& id, String& fname, String& fvalue);

  // method to test if a feature exists in the annotation
  //
  boolean existsFeature(String& id, String& fmame);

  // method that deletes the specified feature from the annotation
  //
  boolean deleteFeature(String& id, String& fname);

  // method that gets the value of specified feature in the annotation
  //
  String getFeature(String& id, String& fname);
    
  // method that gets all feature names from the annotation
  //
  boolean getFeatureNames(String& id, Vector<String>& names);
  
  // method to unset all features in the annotation
  //
  boolean unsetFeatures(String& id);
    
  // method to set the specified feature of the annotation to this value
  //
  boolean setFeature(Annotation* anno, String& fname, String& fvalue);

  // method to get the annotations with the feature-value pair
  //
  boolean getAnnotationSetByFeature(const String& feature, const String& value,
				    DoubleLinkedList<Annotation>& annos);
  
  // method to delete the annotations and the corresponding redundant
  // anchors with the feature-value pair
  //
  boolean deleteAnnotationSetByFeature(const String& feature,
				       const String& value);
  
  // method to get all annotations
  //
  boolean getAnnotationSet(DoubleLinkedList<Annotation>& annos);

  // method to purge all the redundant anchors in the graph
  //
  boolean purgeAnchors();
  
  //---------------------------------------------------------------------------
  //
  // private methods
  //
  //---------------------------------------------------------------------------
  private:

  // method that makes a copy of the specified annotation
  //
  Annotation* copyAnnotation(const Annotation* anno);
  
  // method that sets the start anchor of an annotation to the input anchor
  //
  boolean setStartAnchor(Annotation* anno, Anchor* ancr);

  // method that sets the end anchor of an annotation to the specified anchor
  //
  boolean setEndAnchor(Annotation* anno, Anchor* ancr);  
};

//end of include file
//
#endif

