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

/*
 * Power System class source.
 */
#include <sstream>					// USES stringstream
#include <iostream>					// USES cout
#include <deque>					// USES deque (connectedness checking)
#include "Interface/Interface.h"	// USES Interface
#include "PowerSystem.h"


POWERSYSTEM_NAMESPACE_BEGIN


/////////////////////////////// PUBLIC ///////////////////////////////////////


//============================= LIFECYCLE ====================================


PowerSystem::PowerSystem(void) :
	mBasePower(0), mBusContainer(), mBranchContainer(), mAdjacencyList()
{
} // PowerSystem::PowerSystem


/* virtual */ PowerSystem::~PowerSystem(void)
{ // Always provide a virtual destructor on base classes, even if it is empty.
} // PowerSystem::~PowerSystem


//============================= OPERATIONS ===================================


/* virtual */ void PowerSystem::Clear(void)
{
	mBasePower = 0;
	mBusContainer.clear();
	mBranchContainer.clear();
	mAdjacencyList.Clear();
} // PowerSystem::Clear


/* virtual */ bool PowerSystem::Read(const std::string& rSourceName, Interface& rIface)
{
	Clear();
	if (!rIface.Open(rSourceName)) return false;	// Open data source
	if (!rIface.Read(*this))						// Read data
	{	// Error while reading, clear the power system data
		Clear();
		return false;
	}
	rIface.Close();									// Close data source
	return true;
} // PowerSystem::Read


/* virtual */ std::string PowerSystem::ToString(void)
{
	std::stringstream ss;

	// Print busses
	ss << "BUSSES" << std::endl;
	if (GetBusCount() == 0)
	{
		ss << "NONE" << std::endl;
	}
	else
	{
		for (BusIndexType i = 0; IsValidBusIndex(i); ++i)
		{
			ss << i << ":\t" << mBusContainer[i] << std::endl;
		}
	}

	// Print branches
	ss << "BRANCHES" << std::endl;
	if (GetBranchCount() == 0)
	{
		ss << "NONE" << std::endl;
	}
	else
	{
		BranchContainerType::const_iterator itBranch;
		for (itBranch = mBranchContainer.begin(); itBranch != mBranchContainer.end(); ++itBranch)
		{
			ss << *itBranch << std::endl;
		}
	}

	return ss.str();
} // PowerSystem::ToString


//============================= BASEPOWER ACCESS =============================


/* virtual */ double PowerSystem::GetBasePower(void) const
{
	return mBasePower;
} // PowerSystem::GetBasePower


/* virtual */ double PowerSystem::SetBasePower(double val)
{
	return (mBasePower = val);
} // PowerSystem::SetBasePower


//============================= BUS ACCESS ===================================


/* virtual */ bool PowerSystem::IsValidBusIndex(BusIndexType i) const
{
	return (i < GetBusCount());
} // PowerSystem::IsValidBusIndex


/* virtual */ PowerSystem::BusIndexType PowerSystem::GetBusCount(void) const
{
	return mBusContainer.size();
} // PowerSystem::GetBusCount


/* virtual */ const Bus* PowerSystem::GetBus(BusIndexType i) const
{
	if (!IsValidBusIndex(i)) return NULL;
	return &mBusContainer[i];
} // PowerSystem::GetBus


/* virtual */ bool PowerSystem::SetBus(BusIndexType i, const Bus& rBus)
{
	if (!IsValidBusIndex(i)) return false;
	// Assigns the value x to the element pointed to by the iterator into the multi_index_container
	// to which the index belongs if replacing is allowed by all other indices of the multi_index_container.
	// Returns true if the replacement took place, false otherwise.
	BusContainerType::iterator it = mBusContainer.iterator_to(mBusContainer[i]);
	return mBusContainer.replace(it, rBus);
} // PowerSystem::SetBus


/* virtual */ bool PowerSystem::AddBus(const Bus& rBus)
{
	// Inserts x at the end of the sequence if no other index of the multi_index_container bans the insertion.
	// The return value is a pair p. p.second is true if and only if insertion took place.
	// On successful insertion, p.first points to the element inserted; otherwise, p.first points to an element that caused the insertion to be banned.
	bool success = mBusContainer.push_back(rBus).second;
	if (success) mAdjacencyList.Clear();	// :TODO: update adjacency list
	return success;
} // PowerSystem::AddBus


/* virtual */ PowerSystem::BusIndexType PowerSystem::GetBusIndex(const std::string& rName) const
{
	// Get a view to the name indices (1)
	BusByNameType& busByName = mBusContainer.get<by_name>();
	// Get an iterator to the element with given name
	BusByNameType::const_iterator itName = busByName.find(rName);
	if (itName == busByName.end()) return GetBusCount();
	// Project to found name iterator (1) to an idx iterator (0)
	BusContainerType::const_iterator itIdx = mBusContainer.project<by_index>(itName);
	// Get the idx by taking the difference with the iterator of the first element
	return itIdx - mBusContainer.begin();
} // PowerSystem::GetBusKey


/* virtual */ bool PowerSystem::IsConnected(BusIndexType i, BusIndexType j) const
{
	if (mAdjacencyList.IsEmpty()) BuildAdjacencyList();
	return mAdjacencyList.IsConnected(i, j);
} // PowerSystem::IsConnected


//============================= BRANCH ACCESS ================================


/* virtual */ PowerSystem::BranchIndexType PowerSystem::GetBranchCount(void) const
{
	return mBranchContainer.size();
} // PowerSystem::GetBranchCount


/* virtual */ PowerSystem::ConstBranchIterator PowerSystem::GetBranchBegin(void) const
{
	return mBranchContainer.get<by_busses>().begin();
} // PowerSystem::GetBranchBegin


/* virtual */ PowerSystem::ConstBranchIterator PowerSystem::GetBranchEnd(void) const
{
	return mBranchContainer.get<by_busses>().end();
} // PowerSystem::GetBranchEnd


/* virtual */ PowerSystem::ConstBranchIterator PowerSystem::GetBranchNextUnique(const ConstBranchIterator& rBaseIterator) const
{
	// Count the number of branches beyond index i, comparing no larger than (thus equal to) that at i
	ConstBranchIterator it = rBaseIterator;
	ConstBranchIterator itEnd = mBranchContainer.end();
	if (it != itEnd) ++it;	// itBase does not to be checked with itself using BranchCompare
	while (it != itEnd && !PowerSystem::BranchCompare(*rBaseIterator, *it)) ++it;
	return it;
} // PowerSystem::GetBranchNextUnique


/* virtual */ bool PowerSystem::AddBranch(const Branch& rBranch)
{
	// Check if the bus keys are valid
	if (!IsValidBusIndex(rBranch.GetFromBus()) || !IsValidBusIndex(rBranch.GetToBus())) return false;
	if (rBranch.GetFromBus() == rBranch.GetToBus()) return false;

	// Inserts x into the multi_index_container to which the index belongs if
	// insertion is allowed by all indices of the multi_index_container.
	// The return value is a pair p. p.second is true if and only if insertion took place.
	// On successful insertion, p.first points to the element inserted; otherwise, p.first points to an element that caused the insertion to be banned.
	bool success = mBranchContainer.insert(rBranch).second;
	if (success) mAdjacencyList.AddBranch(rBranch.GetFromBus(), rBranch.GetToBus());
	return success;
} // PowerSystem::AddBranch


/* virtual */ bool PowerSystem::RemoveBranch(ConstBranchIterator& rBranchIterator)
{
	mBranchContainer.erase(rBranchIterator);
	mAdjacencyList.RemoveBranch(rBranchIterator->GetFromBus(), rBranchIterator->GetToBus());
	return true;
} // PowerSystem::RemoveBranch


bool PowerSystem::IsActiveBranch(const ConstBranchIterator& rBranchIterator) const
{
	return rBranchIterator->IsActive();
} // PowerSystem::IsActiveBranch









bool PowerSystem::ActivateBranch(const ConstBranchIterator& rBranchIterator)
{
	// :KLUDGE: Get non-const branch pointer so we can deactivate the branch.
	// BranchContainer iterators always lead to const branches,
	// since changing the branch may change the position in the BranchContainer.
	// The proper implementation would be to use mBranchContainer::modify(),
	// but since deactivation does not change the position in any of the indices of the branch container,
	// using const_cast leads to the same result without the need of a mod function.
	if (!rBranchIterator->IsActive())
	{
		BranchType* pBranch = const_cast<BranchType*>(&(*rBranchIterator));
		pBranch->Activate();
		mAdjacencyList.AddBranch(rBranchIterator->GetFromBus(), rBranchIterator->GetToBus());
	}
	return true;
} // PowerSystemExt::ActivateBranch


bool PowerSystem::DeactivateBranch(const ConstBranchIterator& rBranchIterator)
{
	// :KLUDGE: See Activate().
	if (rBranchIterator->IsActive())
	{
		BranchType* pBranch = const_cast<BranchType*>(&(*rBranchIterator));
		pBranch->Deactivate();
		mAdjacencyList.RemoveBranch(rBranchIterator->GetFromBus(), rBranchIterator->GetToBus());
	}
	return true;
} // PowerSystemExt::DeactivateBranch









PowerSystem::BranchIndexType PowerSystem::RemoveInactiveBranches(void)
{
	BranchIndexType cnt = 0;
	ConstBranchIterator it, itEnd = GetBranchEnd();
	for (it = GetBranchBegin(); it != itEnd; ++it)
	{
		if (!it->IsActive())
		{
			RemoveBranch(it);	// Remove inactive branch
			++cnt;
		}
	}
	if (cnt > 0) mAdjacencyList.Clear();	// :TODO: update adjacency list
	return cnt;
} // PowerSystem::RemoveInactiveBranches


/////////////////////////////// PRIVATE    ///////////////////////////////////


void PowerSystem::BuildAdjacencyList(void) const
{
	// Build adjacency data structure.
	// Vector with for each bus a list of connected busses.
	// Each connected bus is in the list a number of times equal to the multiplicity of the connection.
	// When the connection multiplicity is mostly 1, this is more efficient
	// than storing the multiplicity itself for each connection.
	mAdjacencyList.Initialize(GetBusCount());
	ConstBranchIterator branchIt, branchItEnd = GetBranchEnd();
	for (branchIt = GetBranchBegin(); branchIt != branchItEnd; ++branchIt)
	{
		if (branchIt->IsActive())
		{
			mAdjacencyList.AddBranch(branchIt->GetFromBus(), branchIt->GetToBus());
		}
	}
} // PowerSystem::BuildAdjacencyList


/*static*/ bool PowerSystem::BranchCompare(const Branch& rLhs,const Branch& rRhs)
{
	BusIndexType lhsFrom = rLhs.GetFromBus();
	BusIndexType lhsTo = rLhs.GetToBus();
	BusIndexType rhsFrom = rRhs.GetFromBus();
	BusIndexType rhsTo = rRhs.GetToBus();
	if (lhsFrom < lhsTo)
	{
		if (rhsFrom < rhsTo)
		{
			return (lhsFrom < rhsFrom || (lhsFrom == rhsFrom && lhsTo < rhsTo) );
		}
		else
		{
			return (lhsFrom < rhsTo   || (lhsFrom == rhsTo && lhsTo < rhsFrom) );
		}
	}
	else
	{
		if (rhsFrom < rhsTo)
		{
			return (lhsTo < rhsFrom || (lhsTo == rhsFrom && lhsFrom < rhsTo) );
		}
		else
		{
			return (lhsTo < rhsTo   || (lhsTo == rhsTo && lhsFrom < rhsFrom) );
		}
	}
} // PowerSystem::BranchCompare


POWERSYSTEM_NAMESPACE_END
