/*
 *  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
 * 
 *  --- CVS Information ---
 *  $Id: TestSWDownloadFile.java,v 1.5 2004/07/28 14:30:19 nxf Exp $
 */
package phex.test;

import junit.framework.*;
import phex.download.swarming.*;
import phex.common.*;
import phex.http.HTTPRangeSet;

/**
 * 
 * @author gkoukkoullis
 */
public class TestSWDownloadFile extends TestCase
{
    protected void setUp()
    {
    }

    protected void tearDown()
    {
    }
    
    public void testSplitting()
        throws Throwable
    {
        SWDownloadFile file = new SWDownloadFile( "test", "test", 1000000, null );
        SWDownloadSegment segment = file.getSegment( 0 );
        SWDownloadSegment newSegment = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "splitDownloadSegment1",
            new Object[]{segment, new Long(0), new Long(500000)},
            new Class[]{SWDownloadSegment.class, long.class, long.class} );
        Assert.assertEquals( segment, newSegment );
        Assert.assertEquals( 0, newSegment.getStartOffset(), 0 );
        Assert.assertEquals( 500000, newSegment.getTransferDataSize() );
        segment = file.getSegment( 1 );
        Assert.assertEquals( 500000, segment.getStartOffset() );
        Assert.assertEquals( 500000, segment.getTransferDataSize() );
        
           
        file = new SWDownloadFile( "test", "test", 1000000, null );
        segment = file.getSegment( 0 );
        newSegment = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "splitDownloadSegment1",
            new Object[]{segment, new Long(250000), new Long(500000)},
            new Class[]{SWDownloadSegment.class, long.class, long.class} );
            
        Assert.assertEquals( 250000, newSegment.getStartOffset() );
        Assert.assertEquals( 500000, newSegment.getTransferDataSize()  );
        Assert.assertEquals( 0, segment.getStartOffset(), 0 );
        Assert.assertEquals( 250000, segment.getTransferDataSize() );    
        segment = file.getSegment( 2 );
        Assert.assertEquals( 750000, segment.getStartOffset() );
        Assert.assertEquals( 250000, segment.getTransferDataSize() );
        
        file = new SWDownloadFile( "test", "test", 1000000, null );
        segment = file.getSegment( 0 );
        newSegment = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "splitDownloadSegment1",
            new Object[]{segment, new Long(500000), new Long(500000)},
            new Class[]{SWDownloadSegment.class, long.class, long.class} );
        
        Assert.assertEquals( 500000, newSegment.getStartOffset() );
        Assert.assertEquals( 500000, newSegment.getTransferDataSize() );
        Assert.assertEquals( 0, segment.getStartOffset() );
        Assert.assertEquals( 500000, segment.getTransferDataSize() );
        
        
        file = new SWDownloadFile( "test", "test", 100, null );
        segment = file.getSegment( 0 );
        try
        {
            newSegment = (SWDownloadSegment)AccessUtils.invokeMethod(
                file, "splitDownloadSegment1",
                new Object[]{segment, new Long(0), new Long(Cfg.INITIAL_SEGMENT_SIZE)},
                new Class[]{SWDownloadSegment.class, long.class, long.class} );
            Assert.fail();
        }
        catch ( IndexOutOfBoundsException exp )
        {
        }
    }
    
    public void testAllocateSegment()
        throws Throwable
    {
        SWDownloadFile file = new SWDownloadFile( "test", "test", 1000000, null );
        SWDownloadWorker worker = new SWDownloadWorker();
        SWDownloadSegment newSegment1 = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "allocateSegment",
            new Object[]{worker},
            new Class[]{SWDownloadWorker.class} );
        Assert.assertEquals( 0, newSegment1.getStartOffset() );
        Assert.assertEquals( Cfg.INITIAL_SEGMENT_SIZE,
            newSegment1.getTransferDataSize() );
            
        SWDownloadSegment newSegment2 = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "allocateSegment",
            new Object[]{worker},
            new Class[]{SWDownloadWorker.class} );
        Assert.assertEquals( Cfg.INITIAL_SEGMENT_SIZE,
            newSegment2.getTransferDataSize() );
            
        SWDownloadSegment newSegment3 = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "allocateSegment",
            new Object[]{worker},
            new Class[]{SWDownloadWorker.class} );
        Assert.assertEquals( Cfg.INITIAL_SEGMENT_SIZE,
            newSegment3.getTransferDataSize() );
            
        file.releaseDownloadSegment( newSegment2 );
        SWDownloadSegment newSegment4 = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "allocateSegment",
            new Object[]{worker},
            new Class[]{SWDownloadWorker.class} );
        Assert.assertEquals( Cfg.INITIAL_SEGMENT_SIZE,
            newSegment1.getTransferDataSize() );
        Assert.assertEquals( newSegment2, newSegment4 );
    }
    
    public void testAllocateSegmentWithRangeSet()
        throws Throwable
    {
        HTTPRangeSet rangeSet = new HTTPRangeSet( 0, 500000 );
        SWDownloadFile file = new SWDownloadFile( "test", "test", 1000000, null );
        SWDownloadWorker worker = new SWDownloadWorker();
        SWDownloadSegment newSegment1 = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "allocateSegmentForRangeSet",
            new Object[]{worker, rangeSet},
            new Class[]{SWDownloadWorker.class, HTTPRangeSet.class} );
        Assert.assertEquals( 0, newSegment1.getStartOffset() );
        Assert.assertEquals( Cfg.INITIAL_SEGMENT_SIZE,
            newSegment1.getTransferDataSize() );
            
        file = new SWDownloadFile( "test", "test", 1000000, null );
        SWDownloadSegment segment = file.getSegment( 0 );
        SWDownloadSegment newSegment = (SWDownloadSegment)AccessUtils.invokeMethod(
                file, "splitDownloadSegment1",
                new Object[]{segment, new Long(500000), new Long(1000000-500000)},
                new Class[]{SWDownloadSegment.class, long.class, long.class} );
        newSegment.setAllocatedByWorker( worker );
        newSegment1 = (SWDownloadSegment)AccessUtils.invokeMethod(
            file, "allocateSegmentForRangeSet",
            new Object[]{worker, rangeSet},
            new Class[]{SWDownloadWorker.class, HTTPRangeSet.class} );
        Assert.assertEquals( 0, newSegment1.getStartOffset() );
        Assert.assertEquals( Cfg.INITIAL_SEGMENT_SIZE,
            newSegment1.getTransferDataSize() );
    }
    
    public void testMergeSegments()
        throws Throwable
    {
        // test all empty segments
        SWDownloadFile file = createFileWithSplittedSegments();
        completlyMerge(file);
        assertEquals( 1, file.getSegmentCount() );
        assertEquals( 0, file.getSegment(0).getStartOffset() );
        assertEquals( 100, file.getSegment(0).getEndOffset() );
        
        // test all filled segments.
        file = createFileWithSplittedSegments();
        for ( int i = 0; i < file.getSegmentCount(); i++ )
        {
            file.getSegment( i ).setTransferredDataSize( 10 );
        }
        completlyMerge(file);
        assertEquals( 1, file.getSegmentCount() );
        assertEquals( 0, file.getSegment(0).getStartOffset() );
        assertEquals( 100, file.getSegment(0).getEndOffset() );
        
        // test 2 filled, two empty segments.
        file = createFileWithSplittedSegments();
        file.getSegment( 0 ).setTransferredDataSize( 10 );
        file.getSegment( 1 ).setTransferredDataSize( 10 );
        // -- 2empty
        file.getSegment( 4 ).setTransferredDataSize( 10 );
        file.getSegment( 5 ).setTransferredDataSize( 10 );
        // -- 2empty
        file.getSegment( 8 ).setTransferredDataSize( 10 );
        file.getSegment( 9 ).setTransferredDataSize( 10 );

        completlyMerge(file);
        assertEquals( 5, file.getSegmentCount() );
        assertEquals( 0, file.getSegment(0).getStartOffset() );
        assertEquals( 20, file.getSegment(0).getEndOffset() );
        assertEquals( 20, file.getSegment(1).getStartOffset() );
        assertEquals( 40, file.getSegment(1).getEndOffset() );
        
        // test partial segments.
        file = createFileWithSplittedSegments();
        for ( int i = 0; i < file.getSegmentCount(); i++ )
        {// all segments are half filled
            file.getSegment( i ).setTransferredDataSize( 5 );
        }

        completlyMerge(file);
        assertEquals( 20, file.getSegmentCount() );
        assertEquals( 0, file.getSegment(0).getStartOffset() );
        assertEquals( 5, file.getSegment(0).getEndOffset() );
        assertEquals( 5, file.getSegment(0).getNextDownloadSegment().getStartOffset() );
        assertEquals( 10, file.getSegment(0).getNextDownloadSegment().getEndOffset() );
        
        // test full - partial segments.
        file = createFileWithSplittedSegments();
        for ( int i = 0; i < file.getSegmentCount(); i+=2 )
        {// all segments are half filled
            file.getSegment( i ).setTransferredDataSize( 10 );
        }
        for ( int i = 1; i < file.getSegmentCount(); i+=2 )
        {// all segments are half filled
            file.getSegment( i ).setTransferredDataSize( 5 );
        }

        completlyMerge(file);
        assertEquals( 10, file.getSegmentCount() );
        assertEquals( 0, file.getSegment(0).getStartOffset() );
        assertEquals( 15, file.getSegment(0).getEndOffset() );
        assertEquals( 15, file.getSegment(0).getNextDownloadSegment().getStartOffset() );
        assertEquals( 20, file.getSegment(0).getNextDownloadSegment().getEndOffset() );
        
        //ArrayList segmentList = (ArrayList)AccessUtils.getFieldValue( file, "downloadSegments" );
        //assertEquals( 1, segmentList.size() );
    }

    private void completlyMerge(SWDownloadFile file)
    {
        int lastCount;
        do
        {
            lastCount = file.getSegmentCount();
            file.mergeSegments();
            System.out.println( file.getSegmentCount() );
        }
        while ( lastCount != file.getSegmentCount());
    }
    
    private SWDownloadFile createFileWithSplittedSegments()
        throws Throwable
    {
        SWDownloadFile file = new SWDownloadFile( "test", "test", 100, null );
        assertEquals( 1, file.getSegmentCount() );
        
        SWDownloadSegment segment = file.getSegment( 0 );
        
        // create 10 equal size segments...
        for ( int i = 0; i < 5; i ++ )
        {
            System.out.println( "Acting on " + segment );
            AccessUtils.invokeMethod(
                file, "splitDownloadSegment1",
                new Object[]{segment, new Long(10), new Long(10)},
                new Class[]{SWDownloadSegment.class, long.class, long.class} );
            segment = segment.getNextDownloadSegment().getNextDownloadSegment();
        }
        assertEquals( 10, file.getSegmentCount() );
        return file;
    }
}
