/**
 * Copyright 2011 Google Inc.
 *
 * 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.
 */

package com.google.bitcoin.core;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;

/**
 * This message is a reference or pointer to an output of a different transaction.
 */
public class TransactionOutPoint extends ChildMessage implements Serializable {
    private static final long serialVersionUID = -6320880638344662579L;

    static final int MESSAGE_LENGTH = 36;

    /** Hash of the transaction to which we refer. */
    private Sha256Hash hash;
    /** Which output of that transaction we are talking about. */
    private long index;

    // This is not part of Bitcoin serialization. It's included in Java serialization.
    // It points to the connected transaction.
    Transaction fromTx;

    public TransactionOutPoint(NetworkParameters params, long index, Transaction fromTx) {
        super(params);
        this.index = index;
        if (fromTx != null) {
            this.hash = fromTx.getHash();
            this.fromTx = fromTx;
        } else {
            // This happens when constructing the genesis block.
            hash = Sha256Hash.ZERO_HASH;
        }
        length = MESSAGE_LENGTH;
    }

    public TransactionOutPoint(NetworkParameters params, long index, Sha256Hash hash) {
        super(params);
        this.index = index;
        this.hash = hash;
        length = MESSAGE_LENGTH;
    }

    /**
    /**
     * Deserializes the message. This is usually part of a transaction message.
     */
    public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
        super(params, payload, offset);
    }

    /**
     * Deserializes the message. This is usually part of a transaction message.
     * @param params NetworkParameters object.
     * @param msg Bitcoin protocol formatted byte array containing message content.
     * @param offset The location of the first msg byte within the array.
     * @param protocolVersion Bitcoin protocol version.
     * @param parseLazy Whether to perform a full parse immediately or delay until a read is requested.
     * @param parseRetain Whether to retain the backing byte array for quick reserialization.  
     * If true and the backing byte array is invalidated due to modification of a field then 
     * the cached bytes may be repopulated and retained if the message is serialized again in the future.
     * @param length The length of message if known.  Usually this is provided when deserializing of the wire
     * as the length will be provided as part of the header.  If unknown then set to Message.UNKNOWN_LENGTH
     * @throws ProtocolException
     */
    public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset, Message parent, boolean parseLazy, boolean parseRetain) throws ProtocolException {
        super(params, payload, offset, parent, parseLazy, parseRetain, MESSAGE_LENGTH);
    }

    protected void parseLite() throws ProtocolException {
        length = MESSAGE_LENGTH;
    }

    @Override
    void parse() throws ProtocolException {
        hash = readHash();
        index = readUint32();
    }

    /* (non-Javadoc)
      * @see com.google.bitcoin.core.Message#getMessageSize()
      */
    @Override
    int getMessageSize() {
        return MESSAGE_LENGTH;
    }

    @Override
    protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
        stream.write(Utils.reverseBytes(hash.getBytes()));
        Utils.uint32ToByteStreamLE(index, stream);
    }

    /**
     * An outpoint is a part of a transaction input that points to the output of another transaction. If we have both
     * sides in memory, and they have been linked together, this returns a pointer to the connected output, or null
     * if there is no such connection.
     */
    TransactionOutput getConnectedOutput() {
        if (fromTx == null) return null;
        return fromTx.getOutputs().get((int) index);
    }

    /**
     * Returns the pubkey script from the connected output.
     */
    byte[] getConnectedPubKeyScript() {
        byte[] result = getConnectedOutput().getScriptBytes();
        assert result != null;
        assert result.length > 0;
        return result;
    }

    /**
     * Convenience method to get the connected outputs pubkey hash.
     */
    byte[] getConnectedPubKeyHash() throws ScriptException {
        return getConnectedOutput().getScriptPubKey().getPubKeyHash();
    }

    @Override
    public String toString() {
        return "outpoint " + index + ":" + hash.toString();
    }


    /**
     * @return the hash
     */
    public Sha256Hash getHash() {
        maybeParse();
        return hash;
    }

    /**
     * @param hash the hash to set
     */
    void setHash(Sha256Hash hash) {
        this.hash = hash;
    }

    /**
     * @return the index
     */
    public long getIndex() {
        maybeParse();
        return index;
    }

    /**
     * Ensure object is fully parsed before invoking java serialization.  The backing byte array
     * is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
     * then data will be lost during serialization.
     */
    private void writeObject(ObjectOutputStream out) throws IOException {
        maybeParse();
        out.defaultWriteObject();
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof TransactionOutPoint)) return false;
        TransactionOutPoint o = (TransactionOutPoint) other;
        return o.getIndex() == getIndex() && o.getHash().equals(getHash());
    }

    @Override
    public int hashCode() {
        return getHash().hashCode();
    }
}

@@ -2393,92 +2393,8 @@
 ct.%0A
-     * @param msg Bitcoin protocol formatted byte array containing message content.%0A
     
@@ -2467,64 +2467,8 @@
 ay.%0A
-     * @param protocolVersion Bitcoin protocol version.%0A
     
@@ -2757,16 +2757,16 @@
 d then %0A
+
      * t
@@ -2867,226 +2867,8 @@
 re.%0A
-     * @param length The length of message if known.  Usually this is provided when deserializing of the wire%0A     * as the length will be provided as part of the header.  If unknown then set to Message.UNKNOWN_LENGTH%0A
     
@@ -4784,22 +4784,8 @@
  %22 +
- index + %22:%22 +
  has
@@ -4796,16 +4796,30 @@
 String()
+ + %22:%22 + index
 ;%0A    %7D%0A

Change order of outpoint printing to be more consistent with Bitcoin practice