/////////////////////////////////////////////////////////////////////////////
// File:            gnMultiSpec.h
// Purpose:         abstract multiple spec class
// Description:     For specs which can contain multiple data sources
// Changes:        
// Version:         libGenome 0.5.1 
// Author:          Aaron Darling 
// Modified by:     
// Copyright:       (c) Aaron Darling 
// Licenses:        See COPYING file for details 
/////////////////////////////////////////////////////////////////////////////
#ifndef _gnMultiSpec_h_
#define _gnMultiSpec_h_

#include "gn/gnDefs.h"

#include <vector>
#include <string>

#include "gn/gnClone.h"
#include "gn/gnBaseFeature.h"
#include "gn/gnBaseHeader.h"
#include "gn/gnBaseSpec.h"

/**
 * This class defines an interface for specs which have multiple subspecs
 * containing sequence data.
 */
class GNDLLEXPORT gnMultiSpec : public gnBaseSpec
{
public:
	gnMultiSpec(){}
	/**
	 * Destructor, frees memory.
	 */
	virtual ~gnMultiSpec(){}
	virtual gnMultiSpec* Clone() const = 0;

// Base Spec stuff
	virtual gnSeqI GetLength() const;
	virtual void CropStart( gnSeqI cropLen );
	virtual void CropEnd( gnSeqI cropLen );

	virtual string GetSourceName() const;
	virtual void SetSourceName(const string& sourceName);
	virtual void Clear();

	virtual boolean SeqRead(const gnSeqI start, gnSeqC* buf, uint32& bufLen, const uint32 contigI ) const;

//Multispec stuff
	/**
	 * Returns the number of subspecs this spec contains.
	 * @return The number of subspecs this spec contains.
	 */
	virtual uint32 GetSpecListLength() const = 0;
	/**
	 * Get the spec at index i in the list of subspecs.
	 * @param i The index of the spec
	 * @return The spec.
	 */
	virtual gnBaseSpec* GetSpec( const uint32 i ) const = 0;
	/**
	 * Get the spec from the list of subspecs which contains the specified base pair.
	 * @param baseI The base pair index.
	 * @return The spec.
	 */
	virtual gnBaseSpec* GetSpecByBase( const gnSeqI baseI ) const = 0;
	/**
	 * Get the index of the subspec which contains the specified base pair.
	 * @param baseI The base pair index.
	 * @return The subspec index.
	 */
	virtual uint32 GetSpecIndexByBase( const gnSeqI baseI ) const;
	/**
	 * Get the index of the spec which has the given name.
	 * @param name The name of the spec to find.
	 * @return The spec index.
	 */
	virtual uint32 GetSpecIndexByName( const string& name ) const;
	/**
	 * Get the starting base pair, in this spec's sequence, of the given subspec.
	 * @param specI The subspec index.
	 * @return The subspec's starting base pair.
	 */
	virtual gnSeqI GetSpecStartBase( const uint32 specI ) const;
	/**
	 * Get the ending base pair, in this spec's sequence, of the given subspec.
	 * @param specI The subspec index.
	 * @return The subspec's ending base pair.
	 */
	virtual gnSeqI GetSpecEndBase( const uint32 specI ) const;
	/**
	 * Add a subspec to this spec.
	 * Throws an exception if the insertion index i is out of range
	 * @param spec The subspec to add.
	 * @param i The subspec to insert before
	 * @return True if successful
	 */
	virtual void AddSpec( gnBaseSpec* spec, const uint32 i = UINT32_MAX ) = 0;
	/**
	 * Remove a subspec from this spec.
	 * @param i The index of the subspec to remove.
	 */
	virtual void RemoveSpec( uint32 i ) = 0;

	/**
	 * Returns the number of headers this spec contains.
	 * @return The number of headers this spec contains.
	 */
	virtual uint32 GetHeaderListLength() const;
	/**
	 * Add a header to this spec, adds to the end of the header list by default.
	 * @param head The header to add.
	 * @param i The header to insert before.  If i is larger than the size of the header list
	 * the header will be added to the end of the list.
	 */
	virtual void AddHeader( gnBaseHeader *head, const uint32 i = UINT32_MAX);
	/**
	 * Get the headers at index i in the list of headers.
	 * Throws a HeaderIndexOutOfBounds exception if a nonexistant header is referenced
	 * @param i The index of the header
	 * @return The header.
	 */
	virtual gnBaseHeader* GetHeader( const uint32 i ) const;
	/**
	 * Find the first header with the specified name, starting at index i.
	 * @param name The name of the header to find.
	 * @param i The index to start looking at.
	 * @return The header or NULL if none was found.
	 */
	virtual gnBaseHeader* GetHeader( const string& name, uint32& i) const;
	/**
	 * Remove a header from this spec.
	 * Throws a HeaderIndexOutOfBounds exception if a nonexistant header is referenced
	 * @param i The index of the header to remove.
	 */
	virtual void RemoveHeader( uint32 i );

	/**
	 * Add a feature to this spec.
	 * @param feat The feature to add.
	 * @return True if successful
	 */
	uint32 AddFeature( gnBaseFeature* feat );
	/**
	 * Returns the number of features this spec contains.
	 * @return The number of features this spec contains.
	 */
	virtual uint32 GetFeatureListLength() const = 0;
	/**
	 * Get the feature at index i in the list of features.
	 * @param i The index of the feature
	 * @return The feature.
	 */
	virtual gnBaseFeature* GetFeature( const uint32 i ) const = 0;
	/**
	 * Creates a list of all features which are contained by coordinates specified.
	 * @param lt The coordinates containing the features to return.
	 * @param feature_vector The vector to store features in.
	 * @param index_vector A vector of indices which correspond to the features.
	 */
	virtual void GetContainedFeatures(const gnLocation& lt, vector<gnBaseFeature*>& feature_vector, vector<uint32>& index_vector) const = 0;
	/**
	 * Creates a list of all features which intersect the coordinates specified.
	 * @param lt The coordinates intersecting the features to return.
	 * @param feature_vector The vector to store features in.
	 * @param index_vector A vector of indices which correspond to the features.
	 */
	virtual void GetIntersectingFeatures(const gnLocation& lt, vector<gnBaseFeature*>& feature_vector, vector<uint32>& index_vector) const = 0;
	/**
	 * Creates a list of features which may have been broken by an edit.
	 * @param lt The coordinates containing the features to return.
	 * @param feature_vector The vector to store features in.
	 */
	virtual void GetBrokenFeatures(const gnLocation& lt, vector<gnBaseFeature*>& feature_vector) const = 0;
	/**
	 * Remove a feature from this spec.
	 * @param i The index of the feature to remove.
	 * @return True if successful
	 */
	virtual void RemoveFeature( const uint32 i ) = 0;
	
protected:
	string m_sourceName;
	
	vector <gnBaseHeader*> m_headerList;
private:

}; // class gnMultiSpec

inline
uint32 gnMultiSpec::GetHeaderListLength() const
{
	return m_headerList.size();
}
inline
gnBaseHeader* gnMultiSpec::GetHeader(const uint32 i) const
{
	if(i < m_headerList.size()){
		return m_headerList[i];
	}
	return 0;
}

inline
string gnMultiSpec::GetSourceName() const{
	return m_sourceName;
}

inline
void gnMultiSpec::SetSourceName(const string& sourceName){
	m_sourceName = sourceName;
}

#endif
	// _gnMultiSpec_h_
