/*******************************************************************************
 Jimm - Mobile Messaging - J2ME ICQ clone
 Copyright (C) 2003-05  Jimm Project

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 ********************************************************************************
 File: src/jimm/comm/ToIcqSrvPacket.java
 Version: 0.5.1  Date: 2006/10/31
 Author(s): Manuel Linsmayer, Andreas Rossbacher
 *******************************************************************************/


package jimm.comm;


import jimm.JimmException;


public class ToIcqSrvPacket extends SnacPacket
{


	// CLI_REQOFFLINEMSGS packet subcommand
	public static final int CLI_REQOFFLINEMSGS_SUBCMD = 0x003C;


	// CLI_ACKOFFLINEMSGS packet subcommand
	public static final int CLI_ACKOFFLINEMSGS_SUBCMD = 0x003E;


	// CLI_META packet subcommand and types
	public static final int CLI_META_SUBCMD = 0x07D0;
	public static final int CLI_META_REQINFO_TYPE = 0x04D0;   // doesn't work
	public static final int CLI_META_REQMOREINFO_TYPE = 0x04B2;


	/****************************************************************************/
	/****************************************************************************/
	/****************************************************************************/


	// ICQ sequence number
	protected int icqSequence;


	// UIN
	protected String uin;


	// Subcommand
	protected int subcommand;


	// Constructor
	public ToIcqSrvPacket(int sequence, long reference, int snacFlags, int icqSequence, String uin, int subcommand, byte[] extData, byte[] data)
	{
		super(sequence, SnacPacket.CLI_TOICQSRV_FAMILY, SnacPacket.CLI_TOICQSRV_COMMAND, snacFlags, reference, extData, data);
		this.icqSequence = icqSequence;
		this.uin = new String(uin);
		this.subcommand = subcommand;
	}

	// Constructor
	public ToIcqSrvPacket(long reference, int icqSequence, String uin, int subcommand, byte[] extData, byte[] data)
	{
		this(-1,reference,0,icqSequence,uin,subcommand,extData,data);
	}

	// Constructor
	public ToIcqSrvPacket(long reference, String uin, int subcommand, byte[] extData, byte[] data)
	{
		this(-1, reference, 0, -1, uin, subcommand, extData, data);
	}


	// Returns the ICQ sequence number
	public int getIcqSequence()
	{
		return (this.icqSequence);
	}


	// Sets the ICQ sequence number
	void setIcqSequence(int icqSequence)
	{
		this.icqSequence = icqSequence;
	}


	// Returns the UIN
	public String getUin()
	{
		return (new String(this.uin));
	}


	// Returns the subcommand
	public int getSubcommand()
	{
		return (this.subcommand);
	}


	// Returns the package as byte array
	public byte[] toByteArray()
	{

		// Allocate memory
		byte buf[] = new byte[6 + 10 + 14 + this.data.length + (this.extData.length > 0 ? 2 + this.extData.length : 0)];

		// Assemble FLAP header
		Util.putByte(buf, 0, 0x2A);   // FLAP.ID
		Util.putByte(buf, 1, 0x02);   // FLAP.CHANNEL
		Util.putWord(buf, 2, Icq.getFlapSequence());   // FLAP.SEQUENCE
		Util.putWord(buf, 4, 10 + 14 + this.data.length + (this.extData.length > 0 ? 2 + this.extData.length : 0));   // FLAP.LENGTH

		// Assemble SNAC header
		Util.putWord(buf, 6, this.family);   // SNAC.FAMILY
		Util.putWord(buf, 8, this.command);   // SNAC.COMMAND
		Util.putWord(buf, 10, (this.extData.length > 0 ? 0x8000 : 0x0000));   // SNAC.FLAGS
		Util.putDWord(buf, 12, this.reference);   // SNAC.REFERENCE;

		// Assemlbe SNAC.DATA
		if (this.extData.length > 0)
		{
			Util.putWord(buf, 16, this.extData.length);
			System.arraycopy(this.extData, 0, buf, 18, this.extData.length);
			Util.putWord(buf, 18 + this.extData.length, 0x0001);
			Util.putWord(buf, 20 + this.extData.length, 10 + this.data.length);
			Util.putWord(buf, 22 + this.extData.length, 8 + this.data.length, false);   // CLI_TOICQSRV.LENGTH in Little Endian
			Util.putDWord(buf, 24 + this.extData.length, Long.parseLong(this.uin), false);   // CLI_TOICQSRV.UIN in Little Endian
			Util.putWord(buf, 28 + this.extData.length, this.subcommand, false);   // CLI_TOICQSRV.SUBCOMMAND in Little Endian
			Util.putWord(buf, 30 + this.extData.length, this.icqSequence, false);   // CLI_TOICQSRV.SEQUENCE in Little Endian
			System.arraycopy(this.data, 0, buf, 32 + this.extData.length, this.data.length);   // CLI_TOICQSRV.DATA in Little Endian
		}
		else
		{
			Util.putWord(buf, 16, 0x0001);
			Util.putWord(buf, 18, 10 + this.data.length);
			Util.putWord(buf, 20, 8 + this.data.length, false);   // CLI_TOICQSRV.LENGTH in Little Endian
			Util.putDWord(buf, 22, Long.parseLong(this.uin), false);   // CLI_TOICQSRV.UIN in Little Endian
			Util.putWord(buf, 26, this.subcommand, false);   // CLI_TOICQSRV.SUBCOMMAND in Little Endian
			Util.putWord(buf, 28, this.icqSequence, false);   // CLI_TOICQSRV.SEQUENCE in Little Endian
			System.arraycopy(this.data, 0, buf, 30, this.data.length);   // CLI_TOICQSRV.DATA in Little Endian
		}

		// Return
		return (buf);

	}


	// Parses given byte array and returns a ToIcqSrvPacket object
	public static Packet parse(byte[] buf, int off, int len) throws JimmException
	{

		// Get FLAP sequence number
		int flapSequence = Util.getWord(buf, off + 2);

		// Get length of FLAP data
		int flapLength = Util.getWord(buf, off + 4);

		// Check length (min. 24 bytes)
		if (flapLength < 24)
		{
			throw (new JimmException(137, 3));
		}

		// Get SNAC flags
		int snacFlags = Util.getWord(buf, off + 10);

		// Get SNAC reference
		long snacReference = Util.getDWord(buf, off + 12);

		// Get data and extra data (if available)
		byte[] extData;
		byte[] data;
		String uin;
		int subcommand;
		int icqSequence;
		if (snacFlags == 0x8000)
		{

			// Check length (min. 26 bytes)
			if (flapLength < 10 + 24 + 2)
			{
				throw (new JimmException(137, 4));
			}

			// Get length of extra data
			int extDataLength = Util.getWord(buf, off + 16);

			// Check length (min. 26+extDataLength bytes)
			if (flapLength < 10 + 24 + 2 + extDataLength)
			{
				throw (new JimmException(137, 5));
			}

			// Get extra data
			extData = new byte[extDataLength];
			System.arraycopy(buf, off + 6 + 10 + 2, extData, 0, extDataLength);

			// Get uin, subcommand and icq sequence number
			uin = String.valueOf(Util.getDWord(buf, off + 6 + 10 + 6 + 2 + extDataLength, false));
			subcommand = Util.getWord(buf, off + 6 + 10 + 10 + 2 + extDataLength, false);
			icqSequence = Util.getWord(buf, off + 6 + 10 + 12 + 2 + extDataLength, false);

			// Get data
			data = new byte[flapLength - 10 - 14 - 2 - extDataLength];
			System.arraycopy(buf, off + 6 + 10 + 14 + 2 + extDataLength, data, 0, flapLength - 10 - 14 - 2 - extDataLength);

		}
		else
		{

			// Get uin, subcommand and icq sequence number
			uin = String.valueOf(Util.getDWord(buf, off + 6 + 10 + 6, false));
			subcommand = Util.getWord(buf, off + 6 + 10 + 10, false);
			icqSequence = Util.getWord(buf, off + 6 + 10 + 12, false);

			// Get extra data and data
			extData = new byte[0];
			data = new byte[flapLength - 10 - 14];
			System.arraycopy(buf, off + 6 + 10 + 14, data, 0, flapLength - 10 - 14);

		}

		// Instantiate ToIcqSrvPacket
		return (new ToIcqSrvPacket(flapSequence, snacReference, snacFlags, icqSequence, uin, subcommand, extData, data));

	}


	// Parses given byte array and returns a ToIcqSrvPacket object
	public static Packet parse(byte[] buf) throws JimmException
	{
		return (ToIcqSrvPacket.parse(buf, 0, buf.length));
	}


}
