/**********************************************************************************

 Infomap software package for multi-level network clustering

 Copyright (c) 2013, 2014 Daniel Edler, Martin Rosvall

 For more information, see <http://www.mapequation.org>


 This file is part of Infomap software package.

 Infomap software package is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Infomap software package is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Affero General Public License for more details.

 You should have received a copy of the GNU Affero General Public License
 along with Infomap software package.  If not, see <http://www.gnu.org/licenses/>.

**********************************************************************************/


#include "ClusterReader.h"
#include "../utils/Log.h"
#include "convert.h"
#include "SafeFile.h"

namespace infomap {

/**
 * Read cluster data
 *
 * Example file for a network with 6 nodes and two clusters:
 * *Vertices 6
 * 1
 * 1
 * 2
 * 1
 * 2
 * 2
 *
 * Example with node mapping
 * # nodeId clusterId
 * 1 1
 * 2 1
 * 4 1
 * 3 2
 * 5 2
 * 6 2
 *
 */
void ClusterReader::readData(const string filename)
{
	SafeInFile input(filename.c_str());
	std::string line;
	std::istringstream lineStream;
	unsigned int numVertices = 0;

	while(!std::getline(input, line).fail())
	{
		if (line.length() == 0 || line[0] == '#')
			continue;

		lineStream.clear();
		lineStream.str(line);

		if (line[0] == '*')
		{
			std::string buf;
			lineStream >> buf;
			if(buf == "*Vertices" || buf == "*vertices") {
				if (!(lineStream >> numVertices))
					throw FileFormatError(io::Str() << "Can't parse an integer after '" << buf <<
							"' as the number of nodes.");
			}
			else {
				throw FileFormatError(io::Str() << "Unrecognized heading '" << line << " in .clu file.");
			}

			if (numVertices == 0)
				throw FileFormatError("Number of vertices declared in the cluster data file is zero.");
			continue;
		}
		else
		{
			parseClusterLine(line);
		}
	}

	unsigned int zeroMinusOne = 0;
	--zeroMinusOne;
	if (m_maxNodeIndex == zeroMinusOne)
		throw InputDomainError(io::Str() << "Integer overflow, be sure to use zero-based node numbering if the node numbers start from zero.");

}

void ClusterReader::parseClusterLine(std::string line)
{
	std::istringstream lineStream(line);
	// Parse nodeIndex clusterIndex, or only clusterIndex
	unsigned int nodeIndex, clusterIndex;
	if (!(lineStream >> nodeIndex))
		throw FileFormatError(io::Str() << "Couldn't parse integer from line '" << line << "'");
	if (!(lineStream >> clusterIndex)) {
		clusterIndex = nodeIndex; // Only one column => assume natural order for node indices
		nodeIndex = m_numParsedRows + m_indexOffset;
	}

	nodeIndex -= m_indexOffset; // Get zero-based indexing
	m_clusters[nodeIndex] = clusterIndex;
	m_maxNodeIndex = std::max(m_maxNodeIndex, nodeIndex);
	++m_numParsedRows;
}

}
