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

/*
 * Extended Power System class source.
 */
#include <sstream>						// USES stringstream
#include <iostream>						// USES cout
#include "../PetscUtils/PetscUtils.h"	// USES PetscUtils
#include "LogEvents.h"					// HASA LogEvents (not owned)
#include "AdmittanceMatrix.h"			// HASA AdmittanceMatrix
#include "PowerVector.h"				// HASA PowerVector
#include "VoltageVector.h"				// HASA VoltageVector
#include "PowerSystemExt.h"


POWERFLOWER_NAMESPACE_BEGIN


// Initialize static member objects
const std::string PowerSystemExt::msErrorBasePowerUpdate = "[Failed] Base power update canceled as it would invalidate admittance matrix, power vector, and voltage vector.\n";
const std::string PowerSystemExt::msErrorBusUpdate = "[Failed] Bus update canceled as it would invalidate admittance matrix, power vector, and voltage vector.\n";
const std::string PowerSystemExt::msErrorBranchUpdate = "[Failed] Branch update canceled as it would invalidate the admittance matrix.\n";


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


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


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::PowerSystemExt"
PowerSystemExt::PowerSystemExt(void) // default base class constructor is called automatically
	: mErr(0), mpLogEvents(NULL), mpAdmittanceMatrix(NULL), mpPowerVector(NULL), mpVoltageVector(NULL)
{
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Creating PowerSystem object.\n"); CHKERRV(mErr);
	}
} // PowerSystemExt::PowerSystemExt


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::PowerSystemExt"
PowerSystemExt::PowerSystemExt(const LogEvents* pLogEvents) // default base class constructor is called automatically
	: mErr(0), mpLogEvents(pLogEvents), mpAdmittanceMatrix(NULL), mpPowerVector(NULL), mpVoltageVector(NULL)
{
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Creating PowerSystem object.\n"); CHKERRV(mErr);
	}
} // PowerSystemExt::PowerSystemExt


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::~PowerSystemExt"
PowerSystemExt::~PowerSystemExt(void)
{
	Clear();
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Destroying PowerSystem object.\n"); CHKERRV(mErr);
	}
} // PowerSystemExt::~PowerSystemExt


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


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::Clear"
void PowerSystemExt::Clear(void)
{
	if (PetscUtils::IsInitialized())
	{
		mErr = PetscInfo(PETSC_NULL, "Clearing PowerSystem object data.\n"); CHKERRV(mErr);
	}
	mErr = 0;
	delete mpAdmittanceMatrix; mpAdmittanceMatrix = NULL;
	delete mpPowerVector; mpPowerVector = NULL;
	delete mpVoltageVector; mpVoltageVector = NULL;
	PowerSystem::Clear();
} // PowerSystemExt::Clear


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::Read"
bool PowerSystemExt::Read(const std::string& rSourceName, Interface& rInterface)
{
	if (PetscUtils::IsInitialized())
	{
		if (mpLogEvents) mpLogEvents->Begin(mpLogEvents->GetPSReadEventId());
		mErr =  PetscInfo1(PETSC_NULL, "Reading power system data from '%s'.\n", rSourceName.c_str()); CHKERRB(mErr);
	}
	bool success = PowerSystem::Read(rSourceName, rInterface);
	if (PetscUtils::IsInitialized())
	{
		if (!success)
		{
			mErr =  PetscInfo1(PETSC_NULL, "[Failed] Error reading power system data from '%s'.\n", rSourceName.c_str()); CHKERRB(mErr);
		}
		if (mpLogEvents) mpLogEvents->End(mpLogEvents->GetPSReadEventId());
	}
	return success;
} // PowerSystemExt::Read


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::ToString"
std::string PowerSystemExt::ToString(void)
{
	if (PetscUtils::IsInitialized())
	{
		if (mpLogEvents) mpLogEvents->Begin(mpLogEvents->GetPSWriteEventId());
	 	PetscInfo(PETSC_NULL, "Writing power system data to string.\n");
	}

	// :TODO: ADD STUFF FOR ADMITTANCE MATRIX ETC
	std::stringstream ss;

	ss << PowerSystem::ToString();
	ss << "ADMITTANCE MATRIX: ";
	if (mpAdmittanceMatrix == NULL)
	{
		ss << "NULL" << std::endl;
	}
	else
	{
		ss << "UP-TO-DATE" << std::endl;
	}
	ss << "POWER VECTOR: ";
	if (mpPowerVector == NULL)
	{
		ss << "NULL" << std::endl;
	}
	else
	{
		ss << "UP-TO-DATE" << std::endl;
	}
	ss << "VOLTAGE VECTOR: ";
	if (mpVoltageVector == NULL)
	{
		ss << "NULL" << std::endl;
	}
	else
	{
		ss << "UP-TO-DATE" << std::endl;
	}

	if (PetscUtils::IsInitialized())
	{
		if (mpLogEvents) mpLogEvents->End(mpLogEvents->GetPSWriteEventId());
	}
	return ss.str();
} // PowerSystemExt::ToString


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::BuildAdmittanceMatrix"
bool PowerSystemExt::BuildAdmittanceMatrix(void)
{
	if (mpAdmittanceMatrix == NULL) mpAdmittanceMatrix = new AdmittanceMatrix(mpLogEvents);
	return mpAdmittanceMatrix->Build(*this);
} // PowerSystemExt::BuildAdmittanceMatrix


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::BuildPowerVector"
bool PowerSystemExt::BuildPowerVector(void)
{
	if (mpPowerVector == NULL) mpPowerVector = new PowerVector;
	return mpPowerVector->Build(*this);
} // PowerSystemExt::BuildPowerVector


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::BuildVoltageVector"
bool PowerSystemExt::BuildVoltageVector(void)
{
	if (mpVoltageVector == NULL) mpVoltageVector = new VoltageVector;
	return mpVoltageVector->Build(*this);
} // PowerSystemExt::BuildVoltageVector


//============================= ACCESS     ===================================


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::SetBasePower"
double PowerSystemExt::SetBasePower(double val)
{
	if (mpAdmittanceMatrix != NULL || mpPowerVector != NULL || mpVoltageVector != NULL)
	{
		// :TODO:
		if (PetscUtils::IsInitialized())
		{
			PetscInfo(PETSC_NULL, msErrorBasePowerUpdate.c_str());
		}
		return GetBasePower();
	}
	return PowerSystem::SetBasePower(val);
} // PowerSystemExt::SetBasePower


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::AddBus"
bool PowerSystemExt::AddBus(const BusType& rBus)
{
	if (mpAdmittanceMatrix != NULL || mpPowerVector != NULL || mpVoltageVector != NULL)
	{
		// :TODO:
		if (PetscUtils::IsInitialized())
		{
			PetscInfo(PETSC_NULL, msErrorBusUpdate.c_str()); CHKERRB(mErr);
		}
		return false;
	}
	return PowerSystem::AddBus(rBus);
} // PowerSystemExt::AddBus


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::SetBus"
bool PowerSystemExt::SetBus(BusIndexType i, const BusType& rBus)
{
	if (mpAdmittanceMatrix != NULL || mpPowerVector != NULL || mpVoltageVector != NULL)
	{
		// :TODO:
		if (PetscUtils::IsInitialized())
		{
			PetscInfo(PETSC_NULL, msErrorBusUpdate.c_str()); CHKERRB(mErr);
		}
		return false;
	}
	return PowerSystem::SetBus(i, rBus);
} // PowerSystemExt::SetBus


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::IsConnected"
bool PowerSystemExt::IsConnected(BusIndexType i, BusIndexType j) const
{
	if (PetscUtils::IsInitialized())
	{
		if (mpLogEvents) mpLogEvents->Begin(mpLogEvents->GetPSIsConnectedEventId());
	}
	bool success = PowerSystem::IsConnected(i, j);
	if (PetscUtils::IsInitialized())
	{
		if (mpLogEvents) mpLogEvents->End(mpLogEvents->GetPSIsConnectedEventId());
	}
	return success;
} // PowerSystemExt::IsConnected


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::AddBranch"
bool PowerSystemExt::AddBranch(const BranchType& rBranch)
{
	if (mpAdmittanceMatrix != NULL)
	{
		// :TODO:
		if (PetscUtils::IsInitialized())
		{
			mErr = PetscInfo(PETSC_NULL, msErrorBranchUpdate.c_str()); CHKERRB(mErr);
		}
		return false;
	}
	return PowerSystem::AddBranch(rBranch);
} // PowerSystemExt::AddBranch


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::RemoveBranch"
bool PowerSystemExt::RemoveBranch(ConstBranchIterator& rBranchIterator)
{
	if (mpAdmittanceMatrix != NULL)
	{
		// :TODO:
		if (PetscUtils::IsInitialized())
		{
			mErr = PetscInfo(PETSC_NULL, msErrorBranchUpdate.c_str()); CHKERRB(mErr);
		}
		return false;
	}
	return PowerSystem::RemoveBranch(rBranchIterator);
} // PowerSystemExt::RemoveBranch











#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::ActivateBranch"
bool PowerSystemExt::ActivateBranch(const ConstBranchIterator& rBranchIterator)
{
	// :WARNING: activate branch before updating admittance matrix, as an inactive branch would otherwise lead to a zero update.
	bool success = PowerSystem::ActivateBranch(rBranchIterator);
	if (success && mpAdmittanceMatrix != NULL)
	{
		mErr = PetscInfo(PETSC_NULL, "Updating admittance matrix.\n"); CHKERRB(mErr);
		if (!mpAdmittanceMatrix->AddBranch(*rBranchIterator)) return false;
	}
	return success;
} // PowerSystemExt::ActivateBranch


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::DeactivateBranch"
bool PowerSystemExt::DeactivateBranch(const ConstBranchIterator& rBranchIterator)
{
	// :WARNING: update admittance matrix before deactivating branch, as the inactive branch would otherwise lead to a zero update.
	if (mpAdmittanceMatrix != NULL)
	{
		mErr = PetscInfo(PETSC_NULL, "Updating admittance matrix.\n"); CHKERRB(mErr);
		if (!mpAdmittanceMatrix->RemoveBranch(*rBranchIterator)) return false;
	}
	return PowerSystem::DeactivateBranch(rBranchIterator);
} // PowerSystemExt::DeactivateBranch


#undef __FUNCT__
#define __FUNCT__ "PowerSystemExt::RemoveInactiveBranches"
PowerSystemExt::BranchIndexType PowerSystemExt::RemoveInactiveBranches(void)
{
	BranchIndexType cnt = PowerSystem::RemoveInactiveBranches();
	if (cnt > 0 && mpAdmittanceMatrix != NULL)
	{
		mErr = PetscInfo(PETSC_NULL, "Rebuilding admittance matrix.\n"); CHKERRB(mErr);
		mpAdmittanceMatrix->Build(*this);
	}
	return cnt;
} // PowerSystemExt::RemoveInactiveBranches


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

// TEMPORARY
void PowerSystemExt::Test(void)
{
	if (mpAdmittanceMatrix != NULL)
	{
		std::cout << "Real part of the admittance matrix" << std::endl;
		mErr = PETSCUTILS_NAMESPACE_NAME::MatSeqAijView(mpAdmittanceMatrix->GetReal()); CHKERRV(mErr);
		std::cout << "Imaginary part of the admittance matrix" << std::endl;
		mErr = PETSCUTILS_NAMESPACE_NAME::MatSeqAijView(mpAdmittanceMatrix->GetImag()); CHKERRV(mErr);
	}

	if (mpPowerVector != NULL)
	{
		std::cout << "Real part of the power vector" << std::endl;
		mErr = PETSCUTILS_NAMESPACE_NAME::VecSeqView(mpPowerVector->GetReal()); CHKERRV(mErr);
		std::cout << "Imaginary part of the power vector" << std::endl;
		mErr = PETSCUTILS_NAMESPACE_NAME::VecSeqView(mpPowerVector->GetImag()); CHKERRV(mErr);
	}

	if (mpVoltageVector != NULL)
	{
		std::cout << "Angle part of the voltage vector" << std::endl;
		mErr = PETSCUTILS_NAMESPACE_NAME::VecSeqView(mpVoltageVector->GetAng()); CHKERRV(mErr);
		std::cout << "Magnitude part of the voltage vector" << std::endl;
		mErr = PETSCUTILS_NAMESPACE_NAME::VecSeqView(mpVoltageVector->GetMag()); CHKERRV(mErr);
	}
}


POWERFLOWER_NAMESPACE_END
