/** @(#) mathpos/array1dpos.h */
#ifndef ARRAY1DPOS_H
#define ARRAY1DPOS_H
//----------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <stdexcept>	// runtime_error
using namespace std;

/**
* Reservar memoria.
* No hace operaciones aritmeticas.
* Entrada y salida de arreglos.
* @author Omar Posada Villarreal
* @version 1.1, 24/04/2002 first [-N, +N]
* @version 1.0, 13/04/2002
*/
template <class TC>
class Array1DPos {

//----------------------------------------------------------------------------
private:
	/** Apuntador a [first]. */
	TC *pCorner;

	/** Apuntador a [0]. */
	TC *pOrigin;

	/** Numero de elementos. */
	int size;

	/** Indice del primer elemento. */
	int first;

	/** Indice del ultimo elemento. */
	int last;
//----------------------------------------------------------------------------
public:

// constructor, ~, friend-----------------------------------------------------
/**
* Reserva memoria para un arreglo unidimensional que permite indices negativos.
* Uso:
* 	Array1DPos<double> V(n);
* @param theFirst [-N, +N] theFirst <= theLast.
* @param theLast [-N, +N] */
// templates solo en *.h
Array1DPos(int theFirst, int theLast)
		throw (invalid_argument, runtime_error) {
	// valida
	if (theFirst > theLast) {
		throw invalid_argument("Array1DPos: indices invertidos");
	}
	first = theFirst;
	last = theLast;

	// Num de elem
	size = last - first + 1;

	// pCorner
	pCorner = new TC[size];

	// pOrigin
	pOrigin = &(pCorner[ -first]);
	// IMPORTANTE Previene underflow del apuntador pOrigin 
	// si first > 0, pOrigin < pCorner
	if (first > 0) {
		if (pOrigin > pCorner) {
			throw runtime_error(
				"Array1DPos: apuntador ArrayOrigin negativo.");
		}
	}
}

/** Por omision, se usa logica 0. */
Array1DPos(int theSize) throw (invalid_argument) {
	if (theSize < 1) {
		throw invalid_argument("Array1DPos: indices no positivos");
	}
	Array1DPos(0, theSize - 1);
}

/** Libera memoria de un arreglo unidimensional. */
// templates solo en *.h
~Array1DPos() {
	deleteArray();
}

void deleteArray() {
	delete[] pOrigin;
 	delete[] pCorner;
	//cout << "} ~Array1DPos()";
}

// inline---------------------------------------------------------------------
inline TC *getArrayOrigin() const {
	return pOrigin;
}
inline int getSize() const {
	return size;
}
inline int getFirst() const {
	return first;
}
inline int getLast() const {
	return last;
}

/** Abreviaciones */
inline int gS() const {	return size; }
inline int gF() const {	return first; }
inline int gL() const {	return last; }

// operator-------------------------------------------------------------------
/** Checa indices. */
TC operator()(int index) throw (invalid_argument) {
	if ( (index < first) || (index > last)) {
		throw invalid_argument("operator(): indices fuera de rango.");
	}
	return pOrigin[index];
}

// public---------------------------------------------------------------------
void print() {
	int i;
	for (i = 0; i < size; ++i) {
		cout << pCorner[i] << "\t";
	}
	cout << endl;
}

void clean() {
	int i;
	for (i = 0; i < size; ++i) {
		pCorner[i] = static_cast<TC>(0);
	}
}

}; // } Array1DPos------------------------------------------------------------
#endif
// Fin------------------------------------------------------------------------