package mds;

import java.lang.reflect.Array;
import java.nio.ByteOrder;

import oneLiners.DataConvertPureJava;


/**
 *  Describes a data object that is to be sent or has been received from the server
 *  
 *  This will returns data only in the form it is stored!
 *   
 * */

public class MDSData extends Object
{
	static public final byte DTYPE_UCHAR = 2;
	static public final byte DTYPE_USHORT = 3;
	static public final byte DTYPE_UINT = 4;
	static public final byte DTYPE_CHAR = 6;
	static public final byte DTYPE_SHORT = 7;
	static public final byte DTYPE_INT = 8;
	static public final byte DTYPE_FLOAT = 10;
	static public final byte DTYPE_DOUBLE = 11;
	static public final byte DTYPE_COMPLEX = 12;
	static public final byte DTYPE_CSTRING = 14;	
	static final byte DTYPE_EVENT = 99;
	
	
	public byte dtype;
	public int  dims[];
	public byte data[];
	
	static final int STATUS_OK = 1;	
	public int status;
	
	public byte getDataType(){
		return dtype;
	}
	
	/** Rotates the internal 2D data, so that when read it is transposed */
	public void rotate2DData(){
		if(dims.length != 2)
			throw new IllegalArgumentException("MDS descriptor is not 2D");
		
		int ny = dims[1];
		int nx = dims[0];		              
		
		int size = getTypeSizeInBytes();
		byte newData[] = new byte[data.length];
		
		for(int i=0; i < ny; i++)
			for(int j=0; j < nx; j++)
				System.arraycopy(data, (i*nx+j)*size, newData, (j*ny+i)*size, size);			
		
		data = newData;
		dims = new int[]{ ny, nx }; //and swap the dims accordingly
	}
	
	public int getRank(){
		return dims.length;
	}
	
	/** Returns an array of the data's dimensions and type with the fastest changing
	 * index as the deepest.
	 * @return
	 */
	public Object getArray(){
		if(dtype == DTYPE_CSTRING)
			return String();
		//the internal dims are a bit backwards
		return DataConvertPureJava.arrayFromData(data, getJavaType(), getDimsFastestLast(), ByteOrder.LITTLE_ENDIAN);		
	}
	
	/** Returns the dimensions of the data with the dimension who's position changes for every element 
	 * (i.e changes fastest for linear scan through the data) as the first entry - dims[0]
	 */
	public int[] getDimsFastestFirst(){
		return dims.clone();
	}
	
	/** Returns the dimensions of the data with the dimenson who's position changes for every element 
	 * (i.e changes fastest for linear scan through the data) as the last entry - dims[n-1]
	 */
	public int[] getDimsFastestLast(){
		int n = dims.length;
		int invDims[] = new int[n];
		for(int i=0; i < n; i++)
			invDims[i] = dims[n-i-1];
		return invDims;	
	}
	
	public final Class<?> getJavaType(){
		switch(dtype){
			case DTYPE_UCHAR:
			case DTYPE_CHAR:	return byte.class;
			case DTYPE_USHORT:	 
			case DTYPE_SHORT:	return short.class;
			case DTYPE_UINT:
			case DTYPE_INT:	 	return int.class;
			case DTYPE_FLOAT:	return float.class;
			case DTYPE_DOUBLE:	return double.class;
			case DTYPE_CSTRING:	return String.class;
			default:
				throw new IllegalArgumentException("Unsupported type " + dtype);
		}
	}	
	
	public final int getTypeSizeInBytes(){
		switch(dtype){
			case DTYPE_UCHAR:
			case DTYPE_CHAR:	return 1;
			case DTYPE_USHORT:	 
			case DTYPE_SHORT:	return 2;
			case DTYPE_UINT:
			case DTYPE_INT:	 	
			case DTYPE_FLOAT:	return 4;
			case DTYPE_DOUBLE:	return 8;
			case DTYPE_CSTRING:	return data.length;
			default:
				throw new IllegalArgumentException("Unsupported type " + dtype);
		}
	}	
	
	/** constructs an empty MdsPlusDescriptor
	*/
	public MDSData() {
		dims = new int[0];
		data = new byte[0];
	}
	
	public MDSData(String s) {
		dtype = DTYPE_CSTRING;
		dims = new int[0];
                data = s.getBytes();
	}
		
	public final boolean isStatusOK(){
		return ((status & STATUS_OK) != 0);
	}

	/** returns the error string if low bit of status is zero.
	*/
	public String GetErrorString() {
		String ans = null;
		if ((dtype == DTYPE_CSTRING) && !isStatusOK() && (data.length > 0))
                        ans = new String(data);
		return ans;
	}
	
	public boolean isString(){
		return (dtype == DTYPE_CSTRING);
	}

	/** returns the data as a String.
	*/
	public String String() {
		String ans = null;
		if ((dtype == DTYPE_CSTRING) && isStatusOK() && (data.length > 0))
                        ans = new String(data);
		return ans;
	}
	


}

														