package net.i2p.router.networkdb.kademlia;

import java.util.Date;

import net.i2p.data.Hash;
import net.i2p.data.RouterInfo;
import net.i2p.data.i2np.DatabaseSearchReplyMessage;
import net.i2p.data.i2np.DatabaseStoreMessage;
import net.i2p.data.i2np.I2NPMessage;
import net.i2p.router.JobImpl;
import net.i2p.router.ReplyJob;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;

/**
 * Called after a match to a db search is found
 *
 */
class SearchUpdateReplyFoundJob extends JobImpl implements ReplyJob {
    private Log _log;
    private I2NPMessage _message;
    private Hash _peer;
    private SearchState _state;
    private KademliaNetworkDatabaseFacade _facade;
    private SearchJob _job;
    
    public SearchUpdateReplyFoundJob(RouterContext context, RouterInfo peer, 
                                     SearchState state, KademliaNetworkDatabaseFacade facade, 
                                     SearchJob job) {
        super(context);
        _log = context.logManager().getLog(SearchUpdateReplyFoundJob.class);
        _peer = peer.getIdentity().getHash();
        _state = state;
        _facade = facade;
        _job = job;
    }
    
    public String getName() { return "Update Reply Found for Kademlia Search"; }
    public void runJob() {
        I2NPMessage message = _message;
        if (_log.shouldLog(Log.INFO))
            _log.info(getJobId() + ": Reply from " + _peer.toBase64() 
                      + " with message " + message.getClass().getName());
        
        if (message instanceof DatabaseStoreMessage) {
            long timeToReply = _state.dataFound(_peer);
            
            DatabaseStoreMessage msg = (DatabaseStoreMessage)message;
            if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_LEASESET) {
                try {
                    _facade.store(msg.getKey(), msg.getLeaseSet());
                    getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
                } catch (IllegalArgumentException iae) {
                    if (_log.shouldLog(Log.ERROR))
                        _log.warn("Peer " + _peer + " sent us an invalid leaseSet: " + iae.getMessage());
                    getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
                }
            } else if (msg.getValueType() == DatabaseStoreMessage.KEY_TYPE_ROUTERINFO) {
                if (_log.shouldLog(Log.INFO))
                    _log.info(getJobId() + ": dbStore received on search containing router " 
                              + msg.getKey() + " with publishDate of " 
                              + new Date(msg.getRouterInfo().getPublished()));
                try {
                    _facade.store(msg.getKey(), msg.getRouterInfo());
                    getContext().profileManager().dbLookupSuccessful(_peer, timeToReply);
                } catch (IllegalArgumentException iae) {
                    if (_log.shouldLog(Log.ERROR))
                        _log.warn("Peer " + _peer + " sent us an invalid routerInfo: " + iae.getMessage());
                    getContext().profileManager().dbLookupReply(_peer, 0, 0, 1, 0, timeToReply);
                }
            } else {
                if (_log.shouldLog(Log.ERROR))
                    _log.error(getJobId() + ": Unknown db store type?!@ " + msg.getValueType());
            }
        } else if (message instanceof DatabaseSearchReplyMessage) {
            _job.replyFound((DatabaseSearchReplyMessage)message, _peer);
        } else {
            if (_log.shouldLog(Log.ERROR))
                _log.error(getJobId() + ": WTF, reply job matched a strange message: " + message);
            return;
        }
        
        _job.searchNext();
    }
    
    public void setMessage(I2NPMessage message) { _message = message; }
}
