/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2004 Gregor Koukkoullis ( phex <at> kouk <dot> de )
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
package phex.http;

import java.util.*;

import phex.utils.Logger;


public class Range
{
    public static final int NOT_SET = -1;

    private long suffixLength;

    /**
     * The start offset of the download.
     */
    private long startOffset;

    /**
     * The end offset of the download (inclusive)
     */
    private long endOffset;

    /**
     * If this is a range for a specific candidate, it relates solely to the
     * candidate's quality. ie: all ranges in the rangeset will have the same value.
     *
     * If this is a range for aggregrated rangesets, it will be the sum of the above
     * rangeset ratings for the matching range.
     */
    private IRating rating;

    /**
     * Creates a HTTPRange object for suffix lengths like '-500' which requests
     * the last 500 bytes of a file.
     * @param suffixLength the suffix length.
     */
    public Range( long suffixLength)
    {
        this.startOffset = NOT_SET;
        this.endOffset = NOT_SET;
        this.suffixLength = suffixLength;
        this.rating = null;
    }

    /**
     * Creates a HTTPRange object with a start and end offset. The end offset
     * can be NOT_SET to form request like '100-'
     * @param startOffset the start offset.
     * @param endOffset the end offset.
     */
    public Range( long startOffset, long endOffset )
    {
        this( startOffset, endOffset, null );
    }

    /**
     * Creates a HTTPRange object with a start and end offset. The end offset
     * can be NOT_SET to form request like '100-'
     * @param startOffset the start offset.
     * @param endOffset the end offset.
     * @param rating the rating
     */
    public Range( long startOffset, long endOffset , IRating rating )
    {
        this.startOffset = startOffset;
        this.endOffset = endOffset;
        this.suffixLength = NOT_SET;
        this.rating = rating;
    }

    /**
     * Updates a HTTPRange object for suffix lengths like '-500' which requests
     * the last 500 bytes of a file.
     * @param suffixLength the suffix length.
     */
    public void update( long suffix )
    {
        this.startOffset = NOT_SET;
        this.endOffset = NOT_SET;
        this.suffixLength = suffix;
    }

    /**
     * Updats a HTTPRange object with a start and end offset. The end offset
     * can be NOT_SET to form request like '100-'
     * @param startOffset the start offset.
     * @param endOffset the end offset.
     */
    public void update( long startOffset, long endOffset )
    {
        this.startOffset = startOffset;
        this.endOffset = endOffset;
        this.suffixLength = NOT_SET;
    }

    public String toString()
    {
        StringBuffer buf = new StringBuffer("[Range: " + startOffset + "-" + endOffset + " ("
                            + rating + ")]");
        return buf.toString();
    }

    /**
     * Returns the start offset of the download.
     * @param fileSize the file size is needed in case of suffix byte range
     * requests.
     * @return
     */
    public long getStartOffset( long fileSize )
    {
        if ( suffixLength == NOT_SET )
        {// we have absolute ranges.
            return startOffset;
        }
        else
        {
            return fileSize - suffixLength;
        }
    }

    /**
     * Returns the end offset (inclusive) of the download.
     * @param fileSize the file size is needed in case of suffix byte range
     * requests.
     * @return
     */
    public long getEndOffset( long fileSize )
    {
        if ( suffixLength == NOT_SET && endOffset != NOT_SET )
        {// we have absolut ranges.
            return Math.min( endOffset, fileSize );
        }
        else
        {
            return fileSize;
        }
    }

    public void accumulate( IRating rating )
    {
        this.rating.accumulate(rating);
    }

    public void setRating( IRating rating )
    {
        if (this.rating == rating) return;
        Logger.logMessage ( Logger.INFO, Logger.DOWNLOAD,
                "Changing rating from " + this.rating + " to " + rating + " for range: " + startOffset + " - " + endOffset);
        this.rating = rating;
    }

    public IRating getRating()
    {
        return rating;
    }

    public boolean isRangeSatisfiable( Range range, long fileSize )
    {
        // a------a
        // r--r
        //   r--r
        //     r--r
        //          r--r
        long rangeStart = range.getStartOffset( fileSize );
        if (   getStartOffset( fileSize ) <= rangeStart
            && rangeStart <= getEndOffset( fileSize ) )
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public String buildHTTPRangeString()
    {
        if ( suffixLength == NOT_SET )
        {
            return String.valueOf( startOffset ) + '-' + String.valueOf(
                endOffset );
        }
        else
        {
            return '-' + String.valueOf( suffixLength );
        }
    }
}

