/*
   Project: UL

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   Created: 2005-06-02 15:34:11 +0200 by michael johnston

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

   This application 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
   Library General Public License for more details.

   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#ifndef _ADDATAMATRIX_H_
#define _ADDATAMATRIX_H_

#include <gsl/gsl_matrix.h>
#include <Foundation/Foundation.h>
#include "AdunKernel/AdunDefinitions.h"

/**
Contains a matrix of values. AdDataMatrix (as opposed to AdMatrix which
is a C structure) is a very light
weight wrapper around NSArray. It is primarily a convenient way to
represent heterogenous matrix (tabular) data, including column titles and name, 
as an object to facititate transport and transparent access. 
However it is not optimised for performace in any way and should not be
used where heavy access is required to the matrix elements i.e. for computations
use the AdunBase library C structures or the gsl_matrix type.
\ingroup model
\todo Optimise as much as possible.
\todo implement proper coding.
\todo Add row titles
\todo Add referencing by column title, row title or both
\bug At the moment only matrices containing numbers and nothing else can be archived and
unarchiving them will always convert them to doubles.
\note it may be better to implement this as a class cluster with different classes for
matrices created using matrixFromAdMatrix etc. This would provide good performance for
matrices containing only numerical data and also allow for coding of heterogenous data.
*/

@interface AdDataMatrix : NSObject <NSCoding>
{
	int numberOfRows;
	int numberOfColumns;
	NSMutableArray* columnHeaders;
	NSString* name;
	NSMutableArray* matrix;	//!<an array of arrays
}

/**Returns an autoreleases AdDataMatrix instance initialise
with the values of \e aMatrix
\param aMatrx An AdDataMatrix struct
\return An autoreleased AdDataMatrix instance
*/

+ (id) matrixFromADMatrix: (AdMatrix*) aMatrix;

/**Returns an autoreleases AdDataMatrix instance initialise
with the values of \e aMatrix
\param aMatrx A gsl_matrix struct
\return An autoreleased AdDataMatrix instance
*/

+ (id) matrixFromGSLMatrix: (gsl_matrix*) aMatrix;

/**Returns an autoreleases AdDataMatrix instance initialise
with the values of \e aVector
\param aMatrx An gsl_vector struct
\return An autoreleased AdDataMatrix instance
*/

+ (id) matrixFromGSLVector: (gsl_vector*) aVector;
/**
Returns an initialised AdDataMatrix instance representing an empty
matrix of dimension rows*columns where all entries are zero
\param rows The number of rows
\param columns The number of columns
\return A AdDataMatrix instance
*/
- (id) initWithRows: (int) rows columns: (int) columns;

/**
Sets the element at position (row, columns) to valus \e value
\param row The row number
\param columns The column number
\param value The value the element is to be set to
*/
- (void) setElementAtRow: (int) row column: (int) column withValue: (NSNumber*) value;

/**
Get the value of the element at (row, column)
\param row The row number
\param column The column number
\return The value of the element
*/
- (NSNumber*) elementAtRow: (int) row column: (int) column;

/** 
Extends the matrix with \e extendingMatrix adding the rows on to the end.
\e extendingMatrix must have the same number of columns as the AdDataMatrix instance
\param extendingMatrix A matrix to be appended
*/
- (void) extendMatrixWithMatrix: (AdDataMatrix*) extendingMatrix;

/**
Extends the matrix with \e array appending it as a new row at the end of 
the matrix.
\param array The array to be appended as a row
*/
- (void) extendMatrixWithRow: (NSArray*) row;

/**
Adds \e column to the end of the matrix
\param array The array to be appended 
\note add exceptions
*/

- (void) extendMatrixWithColumn: (NSArray*) column;

/**
Returns an array containing the rows of the matrix (the underlying
matrix representation)
*/
- (NSArray*) matrixRows;

/**
Returns the number of rows
*/
- (int) numberOfRows;

/**
Returns the number of columns
*/
- (int) numberOfColumns;

/**
Returns a copy of column number \e columnIndex
*/

- (NSMutableArray*) column: (int) columnIndex;

/**
Uses NSLog to print the data matrix to stderr. Useful
for debugging.
*/
- (void) printMatrix;

/**
Writes a plain text representation of the data matrix
to a file.
*/
- (BOOL) writeMatrixToFile: (NSString*) filename;

/**
Removes the rows with the indexes in indexSet 
and modifies the matrixs' rows attribute aswell
*/

- (void) removeRowsWithIndexes: (NSIndexSet*) indexSet;

/**
Returns an array of columnHeaders  or nil if there are none.
This array may not be the same as the one set with setColumnHeaders:
*/
- (NSArray*) columnHeaders;
/**
Returns the name of the data matrix
*/
- (NSString*) name;

/**
Sets titles for each column in the array.
\param anArray An array of strings describing the contents
of each column. If the number of strings is not equal to the
number of columns an exception is raised. 
*/
- (void) setColumnHeaders: (NSArray*) anArray;
/**
Sets the name of the data matrix to \e aString.
*/
- (void) setName: (NSString*) aString;

@end

#endif // _ADMATRIX_H_

