/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2004 Gregor Koukkoullis ( phex <at> kouk <dot> de )
 *
 *  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
 * 
 *  --- CVS Information ---
 *  $Id: VendorMsg.java,v 1.5 2004/08/23 12:23:20 gregork Exp $
 */
package phex.msg.vendor;

import java.io.IOException;
import java.util.Arrays;

import phex.msg.*;
import phex.msg.MsgHeader;
import phex.utils.*;
import phex.utils.IOUtil;

/**
 * 
 */
public abstract class VendorMsg extends Message implements VendorMessageConstants
{
    private static final int VM_PREFIX_LENGTH = 8;
    
    private MsgHeader header;
    private byte[] vendorId;
    private int subSelector;
    private int version;
    private byte[] data;
    
    public VendorMsg( MsgHeader header, byte[] vendorId, int subSelector, 
        int version, byte[] data )
    {
        this.header = header;
        this.vendorId = vendorId;
        this.subSelector = subSelector;
        this.version = version;
        this.data = data;
    }
    
    public VendorMsg( byte[] vendorId, int subSelector, 
        int version, byte[] data )
    {
        this.header = new MsgHeader( new GUID(), MsgHeader.VENDOR_MESSAGE_PAYLOAD,
            (byte)1, (byte)0, (VM_PREFIX_LENGTH + data.length)  );
        this.vendorId = vendorId;
        this.subSelector = subSelector;
        this.version = version;
        this.data = data;
    }
    
    public void writeMessage( GnutellaOutputStream outStream )
        throws IOException
    {
        header.writeHeader( outStream );
        outStream.write( vendorId );
        IOUtil.serializeShortLE( (short)subSelector, outStream );
        IOUtil.serializeShortLE( (short)version, outStream );
        outStream.write( data );        
    }
    
    public MsgHeader getHeader()
    {
        return header;
    }
    
    public static VendorMsg parseMessage( MsgHeader header, byte[] aBody )
        throws InvalidMessageException
    {
        if ( aBody.length < VM_PREFIX_LENGTH )
        {
            throw new InvalidMessageException( "Vendor Message Wrong Format" );
        }
        byte[] vendorId = new byte[4];
        System.arraycopy(aBody, 0, vendorId, 0, 4);

        int subSelector =
            IOUtil.unsignedShort2Int(IOUtil.deserializeShortLE(aBody, 4));
        int version =
            IOUtil.unsignedShort2Int(IOUtil.deserializeShortLE(aBody, 6));

        byte[] data = new byte[aBody.length - VM_PREFIX_LENGTH];
        System.arraycopy(aBody, VM_PREFIX_LENGTH, data, 0, data.length);
        
        if ( subSelector == SUBSELECTOR_MESSAGES_SUPPORTED
            && Arrays.equals( vendorId, VENDORID_NULL ) )
        {
            return new MessagesSupportedVMsg( header, vendorId, subSelector, 
                version, data );
        }
        
        if ( subSelector == SUBSELECTOR_TCP_CONNECT_BACK 
            && Arrays.equals( vendorId, VENDORID_BEAR ))
        {
            return new TCPConnectBackVMsg( header, vendorId, subSelector,
                version, data );
        }
        
        // ignoring BEAR5v1 (BearHorizonPing)
        
        throw new InvalidMessageException(
            "Unknown Vendor Message variant: " + new String( vendorId )
            + subSelector + "v" + version);
    }
}
