/*
 * Copyright 2009-2010 Yuichiro Moriguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.morilib.awk.matrix;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 *
 *
 * @author MORIGUCHI, Yuichiro 2011/09/23
 */
public class ArrayDoubleVector implements DoubleVector {

	//
	private double[] array;

	/**
	 * 
	 * @param size
	 */
	public ArrayDoubleVector(int size) {
		this(size, 0);
	}

	/**
	 * 
	 * @param size
	 * @param fill
	 */
	public ArrayDoubleVector(int size, double fill) {
		this.array = new double[size];
		Arrays.fill(array, fill);
	}

	//
	/*package*/ ArrayDoubleVector(double... nums) {
		this.array = nums;
	}

	/**
	 * 
	 * @param nums
	 * @return
	 */
	public static ArrayDoubleVector newInstance(double... nums) {
		double[] c = new double[nums.length];

		System.arraycopy(nums, 0, c, 0, nums.length);
		return new ArrayDoubleVector(c);
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.ILispVector#size()
	 */
	public int size() {
		return array.length;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#get(int)
	 */
	public double get(int index) {
		return array[index];
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#set(int, net.morilib.lisp.LispNumber)
	 */
	public void set(int index, double x) {
		array[index] = x;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#multiply(net.morilib.lisp.LispNumber)
	 */
	public DoubleVector mul(double x) {
		ArrayDoubleVector r = new ArrayDoubleVector(array.length);

		for(int i = 0; i < array.length; i++) {
			r.array[i] = array[i] * x;
		}
		return r;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#add(net.morilib.lisp.matrix.ILispNumberVector)
	 */
	public DoubleVector add(DoubleVector v) {
		ArrayDoubleVector r = new ArrayDoubleVector(array.length);

		if(array.length != v.size()) {
			throw new AwkMatrixException("cannot add the vector");
		} else {
			for(int i = 0; i < array.length; i++) {
				r.array[i] = array[i] + v.get(i);
			}
			return r;
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#subtract(net.morilib.lisp.matrix.ILispNumberVector)
	 */
	public DoubleVector sub(DoubleVector v) {
		ArrayDoubleVector r = new ArrayDoubleVector(array.length);

		if(array.length != v.size()) {
			throw new AwkMatrixException("cannot subtract the vector");
		} else {
			for(int i = 0; i < array.length; i++) {
				r.array[i] = array[i] - v.get(i);
			}
			return r;
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#negate()
	 */
	public DoubleVector uminus() {
		ArrayDoubleVector r = new ArrayDoubleVector(array.length);

		for(int i = 0; i < array.length; i++) {
			r.array[i] = -array[i];
		}
		return r;
	}

	/* (non-Javadoc)
	 * @see java.lang.Iterable#iterator()
	 */
	public Iterator<Double> iterator() {
		return new Iterator<Double>() {

			private int p = 0;

			public boolean hasNext() {
				return p < array.length;
			}

			public Double next() {
				if(p >= array.length) {
					throw new NoSuchElementException();
				}
				return array[p++];
			}

			public void remove() {
				throw new UnsupportedOperationException();
			}

		};
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#innerProduct(net.morilib.lisp.matrix.ILispNumberVector)
	 */
	public double innerProduct(
			DoubleVector b) throws AwkMatrixException {
		if(b.size() != size()) {
			throw new AwkMatrixException(
					"size of the vectors are different");
		} else {
			double x = 0.0;

			for(int i = 0; i < size(); i++) {
				x = x + get(i) * b.get(i);
			}
			return x;
		}
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.matrix.ILispNumberVector#normSquared()
	 */
	public double normSquared() {
		double x = 0.0;

		for(int i = 0; i < size(); i++) {
			x = x + get(i) * get(i);
		}
		return x;
	}

	/* (non-Javadoc)
	 * @see net.morilib.lisp.math.matrix.ILispNumberVector#isEqualTo(net.morilib.lisp.math.matrix.ILispNumberVector)
	 */
	public boolean isEqualTo(DoubleVector y) {
		if(size() == y.size()) {
			for(int i = 0; i < size(); i++) {
				if(get(i) != y.get(i)) {
					return false;
				}
			}
			return true;
		} else {
			return false;
		}
	}

}
