package com.limegroup.gnutella.messages.vendor;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

import com.limegroup.gnutella.ErrorService;
import com.limegroup.gnutella.messages.BadGGEPBlockException;
import com.limegroup.gnutella.messages.BadGGEPPropertyException;
import com.limegroup.gnutella.messages.BadPacketException;
import com.limegroup.gnutella.messages.GGEP;

public final class UpdateResponse extends VendorMessage {
    
    private static final int NON_GGEP_VERSION = 1;
    
    public static final int VERSION = 2;

    private byte [] update;
    
    /**
     * Constructs a new UpdateResponse message from the network.
     */
    UpdateResponse(byte[] guid, byte ttl, byte hops, int version, byte[] payload) 
                                                     throws BadPacketException {
        super(guid, ttl, hops, F_LIME_VENDOR_ID, F_UPDATE_RESP, version, payload);
        
        if (version == NON_GGEP_VERSION)
            update = payload;
        else {
            // try to parse a GGEP block
            try {
                GGEP ggep = new GGEP(payload,0,null);
                if (ggep.hasKey(UpdateRequest.UNCOMPRESSED_UPDATE_KEY))
                    update = ggep.getBytes(UpdateRequest.UNCOMPRESSED_UPDATE_KEY);
                else if (ggep.hasKey(UpdateRequest.COMPRESSED_UPDATE_KEY))
                    update = ggep.getBytes(UpdateRequest.COMPRESSED_UPDATE_KEY);
                else throw new BadPacketException("no update in GGEP?");
            } catch (BadGGEPPropertyException bad) {
                throw new BadPacketException("bad ggep property");
            } catch (BadGGEPBlockException notSoBad) {
                update = payload;
            }
        }
    }
    
    /**
     * Constructs an outgoing message with the payload being the signed parameter body.
     */
    private UpdateResponse(byte[] body, int version) {
        super(F_LIME_VENDOR_ID, F_UPDATE_RESP, version, body);
    }

    public static UpdateResponse createUpdateResponse(byte [] update, UpdateRequest request) {
        if (!request.hasGGEP()) 
            return new UpdateResponse(update, NON_GGEP_VERSION);
        
        GGEP ggep = new GGEP(true);
        if (request.requestsCompressed()) {
            ggep.putCompressed(UpdateRequest.COMPRESSED_UPDATE_KEY,update);
        } else
            ggep.put(UpdateRequest.UNCOMPRESSED_UPDATE_KEY,update);
        
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ggep.write(baos);
        } catch (IOException bad) {
            ErrorService.error(bad);
        }
        
        return new UpdateResponse(baos.toByteArray(),VERSION);
    }
    
    public byte[] getUpdate() {
        return update;
    }
}
