/*
 * Copyright 2009 Thomas Bocek
 *
 * 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 net.tomp2p.dht;

import java.util.Map;

import net.tomp2p.dht.StorageLayer.PutStatus;
import net.tomp2p.futures.FutureDone;
import net.tomp2p.peers.Number640;
import net.tomp2p.peers.PeerAddress;
import net.tomp2p.rpc.DigestResult;
import net.tomp2p.storage.Data;

/**
 * The future object for put() operations including routing.
 * 
 * @author Thomas Bocek
 */
public class FutureGet extends FutureDHT<FutureGet> {
    // The minimum number of expected results. This is also used for put()
    // operations to decide if a future failed or not.
    private final int min;

    // Since we receive multiple results, we have an evaluation scheme to
    // simplify the result
    private final EvaluatingSchemeDHT evaluationScheme;

    // Storage of results
    private Map<PeerAddress, Map<Number640, Data>> rawData;
    // Digest results
    private Map<PeerAddress, DigestResult> rawDigest;
    // here we store also failed attempts
    private Map<PeerAddress, Byte> rawStatus;

    // Flag indicating if the minimum operations for put have been reached.
    private boolean minReached;
    
    private boolean convertToHeapBuffer = true;

    /**
     * Default constructor.
     */
    public FutureGet(final DHTBuilder<?> builder) {
        this(builder, 0, new VotingSchemeDHT());
    }

    /**
     * Creates a new DHT future object that keeps track of the status of the DHT operations.
     * 
     * @param min
     *            The minimum of expected results
     * @param evaluationScheme
     *            The scheme to evaluate results from multiple peers
     */
    public FutureGet(final DHTBuilder<?> builder, final int min, final EvaluatingSchemeDHT evaluationScheme) {
        super(builder);
        this.min = min;
        this.evaluationScheme = evaluationScheme;
        self(this);
    }

    /**
     * Finish the future and set the keys and data that have been received.
     * 
     * @param rawData
     *            The keys and data that have been received with information from which peer it has been received.
     * @param rawDigest
     *            The hashes of the content stored with information from which peer it has been received.
     * @param rawStatus 
     * @param futuresCompleted 
     */
    public void receivedData(final Map<PeerAddress, Map<Number640, Data>> rawData, final Map<PeerAddress, DigestResult> rawDigest, Map<PeerAddress, Byte> rawStatus, FutureDone<Void> futuresCompleted) {
        synchronized (lock) {
            if (!completedAndNotify()) {
                return;
            }
            this.rawData = rawData;
            
            if(convertToHeapBuffer) {
            	for(Map<Number640, Data> map:rawData.values()) {
            		for(Data data:map.values()) {
            			data.convertToHeapBuffer();
            		}
            	}
            	for(DigestResult digest:rawDigest.values()) {
            		if(digest.dataMap() != null) {
            			for(Data data:digest.dataMap().values()) {
            				data.convertToHeapBuffer();
            			}
            		}
            	}
            }
            
            this.rawDigest = rawDigest;
            this.rawStatus = rawStatus;
            this.futuresCompleted = futuresCompleted;
            final int size = rawStatus.size();
            this.minReached = size >= min;
            this.type = size > 0 ? FutureType.OK : FutureType.FAILED;
            this.reason = size > 0 ? "Minimum number of answers reached" : "Expected >0 answers, but got " + size;
        }
        notifyListeners();
    }

    /**
     * Returns the raw data from the get operation.
     * 
     * @return The raw data and the information which peer has been contacted
     */
    public Map<PeerAddress, Map<Number640, Data>> rawData() {
        synchronized (lock) {
            return rawData;
        }
    }

    /**
     * @return The raw digest information with hashes of the content and the information which peer has been contacted
     */
    public Map<PeerAddress, DigestResult> rawDigest() {
        synchronized (lock) {
            return rawDigest;
        }
    }
    
    /**
     * @return The raw digest information with hashes of the content and the information which peer has been contacted
     */
    public Map<PeerAddress, Byte> rawStatus() {
        synchronized (lock) {
            return rawStatus;
        }
    }

    /**
     * Return the digest information from the get() after evaluation. The evaluation gets rid of the PeerAddress
     * information, by either a majority vote or cumulation.
     * 
     * @return The evaluated digest information that have been received.
     */
    public DigestResult digest() {
        synchronized (lock) {
            return evaluationScheme.evaluate5(rawDigest);
        }
    }

    /**
     * Return the data from get() after evaluation. The evaluation gets rid of the PeerAddress information, by either a
     * majority vote or cumulation.
     * 
     * @return The evaluated data that have been received.
     */
    public Map<Number640, Data> dataMap() {
        synchronized (lock) {
            return evaluationScheme.evaluate2(rawData);
        }
    }
    
    /**
     * @return The first data object from get() after evaluation.
     */
    public Data data() {
        Map<Number640, Data> dataMap = dataMap();
        if (dataMap.size() == 0) {
            return null;
        }
        return dataMap.values().iterator().next();
    }

    /**
     * Checks if the minimum of expected results have been reached. This flag is also used for determining the success
     * or failure of this future for put and send_direct.
     * 
     * @return True, if expected minimum results have been reached.
     */
    public boolean isMinReached() {
        synchronized (lock) {
            return minReached;
        }
    }

	public boolean isEmpty() {
		synchronized (lock) {
			for(byte b:rawStatus.values()) {
				if (b == PutStatus.OK.ordinal()) {
					return false;
				}
			}
			return true;
		} 
    }
}

@@ -887,18 +887,18 @@
 ect for 
-pu
+ge
 t() oper

Update class comment text