package mikera.vectorz.impl;

import java.nio.DoubleBuffer;

import mikera.arrayz.INDArray;
import mikera.vectorz.AVector;
import mikera.vectorz.Op;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.VectorzException;

/**
 * A vector that represents the concatenation of many vectors.
 * 
 * @author Mike
 *
 */
public final class JoinedMultiVector extends AJoinedVector {
	private static final long serialVersionUID = 6226205676178066609L;
	
	/**
	 * The number of segments
	 */
	private final int n;
	
	/**
	 * The set of vectors that define all the segments of this JoinedMultiVector
	 */
	private final AVector[] vecs;
	
	// array of split positions [0, ...... , length] with length n+1
	private final int[] splits;
	
	private JoinedMultiVector(int length, AVector[] vecs, int[] splits) {
		super(length);
		n=vecs.length;
		this.vecs=vecs;
		this.splits=splits;
	}
	
	private JoinedMultiVector(AVector[] vs) {
		this(sumOfLengths(vs),vs,new int[vs.length+1]);
		int j=0;
		for (int i=0; ithis.length)||(length<0)) throw new IndexOutOfBoundsException(ErrorMessages.invalidRange(this,offset, length));
		int i1=IntArrays.indexLookup(splits, start);
		int i2=IntArrays.indexLookup(splits, end-1);
		if (i1==i2) {
			offset-=splits[i1];
			vecs[i1].addToArray(offset, array,arrayOffset,length);
			return;
		}
		vecs[i1].addToArray(offset-splits[i1], array, arrayOffset,splits[i1+1]-offset);
		vecs[i2].addToArray(0, array, arrayOffset+splits[i2]-offset,end-splits[i2]);
		for (int i=i1+1;ithis.length)||(length<0)) throw new IndexOutOfBoundsException(ErrorMessages.invalidRange(this,offset, length));
		int i1=IntArrays.indexLookup(splits, start);
		int i2=IntArrays.indexLookup(splits, end-1);
		if (i1==i2) {
			offset-=splits[i1];
			vecs[i1].addMultipleToArray(factor,offset, array,arrayOffset,length);
			return;
		}
		vecs[i1].addMultipleToArray(factor,offset-splits[i1], array, arrayOffset,splits[i1+1]-offset);
		vecs[i2].addMultipleToArray(factor,array, arrayOffset+splits[i2]-offset);
		for (int i=i1+1;ithis.length)||(length<0)) throw new IndexOutOfBoundsException(ErrorMessages.invalidRange(this,start, length));
		if (length==this.length) return this;
		int i1=IntArrays.indexLookup(splits, start);
		int i2=IntArrays.indexLookup(splits, end-1);
		if (i1==i2) {
			return vecs[i1].subVector(start-splits[i1], length);
		}
		int nn =i2-i1+1;
		AVector[] nvecs=new AVector[nn];
		nvecs[0]=vecs[i1].subVector(start-splits[i1], splits[i1+1]-start);
		nvecs[nn-1]=vecs[i2].subVector(0, end-splits[i2]);
		for (int i=1; i<(i2-i1); i++) {
			nvecs[i]=vecs[i1+i];
		}
		return new JoinedMultiVector(nvecs);
	}
	
	@Override
	public AVector tryEfficientJoin(AVector v) {
		if (v instanceof JoinedMultiVector) return join((JoinedMultiVector)v);
		if (v instanceof JoinedVector) return join((JoinedVector)v);
		
		AVector ej=vecs[n-1].tryEfficientJoin(v);
		if (ej!=null) {
			AVector[] nvecs=vecs.clone();
			nvecs[n-1]=ej;		
			return new JoinedMultiVector(nvecs);
		} else {		
			AVector[] nvecs=new AVector[n+1];
			System.arraycopy(vecs, 0, nvecs, 0, n);
			nvecs[n]=v;	
			return new JoinedMultiVector(nvecs);
		}
	}
	
	public AVector join(JoinedMultiVector v) {
		AVector[] nvecs=new AVector[n+v.n];
		System.arraycopy(vecs, 0, nvecs, 0, n);
		System.arraycopy(v.vecs, 0, nvecs, n, v.n);
		
		return new JoinedMultiVector(nvecs);
	}
	
	public AVector join(JoinedVector v) {
		AVector ej=vecs[n-1].tryEfficientJoin(v.left);
		if (ej!=null) {
			AVector[] nvecs=new AVector[n+1];
			System.arraycopy(vecs, 0, nvecs, 0, n);
			nvecs[n-1]=ej;
			nvecs[n]=v.right;
			return new JoinedMultiVector(nvecs);
		} else {
			AVector[] nvecs=new AVector[n+2];
			System.arraycopy(vecs, 0, nvecs, 0, n);
			nvecs[n]=v.left;
			nvecs[n+1]=v.right;
			return new JoinedMultiVector(nvecs);
		}
	}
	
	@Override
	public void add(AVector a) {
		assert(length()==a.length());
		if (a instanceof JoinedMultiVector) {
			add((JoinedMultiVector)a);	
		} else {
			add(a,0);
		}
	}
	
	public void add(JoinedMultiVector a) {
		if (IntArrays.equals(splits, a.splits)) {
			for (int i=0; iresult) result=m;
		}
		return result;
	}
	
	@Override
	public double elementMin() {
		double result=vecs[0].elementMin();
		for (int i=0; i 

Ads help maintain this website.