/*
 * Copyright (C) 2008-2012 Delft University of Technology - All rights reserved.
 *
 * Author: Reijer Idema
 */

/**
 * @file PowerSystem.h
 * Power System class header.
 */
#ifndef PowerSystem_PowerSystem_h
#define PowerSystem_PowerSystem_h

#include <string>										// USES string
#include <boost/multi_index_container.hpp>				// HASA multi_index_container
#include <boost/multi_index/random_access_index.hpp>	// HASA random_access index
#include <boost/multi_index/ordered_index.hpp>			// HASA ordered_unique and ordered_non_unique index
#include <boost/multi_index/member.hpp>					// HASA member key extractor


#include <vector>										// HASA vector (adjacency list)
#include <list>											// HASA list (adjacency list)


#include "Bus.h"										// HASA Bus
#include "Branch.h"										// HASA Branch
#include "AdjacencyList.h"								// HASA AdjacencyList
#include "PowerSystem.def"

POWERSYSTEM_NAMESPACE_BEGIN

// FORWARD DECLARATIONS
class Interface;

/**
 * Power System class.
 * Implements the power system class,
 * containing bus and branch data of a power system.
 */
class PowerSystem
{

private:
	/**
	 * Comparison function for ordering branches.
	 * A branch is ordered before another branch if the lower index of the from and to bus indices is smaller,
	 * or the lower of the indices is equal and the higher is smaller than that of the other branch.
	 * @param rLhs left-hand side branch.
	 * @param rRhs right-hand side branch.
	 * @return \c true if the left-hand side branch comes strictly before the right-hand side branch, \c false otherwise.
	 */
	static bool BranchCompare(const Branch& rLhs, const Branch& rRhs);

	// PRIVATE TYPE DEFINITIONS

	struct by_index {};		///< MultiIndex tag.
	struct by_name {};		///< MultiIndex tag.
	struct by_busses {};	///< MultiIndex tag.

	/// Struct wrapper for the BranchCompare() function, used in BranchContainerType.
	struct BranchCompareType
	{
		bool operator()(const Branch& rLhs, const Branch& rRhs) const
		{
			return PowerSystem::BranchCompare(rLhs, rRhs);
		}
	};

	/// Type of the bus data container.
	typedef boost::multi_index_container
			< Bus,
				boost::multi_index::indexed_by
				<
					boost::multi_index::random_access< boost::multi_index::tag<by_index> >,
					boost::multi_index::ordered_unique< boost::multi_index::tag<by_name>, boost::multi_index::member<Bus,std::string,&Bus::mName> >
				>
			> BusContainerType;

	/// Type of the bus data view sorted by bus name.
	typedef const BusContainerType::index<by_name>::type BusByNameType;

	/// Type of the branch data container.
	typedef boost::multi_index_container
			< Branch,
				boost::multi_index::indexed_by
				<
					boost::multi_index::ordered_non_unique< boost::multi_index::tag<by_busses>, boost::multi_index::identity<Branch>, BranchCompareType >
				>
			> BranchContainerType;

	/// Type of the adjacency list
	typedef std::vector< std::list<Branch::BusIndexType> > AdjacencyListType;

public:
	// PUBLIC TYPE DEFINITIONS

	typedef POWERSYSTEM_NAMESPACE_NAME::Interface Interface;	///< Type of the input/output interface.
	typedef POWERSYSTEM_NAMESPACE_NAME::Bus BusType;			///< Type of the busses.
	typedef POWERSYSTEM_NAMESPACE_NAME::Branch BranchType;		///< Type of the branches.
	typedef Branch::BusIndexType BusIndexType;							///< Type of bus indices.
	typedef unsigned int BranchIndexType;								///< Type of branch indices.
//	typedef BranchContainerType::iterator BranchIterator;				///< Type of the branch iterator to const branch.
	typedef BranchContainerType::const_iterator ConstBranchIterator;	///< Type of the const branch iterator to const branch.

	// LIFECYCLE

	/**
	 * Default constructor.
	 * Creates an empty power system object.
	 */
	PowerSystem(void);

	/**
	 * Destructor.
	 */
	virtual ~PowerSystem(void);

	// OPERATIONS

	/**
	 * Clears all data from the power system object.
	 */
	virtual void Clear(void);

	/**
	 * Reads data into the power system.
	 * @param rSourceName name of the data source.
	 * @param rIface interface object used to interpret the data.
	 * @return \c true on success, \c false otherwise.
	 */
	virtual bool Read(const std::string& rSourceName, Interface& rIface);

	/**
	 * Writes the power system data into a string.
	 */
	virtual std::string ToString(void);

	// BASEPOWER ACCESS

	/**
	 * Get the base power in MVA.
	 * @return base power in MVA.
	 */
	virtual double GetBasePower(void) const;

	/**
	 * Set the base power in MVA.
	 * @param val base power in MVA.
	 * @return base power in MVA.
	 */
	virtual double SetBasePower(double val);

	// BUS ACCESS

	/**
	 * Checks whether a given index leads to an existing bus.
	 * @param i index to check.
	 * @return \c true if there exists a bus at the given index, \c false otherwise.
	 */
	virtual bool IsValidBusIndex(BusIndexType i) const;

	/**
	 * Gets the number of busses in the power system.
	 * @return number of busses in the power system.
	 */
	virtual BusIndexType GetBusCount(void) const;

	/**
	 * Gets a bus from the power system.
	 * @param i index of the bus to retrieve.
	 * @return pointer to the bus if the index is valid, \c NULL otherwise.
	 */
	virtual const Bus* GetBus(BusIndexType i) const;

	/**
	 * Adds a new bus to the power system.
	 * The bus is only added if there is no bus with the same name yet.
	 * @param rBus bus data to add to the power system.
	 * @return \c true if a new bus was added, \c false if a bus with the same name already exists.
	 */
	virtual bool AddBus(const Bus& rBus);

	/**
	 * Sets a bus in the power system.
	 * The bus data at the given index is updated with the new bus data,
	 * unless there is already a bus with the same name at another index.
	 * @param i index.
	 * @param rBus bus data.
	 * @return \c true if the bus data was updated, \c false if the index is invalid
	 * or there is a bus with the same name at a different index.
	 */
	virtual bool SetBus(BusIndexType i, const Bus& rBus);

	/**
	 * Searches for a bus with the given name.
	 * Use IsValidBusIndex() on the return value to check
	 * whether a bus with the given name was indeed found.
	 * @param rName name of the bus to get the key of.
	 * @return index of the bus with the given name.
	 */
	virtual BusIndexType GetBusIndex(const std::string& rName) const;

	/**
	 * Checks whether a bus is connected to other busses.
	 * @param i index of the bus to check.
	 * @return \c true if the bus is connected, \c false otherwise.
	 */
//	virtual bool IsConnected(BusIndexType i) const;

	/**
	 * Checks whether two busses are connected, i.e., whether they are not each in a different disconnected subnetwork.
	 * @param i index of the first bus.
	 * @param i index of the second bus.
	 * @return \c true if the busses are connected, \c false otherwise.
	 */
	virtual bool IsConnected(BusIndexType i, BusIndexType j) const;

	// BRANCH ACCESS

	/**
	 * Gets the number of branches in the power system.
	 * @return number of branches in the power system.
	 */
	virtual BranchIndexType GetBranchCount(void) const;

	/**
	 * Gets an iterator to the first branch.
	 * @return iterator to the first branch.
	 */
	virtual ConstBranchIterator GetBranchBegin(void) const;

	/**
	 * Gets an iterator to the past-the-end branch.
	 * @return iterator to the past-the-end branch.
	 */
	virtual ConstBranchIterator GetBranchEnd(void) const;

	/**
	 * Gets an iterator to the first branch after the given branch that is not between the same busses.
	 * @param rBaseIterator iterator to the branch to start from.
	 * @return first branch after the given branch that is not between the same busses.
	 */
	virtual ConstBranchIterator GetBranchNextUnique(const ConstBranchIterator& rBaseIterator) const;

	/**
	 * Adds a new branch to the power system.
	 * The branch is only added if the bus keys are valid.
	 * @param rBranch branch data.
	 * @return \c true if a new branch was added, \c false if the bus keys are invalid.
	 */
	virtual bool AddBranch(const Branch& rBranch);

	/**
	 * Removes a branch from the power system.
	 * @param rBranchIterator branch iterator.
	 * @return \c true if the branch was removed (which is always the case).
	 */
	virtual bool RemoveBranch(ConstBranchIterator& rBranchIterator);

	/**
	 * Checks if a given branch is active.
	 * @param rBranchIterator iterator pointing to the branch to check.
	 * @return \c true if active, \c false if not.
	 */
	virtual bool IsActiveBranch(const ConstBranchIterator& rBranchIterator) const;

	/**
	 * Activates a given branch.
	 * @param rBranchIterator iterator pointing to the branch to activate.
	 * @return \c true on success, \c false otherwise.
	 */
	virtual bool ActivateBranch(const ConstBranchIterator& rBranchIterator);

	/**
	 * Deactivates a given branch.
	 * @param rBranchIterator iterator pointing to the branch to deactivate.
	 * @return \c true on success, \c false otherwise.
	 */
	virtual bool DeactivateBranch(const ConstBranchIterator& rBranchIterator);

	/**
	 * Removes all inactive branches from the power system.
	 * @return number of removed branches.
	 */
	BranchIndexType RemoveInactiveBranches(void);


private:

	void BuildAdjacencyList(void) const;

	double mBasePower;						///< Base power in MVA.
	BusContainerType mBusContainer;			///< Bus data.
	BranchContainerType mBranchContainer;	///< Branch data.
	mutable AdjacencyList mAdjacencyList;	///< Adjacency list.
};

POWERSYSTEM_NAMESPACE_END

#endif // PowerSystem_PowerSystem_h
