package com.limegroup.gnutella.bugs;

import java.io.IOException;
import java.util.StringTokenizer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.limegroup.gnutella.ErrorService;
import com.limegroup.gnutella.util.URLDecoder;

/**
 * Handles the client-side representation of an 
 * <tt>RemoteServletInfo</tt> object, which reconstructs the data
 * for the update created on the server side.  This parses that 
 * information so BugManager can store it.
 */
//2345678|012345678|012345678|012345678|012345678|012345678|012345678|012345678|
public final class RemoteClientInfo extends RemoteAbstractInfo {
    
    private static final Log LOG = LogFactory.getLog(RemoteClientInfo.class);
    
    /**
     * The amount of time to wait should the server be down.
     */
    private static final long FAILURE_TIME = 60 * 60 * 1000; // 1 hour

    /**
     * The next time this particular bug can be sent.
     */
	private String _nextThisBugTime;
	
	/**
	 * The next time any bug can be sent.
	 */
	private String _nextAnyBugTime;
    
	/**
	 * Adds multiple key/value pairs based on the information
	 * in infoLine.  infoLine is expected to be in the form of
	 * 'key=URLEncoder.encode(value)&key2=URLEncode.encode(value2)'
     * 
     * This method is used on the client side to reconstruct the 
     * <tt>RemoteServletInfo</tt> object originally created on the server.
	 *
	 * @param infoLine string containing all name/value pairs.
	 */
	final void addRemoteInfo(final String infoLine) {
	    if(LOG.isDebugEnabled())
	        LOG.debug("Adding info: " + infoLine);
	        
        StringTokenizer st = new StringTokenizer(infoLine, "=&");
        if( st.countTokens() % 2 != 0 )
            return; //invalid response.
        while(st.hasMoreTokens()) {
            handleKeyValuePair(st.nextToken(), st.nextToken());
        }
    }

	/**
	 * Handles a single key/value pair, storing the values in this
	 * object.
     * 
     * This method is used on the client side to reconstruct the 
     * <tt>RemoteUpdateInfo</tt> object originally created on the server.
	 *
	 * @param line a string representing one key-value pair of
	 *             information from the server's response
	 */
    private final void handleKeyValuePair(final String k, final String v) {
        String value = "";
        try {
            value = URLDecoder.decode(v);
        } catch (IOException e) {
            // Should not happen from our own bug server.
            ErrorService.error(e);
            return;
        }
        if(k.equalsIgnoreCase(NEXT_THIS_BUG_TIME))
            _nextThisBugTime = value;
        else if (k.equalsIgnoreCase(NEXT_ANY_BUG_TIME))
            _nextAnyBugTime = value;
        // else something random -- don't worry about it
	}
	
	/**
	 * Marks the next bug time & next any bug time for the appropriate values
	 * given a connection failure.
	 */
	final void connectFailed() {
	    _nextThisBugTime = "" + FAILURE_TIME;
	    _nextAnyBugTime = "" + FAILURE_TIME;
    }
	
	/**
	 * Returns the next time, as a long, that this bug is allowed to be sent.
	 * The return value is in milliseconds, and should be added to
	 * System.currentTimeMillis() to retrieve the exact millisecond at which
	 * the next bug should be sent.
	 */
	long getNextThisBugTime() {
	    if( _nextThisBugTime == null)
	        return 0;
	    else {
	        long nextTime;
	        try {
	            nextTime = Long.parseLong(_nextThisBugTime);
	        } catch(NumberFormatException nfe) {
	            nextTime = 0;
	        }
	        return nextTime;
	    }
	}
	
	/**
	 * Returns the next time, as a long, that any bug is allowed to be sent.
	 * The return value is in milliseconds, and should be added to
	 * System.currentTimeMillis() to retrieve the exact millisecond at which
	 * the next bug should be sent.
	 */
	long getNextAnyBugTime() {
	    if( _nextAnyBugTime == null)
	        return 0;
	    else {
	        long nextTime;
	        try {
	            nextTime = Long.parseLong(_nextAnyBugTime);
	        } catch(NumberFormatException nfe) {
	            nextTime = 0;
	        }
	        return nextTime;
	    }	    
	}
}
