package htsjdk.beta.io.bundle;

import htsjdk.HtsjdkTest;
import htsjdk.io.HtsPath;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

public class BundleResourceTest extends HtsjdkTest {

    @DataProvider(name = "inputOutputTestData")
    public Object[][] getInputOutputTestData() {
        return new Object[][] {
            // bundle resource, isInput, isOutput
            {BundleResourceTestData.readsWithFormat, true, true},
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                true,
                false
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                false,
                true
            },
        };
    }

    @Test(dataProvider = "inputOutputTestData")
    public void testIsInputOutput(
            final BundleResource resource, final boolean expectedIsInput, final boolean expectedIsOutput) {
        Assert.assertEquals(resource.hasInputType(), expectedIsInput);
        Assert.assertEquals(resource.hasOutputType(), expectedIsOutput);
    }

    @DataProvider(name = "resourceEqualityTestData")
    public Object[][] getResourceEqualityTestData() {
        return new Object[][] {

            // equal
            {BundleResourceTestData.readsWithFormat, BundleResourceTestData.readsWithFormat, true},
            {
                // force two separate IOPath instances for which == is false
                new IOPathResource(
                        BundleResourceTestData.READS_FILE,
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                new IOPathResource(
                        new HtsPath(BundleResourceTestData.READS_FILE.getRawInputString()),
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                true
            },
            {BundleResourceTestData.readsNoFormat, BundleResourceTestData.readsNoFormat, true},
            {
                new IOPathResource(BundleResourceTestData.READS_FILE, BundleResourceType.CT_ALIGNED_READS),
                new IOPathResource(BundleResourceTestData.READS_FILE, BundleResourceType.CT_ALIGNED_READS),
                true
            },
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                true
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                true
            },

            // not equal
            {
                new IOPathResource(BundleResourceTestData.READS_FILE, BundleResourceType.CT_ALIGNED_READS),
                new IOPathResource(BundleResourceTestData.READS_FILE, "NOTREADS"),
                false
            },
            {BundleResourceTestData.readsWithFormat, BundleResourceTestData.readsNoFormat, false},
            {BundleResourceTestData.indexWithFormat, BundleResourceTestData.readsNoFormat, false},

            // not equal inputstreams
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream,
                        "differentDisplayName",
                        BundleResourceType.CT_ALIGNED_READS),
                false
            },
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                false
            },
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_CRAM),
                false
            },
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_VARIANT_CONTEXTS),
                false
            },

            // not equal outputstreams
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream,
                        "differentDisplayName",
                        BundleResourceType.CT_ALIGNED_READS),
                false
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                false
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_CRAM),
                false
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_VARIANT_CONTEXTS),
                false
            },
        };
    }

    @Test(dataProvider = "resourceEqualityTestData")
    public void testInputResourceEquality(
            final BundleResource inputResource1, final BundleResource inputResource2, final boolean expectedEquals) {
        Assert.assertEquals(inputResource1.equals(inputResource2), expectedEquals);
        Assert.assertEquals(inputResource2.equals(inputResource1), expectedEquals);
    }

    @DataProvider(name = "toStringTestData")
    public Object[][] getToStringTestData() {
        return new Object[][] {
            {BundleResourceTestData.readsWithFormat, "IOPathResource (file://myreads.bam): ALIGNED_READS/BAM"},
            {BundleResourceTestData.readsNoFormat, "IOPathResource (file://myreads.bam): ALIGNED_READS/NONE"},
            {BundleResourceTestData.indexNoFormat, "IOPathResource (file://myreads.bai): READS_INDEX/NONE"},
            {BundleResourceTestData.indexWithFormat, "IOPathResource (file://myreads.bai): READS_INDEX/BAI"},
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                "InputStreamResource (displayName): ALIGNED_READS/NONE"
            },
            {
                new InputStreamResource(
                        BundleResourceTestData.fakeInputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                "InputStreamResource (displayName): ALIGNED_READS/BAM"
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream, "displayName", BundleResourceType.CT_ALIGNED_READS),
                "OutputStreamResource (displayName): ALIGNED_READS/NONE"
            },
            {
                new OutputStreamResource(
                        BundleResourceTestData.fakeOutputStream,
                        "displayName",
                        BundleResourceType.CT_ALIGNED_READS,
                        BundleResourceType.FMT_READS_BAM),
                "OutputStreamResource (displayName): ALIGNED_READS/BAM"
            },
        };
    }

    @Test(dataProvider = "toStringTestData")
    public void testToString(final BundleResource resource, final String expectedString) {
        Assert.assertTrue(resource.toString().contains(expectedString));
    }
}
