/*********************************************************************
 * This file is part of the cpplibs suite.
 *
 * Copyright (C) 2001 Topi Mäenpää and Jaakko Viertola
 * 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.5 $
 *********************************************************************/

#ifndef _ASCIICODEC_H
#define _ASCIICODEC_H

#include "MatrixCodec.h"
#include "List.h"
#include "String.h"

namespace util
{
	/**
	 * A codec for reading and writing ascii-encoded matrices.
	 **/
	template <class T> class AsciiCodec : public MatrixCodec<T>
	{
	public:
		/**
		 * Create a new AsciiCodec with the given column and row
		 * deliminator. The default values allow data interchange between
		 * matlab. (Matlab fuction dlmread/dlmwrite).
		 *
		 * @param columnDeliminator The deliminator for colums.
		 * @param rowDeliminator The deliminator for rows.
		 **/
		AsciiCodec(char columnDeliminator=',', char rowDeliminator='\n'):
			_cColDelim(columnDeliminator),_cRowDelim(rowDeliminator){}

		/**
		 * Set the colum deliminator.
		 **/
		void setColumnDeliminator(char delim){_cColDelim=delim;}
		/**
		 * Set the row deliminator.
		 **/
		void setRowDeliminator(char delim){_cRowDelim=delim;}
		/**
		 * Get the colum deliminator
		 **/
		char getColumnDeliminator()const {return _cColDelim;}
		/**
		 * Get the row deliminator.
		 **/
		char getRowDeliminator()const {return _cRowDelim;}
		
		void decodeMatrix(std::istream& in, Matrix<T>& mat) throw (MatrixException&, io::IOException&);
		void encodeMatrix(std::ostream& out, const Matrix<T>& mat) throw (MatrixException&, io::IOException&);

	private:
		char _cColDelim;
		char _cRowDelim;
	};

	template <class T> void AsciiCodec<T>::decodeMatrix(std::istream& in, Matrix<T>& mat)
		throw (MatrixException&, io::IOException&)
	{
		List<T> lst(262144,65536);//size for matrix 512x512 and grows 512x128 when needeed.
		char* tmp = new char[256];
		int index=0;
		int col=0,row=0; // for the matrix size.
		// read the newline while file is empty
		while(in.getline(tmp,256,_cColDelim) && in != NULL)
			{
				std::string temp(tmp);
				// try to find the end mark
				if((index=temp.find(_cRowDelim)) != -1)
					{
						// if found take te first part out
						lst+=String::parse<T>(temp.substr(0,index));
						// then give the cols the right value
						if(col==0)col=lst.getLength();
						// then take the second part out.
						lst+=String::parse<T>(temp.substr(index+1,temp.length()));
						// it was the next row
						row++;
					}
				else lst+=String::parse<T>(tmp);
			}
		delete[] tmp; // remember to free tmp memory

		// make new matrix and set the list data to matrix and then
		// insert matrix to mat.
		Matrix<T> matrix(row,col,lst.getData());
		mat=matrix;
	}

	template <class T> void AsciiCodec<T>::encodeMatrix(std::ostream& out, const Matrix<T>& mat)
		throw (MatrixException&, io::IOException&)
	{
		int rows=mat.getRows();
		int cols=mat.getColumns();
		const T* data=mat.getData();
		cols--; // needeed beacause we don't set _cColDelim after each row.
		
		for(int r=0;r<rows;r++)
			{
				for(int c=0;c<cols;c++,data++)out<<*data<< _cColDelim;
				// set the last item in the row and the _cRowDelim.
				out << *data<< _cRowDelim;
				data++;
			}
	}
}
#endif

	

	
