/////////////////////////////////////
//  Vector Class Implementation
//
//  File: Vector.cpp
//
//  Description:
/////////////////////////////////////
#ifndef x_vector_implementation_x
#define x_vector_implementation_x

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "Environment.h"
#include "vector.h"

template<class T> Vector<T>::Vector() {
  length = 0;
  data = 0;
  Delete = 0;
}

template<class T> Vector<T>::Vector(const Vector<T> & x) {
  length = 0;
  data = 0;
  allocate(x.length);
  for(int i = 0; i < length; i++)
    data[i] = x.data[i];
}

template<class T> Vector<T>::~Vector() {
  deallocate();
}

template<class T> void Vector<T>::allocate(int l) {
  deallocate();
  if(l>0){
    length = l;
    data = new T[l];
    Delete = 1;
  }
}

template<class T> void Vector<T>::fastallocate(int l){
  if(l>length)
    allocate(l);
  else
    length = l;
}

template<class T> void Vector<T>::deallocate() {
  if(Delete && data)
    delete [] data;
  length = 0;
  data = 0;
  Delete = 0;
}

template<class T> inline T& Vector<T>::operator[](int index) {
  if(index < 0 || index>=length)
	  print(L"Vector: access beyond array bounds!\n");
  return data[index];
}

template<class T> inline T& Vector<T>::get(int index) {
  if(index < 0 || index>=length)
	  print(L"Vector: access beyond array bounds!\n");
  return data[index];
}

template<class T> inline void Vector<T>::set(int index, T& newval) {
  data[index] = newval;
}

// Assignment
template<class T> void Vector<T>::copy(T * newdata, int len) {
  if(length != len) {
    allocate(len);
  }
  for(int i = 0; i < len; i++)
    data[i] = newdata[i];
}

template<class T> inline Vector<T>& Vector<T>::operator=(const Vector<T>& newval) {
  if(this != &newval) {
    if(length != newval.length) {
      allocate(newval.length);
    }
    for(int i = 0; i < newval.length; i++)
      data[i] = newval.data[i];
  }
  return *this;
}

template<class T> inline Vector<T>& Vector<T>::operator=(T scalar) {
  T * end = &(data[length]);
  for(T * p = data; p != end; p++)
    *p = scalar;
  return *this;
}

// Arithmetic

template<class T> inline Vector<T>& Vector<T>::operator*=(const Vector<T>& newval) {
  for(int i = 0; i < newval.length; i++)
    data[i] *= newval.data[i];
  return *this;
}

template<class T> inline Vector<T>& Vector<T>::operator/=(const Vector<T>& newval) {
  for(int i = 0; i < newval.length; i++)
    data[i] /= newval.data[i];
  return *this;
}

template<class T> inline Vector<T>& Vector<T>::operator*=(const T scalar) {
  for(int i = 0; i < length; i++)
    data[i] *= scalar;
  return *this;
}

template<class T> inline Vector<T>& Vector<T>::operator/=(const T scalar) {
  for(int i = 0; i < length; i++)
    data[i] /= scalar;
  return *this;
}

template<class T> inline Vector<T>& Vector<T>::operator-=(const T scalar) {
  for(int i = 0; i < length; i++)
    data[i] -= scalar;
  return *this;
}

template<class T> inline Vector<T>& Vector<T>::operator+=(const Vector<T>& newval) {
  for(int i = 0; i < newval.length; i++)
    data[i] += newval.data[i];
  return *this;
}


template<class T> inline Vector<T>& Vector<T>::operator-=(const Vector<T>& newval) {
  for(int i = 0; i < newval.length; i++)
    data[i] -= newval.data[i];
  return *this;
}


template<class T> Vector<T> Vector<T>::operator*(const Vector<T>& a) {
  Vector<T> v;
  v.allocate(length);
  for(int i = 0; i < length; i++)
    v.data[i] = a.data[i]*data[i];
  return v;
}

template<class T> Vector<T> Vector<T>::operator/(const Vector<T>& a) {
  Vector<T> v;
  v.allocate(length);
  for(int i = 0; i < length; i++)
    v.data[i] = data[i]/a.data[i];
  return v;
}

template<class T> Vector<T> Vector<T>::operator*(const T scalar) {
  Vector<T> v;
  v.allocate(length);
  for(int i = 0; i < length; i++)
    v.data[i] = scalar*data[i];
  return v;
}

template<class T> Vector<T> Vector<T>::operator/(const T scalar) {
  Vector<T> v;
  v.allocate(length);
  for(int i = 0; i < length; i++)
    v.data[i] = data[i]/scalar;
  return v;
}

template<class T> Vector<T> Vector<T>::operator+(const Vector<T>& a) {
  Vector<T> v;
  v.allocate(length);
  for(int i = 0; i < length; i++)
    v.data[i] = a.data[i]+data[i];
  return v;
}

template<class T> Vector<T> Vector<T>::operator-(const Vector<T>& a) {
  Vector<T> v;
  v.allocate(length);
  for(int i = 0; i < length; i++)
    v.data[i] = data[i]-a.data[i];
  return v;
}

template<class T> int Vector<T>::operator==(const Vector<T>& a) {
	if(a.length!=length)
		return 0;
	for(int i = 0; i < length; i++){
		if(a.data[i]!=data[i])
			return 0;
	}
	return 1;
}

template<class T> int Vector<T>::operator!=(const Vector<T>& a) {
	return !((*this)==a);
}

template<class T> T Vector<T>::dot(const Vector<T>& a) {
  int i;
  T sum;
  sum = 0;
  for(i=0;i<length;i++)
    sum += a.data[i]*data[i];
  return sum;
}

template<class T> T Vector<T>::distance(const Vector<T>& a) {
  T d,x;
  d = 0;
  for(int i=0;i<length;i++) {
    x = (a.data[i]-data[i]);
    d += x*x;
  }
  d = sqrt(d);
  return d;
}

template<class T> T Vector<T>::distance2(const Vector<T>& a) {
  T d,x;
  d = 0;
  for(int i=0;i<length;i++) {
    x = (a.data[i]-data[i]);
    d += x*x;
  }

  return d;
}

template<class T> T Vector<T>::max() {
  T x;
  x = data[0];
  for(int i=1;i<length;i++){
    if(x<data[i])
      x = data[i];
  }
  return x;
}


template<class T> T Vector<T>::min() {
  T x;
  x = data[0];
  for(int i=1;i<length;i++){
    if(x>data[i])
      x = data[i];
  }
  return x;
}

template<class T> int Vector<T>::argmax() {
  T x;
  int imax = 0;
  x = data[0];
  for(int i=1;i<length;i++){
    if(x<data[i]){
      x = data[i];
      imax = i;
    }
  }
  return imax;
}


template<class T> int Vector<T>::argmin() {
  T x;
  int imin = 0;
  x = data[0];
  for(int i=1;i<length;i++){
    if(x>data[i]){
      x = data[i];
      imin = i;
    }
  }
  return imin;
}

template<class T> T Vector<T>::norm() {
  T d;
  d = 0;
  for(int i=0;i<length;i++) {
    d += data[i]*data[i];
  }
  d = sqrt(d);

  return d;
}

template<class T> T Vector<T>::normalize(void) {
  int i;
  T d;
  d=0;
  for(i=0;i<length;i++)
    d += data[i]*data[i];
  if(d>0){
    d = sqrt(d);
    for(i=0;i<length;i++)
      data[i] /= d;
  }
  return d;
}

template<class T> T Vector<T>::normalize2() {
  int i;
  T d,d2;
  d2=0;
  for(i=0;i<length;i++)
    d2 += data[i]*data[i];

  if(d2>0) {
    d = sqrt(d2);
    for(i=0;i<length;i++)
      data[i] /= d;
  }

  return d2;
}

template<class T> void Vector<T>::setptr(T * vals, int len){
  data = vals;
  length = len;
  Delete = 0;
}

template<class T> void Vector<T>::setvoidptr(void * vals, int len){
  data = (T *)vals;
  length = len;
  Delete = 0;
}

template<class T> void Vector<T>::wrap(Vector<T>& v){
  data = v.data;
  length = v.length;
  Delete = 0;
}


template<class T> void Vector<T>::setptr(Vector<T>& v){
  data = v.data;
  length = v.length;
  Delete = 0;
}


template<class T> void Vector<T>::setmany(T * vals, int len){
  int i;
  allocate(len);
  for(i=0;i<len;i++)
    data[i].set(vals[i]);
}

template<class T> inline void Vector<T>::CopyFrom(const Vector<T>& newval,int org) {
  BlockCopyFrom(newval,0,newval.length,org);
}

template<class T> inline void Vector<T>::BlockCopyFrom(const Vector<T>& newval,int min, int max, int org) {
  int i;
  for(i = min; i < max; i++)
    data[i-min+org] = newval.data[i];
}

template<class T> void Vector<T>::Grow(int r) {
  resize(length+r);
}

template<class T> void Vector<T>::Shrink(int r) {
  if(r>=length)
    deallocate();
  else
    Resize(length-r);
}

template<class T> void Vector<T>::append(T scalar){
  resize(length+1);
  data[length-1] = scalar;
}

template<class T> void Vector<T>::resize(int r) {
  T * tmp;
  int min,i;
  
  min= (r<length)?r:length;
  
  tmp = new T[r];
  
  for(i=0;i<min;i++)
    tmp[i] = data[i];
  
  deallocate();
  length = r;
  data = tmp;
  Delete = 1;
}

template<class T> int Vector<T>::find(T x){
	int i;
	for(i=0;i<length;i++){
		if(x==data[i])
			return i;
	}
	return -1;
}

template<class T> void Vector<T>::insert(T x){
	if(find(x)==-1){
		append(x);
	}
}

template<class T> void Vector<T>::remove(T x){
	int i , c = 0;
	for(i=0;i<length;i++){
		if(data[i]==x)
			c++;
	}
	if(c==0)
		return;

	T * tmp;

	tmp = new T[length-c];

	c = 0;
	for(i=0;i<length;i++){
		if(data[i]!=x){
			tmp[c] = data[i];
			c++;
		}
	}

	deallocate();
	length = c;
	data = tmp;
	Delete = 1;
}

#endif
