/*********************************************************************
 * This file is part of the PRAPI library.
 *
 * Copyright (C) 2001 Topi Mäenpää
 * All rights reserved.
 *
 * This program is free software. You can redistribute and/or modify
 * it under the terms of the free software licence found in the
 * accompanying file "COPYING". The licence terms must always be
 * redistributed with this source file. The above copyright notice
 * must be reproduced in all modified and unmodified copies of this
 * source file.
 *
 * $Revision: 1.2 $
 *********************************************************************/

#include "Distribution.h"

namespace prapi
{
	Distribution::Distribution(int length) : DoubleList(length)
	{
		_lstDimensions.addElement(length);
		_lstSteps.addElement(1);
		setCapacity(length);
		for (int i=0;i<length;i++)
			addElement(0.0);
	}

	Distribution::Distribution(const IntegerList& dims) : DoubleList(1)
	{
		int totalSize = 1;
		_lstDimensions = dims;
		for (int i=0;i<_lstDimensions.getLength();i++)
			{
				_lstSteps.addElement(totalSize);
				totalSize *= _lstDimensions[i];
			}
		
		setCapacity(totalSize);
		for (int i=0;i<totalSize;i++)
			addElement(0.0);
	}

	Distribution::Distribution(const Distribution& other) : DoubleList(other)
	{
		_lstDimensions = other._lstDimensions;
		_lstSteps = other._lstSteps;
	}

	Distribution& Distribution::operator= (const Distribution& other)
	{
		DoubleList::operator=(other);
		_lstDimensions = other._lstDimensions;
		_lstSteps = other._lstSteps;
		return *this;
	}


	Distribution operator* (const Distribution& dist, double value)
	{
		Distribution result(dist);
		for (int i=0;i<dist._iCurrentItems;i++)
			dist._internalArray[i] *= value;
		return result;
	}

	Distribution operator/ (const Distribution& dist, double value)
	{
		Distribution result(dist);
		for (int i=0;i<dist._iCurrentItems;i++)
			dist._internalArray[i] /= value;
		return result;
	}

	void Distribution::normalize(void)
	{
		double sum=0;
		for (int i=0;i<_iCurrentItems;i++)
			sum += _internalArray[i];
		for (int i=0;i<_iCurrentItems;i++)
			_internalArray[i] /= sum;
	}

	void Distribution::setElementAt(const IntegerList& coordinates, double value)
	{
		int index = 0;
		for (int i=0;i<coordinates.getLength();i++)
			index += coordinates[i] * _lstSteps[i];
		DoubleList::setElementAt(value,index);
	}

	double& Distribution::elementAt(const IntegerList& coordinates)
	{
		int index = 0;
		for (int i=0;i<coordinates.getLength();i++)
			index += coordinates[i] * _lstSteps[i];
		return DoubleList::elementAt(index);
	}

	double Distribution::getElementAt(const IntegerList& coordinates) const
	{
		int index = 0;
		for (int i=0;i<coordinates.getLength();i++)
			index += coordinates[i] * _lstSteps[i];
		return DoubleList::getElementAt(index);
	}

	Distribution Distribution::getMarginalDistribution(int dimension) const
	{
		IntegerList newDimensions(_lstDimensions);
		newDimensions.removeElementAt(dimension);
		Distribution result(newDimensions);

		int dimCount = _lstDimensions.getLength();
		IntegerList coordinates(dimCount), newCoordinates(dimCount-1);
		coordinates.setLength(dimCount);
		newCoordinates.setLength(dimCount-1);
		
		for (int i=0;i<_lstDimensions[dimension];i++)
			{
				//PENDING
			}
		return *this;
	}
}
