/*
	Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
	и других спецификаций для функционирования компактных приложений на языке
	Java (мидлетов) в среде программного обеспечения Малик Эмулятор.

	Copyright © 2016, 2019 Малик Разработчик

	Это свободная программа: вы можете перераспространять ее и/или изменять
	ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
	в каком она была опубликована Фондом свободного программного обеспечения;
	либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

	Эта программа распространяется в надежде, что она будет полезной,
	но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
	или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
	общественной лицензии GNU.

	Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
	вместе с этой программой. Если это не так, см.
	<https://www.gnu.org/licenses/>.
*/


package javax.bluetooth;

import java.util.*;

public class DataElement extends Object
{
	public static final int NULL = 0; /* javax.bluetooth.NULL */
	public static final int U_INT_1 = 8; /* java.lang.Long */
	public static final int U_INT_2 = 9; /* java.lang.Long */
	public static final int U_INT_4 = 10; /* java.lang.Long */
	public static final int U_INT_8 = 11; /* byte[] */
	public static final int U_INT_16 = 12; /* byte[] */
	public static final int INT_1 = 16; /* java.lang.Long */
	public static final int INT_2 = 17; /* java.lang.Long */
	public static final int INT_4 = 18; /* java.lang.Long */
	public static final int INT_8 = 19; /* java.lang.Long */
	public static final int INT_16 = 20; /* byte[] */
	public static final int UUID = 24; /* javax.bluetooth.UUID */
	public static final int STRING = 32; /* java.lang.String */
	public static final int BOOL = 40; /* java.lang.Boolean */
	public static final int DATSEQ = 48; /* javax.bluetooth.DataElement[] */
	public static final int DATALT = 56; /* javax.bluetooth.DataElement[] */
	public static final int URL = 64; /* java.lang.String */
	private static final Class DATA_ELEMENT_ARRAY1D_CLASS;

	static
	{
		DATA_ELEMENT_ARRAY1D_CLASS = DataElement[].class;
	}


	private final class Enumerator extends Object
			implements Enumeration
	{
		private int index;

		Enumerator()
		{
		}

		public boolean hasMoreElements()
		{
			return index < (DataElement.this).count;
		}

		public Object nextElement()
		{
			int i;
			int error;
			DataElement thisDataElement;
			Object result;
			error = 0;
			synchronized((thisDataElement = DataElement.this).lock)
			{
				label0:
				{
					if((i = index) >= thisDataElement.count)
					{
						error = 1;
						result = null;
						break label0;
					}
					index = i + 1;
					result = ((Object[]) thisDataElement.value)[i];
				}
			}
			if(error == 1)
			{
				throw new NoSuchElementException("DataElement: " +
						"больше не осталось элементов для перечисления.");
			}
			return result;
		}
	}

	private int type;
	private int count;
	private Object value;
	private Object lock;

	public DataElement(boolean value)
	{
		this.type = BOOL;
		this.value = value ? Boolean.TRUE : Boolean.FALSE;
	}

	public DataElement(int type)
	{
		switch(type)
		{
		default:
			throw new IllegalArgumentException("DataElement: " +
					"недопустимое значение параметра type.");
		case NULL:
			this.type = type;
			this.value = javax.bluetooth.NULL.INSTANCE;
			break;
		case DATALT:
		case DATSEQ:
			this.type = type;
			this.count = 0;
			this.value = new DataElement[2];
			this.lock = new Object();
			break;
		}
	}

	public DataElement(int type, long value)
	{
		switch(type)
		{
		default:
			throw new IllegalArgumentException("DataElement: " +
					"недопустимое значение параметра type.");
		case U_INT_1:
			if(value < 0x00L || value > 0xffL)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			break;
		case U_INT_2:
			if(value < 0x0000L || value > 0xffffL)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			break;
		case U_INT_4:
			if(value < 0x00000000L || value > 0xffffffffL)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			break;
		case INT_1:
			if(value < -0x80L || value > 0x7fL)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			break;
		case INT_2:
			if(value < -0x8000L || value > 0x7fffL)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			break;
		case INT_4:
			if(value < -0x80000000L || value > 0x7fffffffL)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			break;
		case INT_8:
			break;
		}
		this.type = type;
		this.value = new Long(value);
	}

	public DataElement(int type, Object value)
	{
		byte[] copy;
		switch(type)
		{
		default:
			throw new IllegalArgumentException("DataElement: " +
					"недопустимое значение параметра type.");
		case URL:
		case STRING:
			if(!(value instanceof String))
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			this.type = type;
			this.value = value;
			break;
		case UUID:
			if(!(value instanceof UUID))
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			this.type = type;
			this.value = value;
			break;
		case INT_16:
		case U_INT_16:
			if((!(value instanceof byte[])) || ((byte[]) value).length != 16)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			this.type = type;
			this.value = copy = new byte[16];
			Array.copy((byte[]) value, 0, copy, 0, 16);
			break;
		case U_INT_8:
			if((!(value instanceof byte[])) || ((byte[]) value).length != 8)
			{
				throw new IllegalArgumentException("DataElement: " +
						"недопустимое значение параметра value.");
			}
			this.type = type;
			this.value = copy = new byte[8];
			Array.copy((byte[]) value, 0, copy, 0, 8);
			break;
		}
	}

	public void addElement(DataElement element)
	{
		int len;
		DataElement[] value;
		if(element == null)
		{
			throw new NullPointerException("DataElement.addElement: " +
					"параметр element равен нулевой ссылке.");
		}
		DATA_ELEMENT_ARRAY1D_CLASS.cast(this.value);
		synchronized(lock)
		{
			if((len = count) == (value = (DataElement[]) this.value).length)
			{
				Array.copy(value, 0, value = new DataElement[len << 1], 0, len);
				this.value = value;
			}
			value[len] = element;
			this.count = len + 1;
		}
	}

	public void insertElementAt(DataElement element, int index)
	{
		int c;
		int len;
		int error;
		DataElement[] value;
		if(element == null)
		{
			throw new NullPointerException("DataElement.insertElementAt: " +
					"параметр element равен нулевой ссылке.");
		}
		DATA_ELEMENT_ARRAY1D_CLASS.cast(this.value);
		error = 0;
		synchronized(lock)
		{
			label0:
			{
				if(index > (len = count) || index < 0)
				{
					error = 1;
					break label0;
				}
				if(len == (value = (DataElement[]) this.value).length)
				{
					Array.copy(value, 0, value = new DataElement[len << 1], 0, len);
					this.value = value;
				}
				if((c = len - index) > 0)
				{
					Array.copy(value, index, value, index + 1, c);
				}
				value[index] = element;
				this.count = len + 1;
			}
		}
		if(error == 1)
		{
			throw new IndexOutOfBoundsException("DataElement.insertElementAt: " +
					"параметр index выходит из диапазона.");
		}
	}

	public boolean removeElement(DataElement element)
	{
		boolean result;
		int c;
		int i;
		int len;
		DataElement[] value;
		if(element == null)
		{
			throw new NullPointerException("DataElement.insertElementAt: " +
					"параметр element равен нулевой ссылке.");
		}
		DATA_ELEMENT_ARRAY1D_CLASS.cast(this.value);
		synchronized(lock)
		{
			result = false;
			for(len = count, value = (DataElement[]) this.value, i = 0; i < len; i++)
			{
				if(value[i] == element)
				{
					result = true;
					break;
				}
			}
			if(result)
			{
				if((c = len - i - 1) > 0)
				{
					Array.copy(value, i + 1, value, i, c);
				}
				this.count = len - 1;
			}
		}
		return result;
	}

	public int getSize()
	{
		DATA_ELEMENT_ARRAY1D_CLASS.cast(this.value);
		return count;
	}

	public int getDataType()
	{
		return type;
	}

	public boolean getBoolean()
	{
		return ((Boolean) value).booleanValue();
	}

	public long getLong()
	{
		return ((Long) value).longValue();
	}

	public Object getValue()
	{
		int len;
		byte[] value;
		byte[] result;
		switch(type)
		{
		default:
			throw new ClassCastException("DataElement.getValue: " +
					"тип значения не соответствует запрашиваемому.");
		case URL:
		case STRING:
		case UUID:
			return this.value;
		case DATALT:
		case DATSEQ:
			return this.new Enumerator();
		case U_INT_8:
		case U_INT_16:
		case INT_16:
			Array.copy(value = (byte[]) this.value, 0,
					result = new byte[len = value.length], 0, len);
			return result;
		}
	}
}
