
package org.ajwcc.pduUtils.gsm3040.ie;

//PduUtils Library - A Java library for generating GSM 3040 Protocol Data Units (PDUs)
//
//Copyright (C) 2008, Ateneo Java Wireless Competency Center/Blueblade Technologies, Philippines.
//PduUtils is distributed under the terms of the Apache License version 2.0
//
//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.
public class ConcatInformationElement extends InformationElement
{
	private static final int CONCAT_IE_LENGTH_16BIT = 6;

	private static final int CONCAT_IE_LENGTH_8BIT = 5;

	public static final int CONCAT_8BIT_REF = 0x00;

	public static final int CONCAT_16BIT_REF = 0x08;

	private static int defaultConcatType = CONCAT_8BIT_REF;

	private static int defaultConcatLength = CONCAT_IE_LENGTH_8BIT;

	public static int getDefaultConcatLength()
	{
		return defaultConcatLength;
	}

	public static int getDefaultConcatType()
	{
		return defaultConcatType;
	}

	public static void setDefaultConcatType(int identifier)
	{
		switch (identifier)
		{
			case CONCAT_8BIT_REF:
				defaultConcatType = CONCAT_8BIT_REF;
				defaultConcatLength = CONCAT_IE_LENGTH_8BIT;
				break;
			case CONCAT_16BIT_REF:
				defaultConcatType = CONCAT_16BIT_REF;
				defaultConcatLength = CONCAT_IE_LENGTH_16BIT;
				break;
			default:
				throw new RuntimeException("Invalid Concat type");
		}
	}

	ConcatInformationElement(byte identifier, byte[] data)
	{
		super(identifier, data);
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			// iei
			// iel
			// ref
			// max
			// seq
			if (data.length != 3) { throw new RuntimeException("Invalid data length in: " + getClass().getSimpleName()); }
		}
		else if (getIdentifier() == CONCAT_16BIT_REF)
		{
			// iei
			// iel
			// ref(2 bytes)
			// max
			// seq
			if (data.length != 4) { throw new RuntimeException("Invalid data length in: " + getClass().getSimpleName()); }
		}
		else
		{
			throw new RuntimeException("Invalid identifier in data in: " + getClass().getSimpleName());
		}
		validate();
	}

	ConcatInformationElement(int identifier, int mpRefNo, int mpMaxNo, int mpSeqNo)
	{
		super();
		byte[] data = null;
		switch (identifier)
		{
			case CONCAT_8BIT_REF:
				data = new byte[3];
				data[0] = (byte) (mpRefNo & 0xFF);
				data[1] = (byte) (mpMaxNo & 0xFF);
				data[2] = (byte) (mpSeqNo & 0xFF);
				break;
			case CONCAT_16BIT_REF:
				data = new byte[4];
				data[0] = (byte) ((mpRefNo & 0xFF00) >>> 8);
				data[1] = (byte) (mpRefNo & 0xFF);
				data[2] = (byte) (mpMaxNo & 0xFF);
				data[3] = (byte) (mpSeqNo & 0xFF);
				break;
			default:
				throw new RuntimeException("Invalid identifier for " + getClass().getSimpleName());
		}
		initialize((byte) (identifier & 0xFF), data);
		validate();
	}

	public int getMpRefNo()
	{
		// this is 8-bit in 0x00 and 16-bit in 0x08 
		byte[] data = getData();
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			return (data[0] & (0xFF));
		}
		else if (getIdentifier() == CONCAT_16BIT_REF) { return ((data[0] << 8) | data[1]) & (0xFFFF); }
		throw new RuntimeException("Invalid identifier");
	}

	public void setMpRefNo(int mpRefNo)
	{
		// this is 8-bit in 0x00 and 16-bit in 0x08 
		byte[] data = getData();
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			data[0] = (byte) (mpRefNo & (0xFF));
		}
		else if (getIdentifier() == CONCAT_16BIT_REF)
		{
			data[0] = (byte) ((mpRefNo >>> 8) & (0xFF));
			data[1] = (byte) ((mpRefNo) & (0xFF));
		}
		else
		{
			throw new RuntimeException("Invalid identifier");
		}
	}

	public int getMpMaxNo()
	{
		byte[] data = getData();
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			return (data[1] & (0xFF));
		}
		else if (getIdentifier() == CONCAT_16BIT_REF) { return (data[2] & (0xFF)); }
		throw new RuntimeException("Invalid identifier");
	}

	public void setMpMaxNo(int mpMaxNo)
	{
		byte[] data = getData();
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			data[1] = (byte) (mpMaxNo & 0xFF);
		}
		else if (getIdentifier() == CONCAT_16BIT_REF)
		{
			data[2] = (byte) (mpMaxNo & 0xFF);
		}
		else
		{
			throw new RuntimeException("Invalid identifier");
		}
	}

	public int getMpSeqNo()
	{
		byte[] data = getData();
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			return (data[2] & (0xFF));
		}
		else if (getIdentifier() == CONCAT_16BIT_REF) { return (data[3] & (0xFF)); }
		throw new RuntimeException("Invalid identifier");
	}

	public void setMpSeqNo(int mpSeqNo)
	{
		byte[] data = getData();
		if (getIdentifier() == CONCAT_8BIT_REF)
		{
			data[2] = (byte) (mpSeqNo & (0xFF));
		}
		else if (getIdentifier() == CONCAT_16BIT_REF)
		{
			data[3] = (byte) (mpSeqNo & (0xFF));
		}
		else
		{
			throw new RuntimeException("Invalid identifier");
		}
	}

	@Override
	public String toString()
	{
		StringBuffer sb = new StringBuffer();
		sb.append(super.toString());
		sb.append("[MpRefNo: ");
		sb.append(getMpRefNo());
		sb.append(", MpMaxNo: ");
		sb.append(getMpMaxNo());
		sb.append(", MpSeqNo: ");
		sb.append(getMpSeqNo());
		sb.append("]");
		return sb.toString();
	}

	private void validate()
	{
		if (getMpMaxNo() == 0) { throw new RuntimeException("mpMaxNo must be > 0"); }
		if (getMpSeqNo() == 0) { throw new RuntimeException("mpSeqNo must be > 0"); }
	}
}
