// © 2016 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html#License
/*
******************************************************************************
* Copyright (C) 2007-2011, International Business Machines Corporation and   *
* others. All Rights Reserved.                                               *
******************************************************************************
*/

// Copyright 2007 Google Inc.  All Rights Reserved.

package com.ibm.icu.dev.test.duration;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.impl.duration.BasicPeriodFormatterService;
import com.ibm.icu.impl.duration.Period;
import com.ibm.icu.impl.duration.PeriodBuilder;
import com.ibm.icu.impl.duration.PeriodBuilderFactory;
import com.ibm.icu.impl.duration.TimeUnit;
import com.ibm.icu.impl.duration.TimeUnitConstants;

@RunWith(JUnit4.class)
public class PeriodBuilderFactoryTest extends TestFmwk implements TimeUnitConstants {
    private PeriodBuilderFactory pbf;

    private static final long[] approxDurations = {
      36525L*24*60*60*10, 3045*24*60*60*10L, 7*24*60*60*1000L, 24*60*60*1000L,
      60*60*1000L, 60*1000L, 1000L, 1L
    };

    @Test
    public void testSetAvailableUnitRange() {
        // sanity check, make sure by default all units are set
        pbf = BasicPeriodFormatterService.getInstance().newPeriodBuilderFactory();
        pbf.setLocale("en"); // in en locale, all units always available
        PeriodBuilder b = pbf.getSingleUnitBuilder();
        for (TimeUnit unit = YEAR; unit != null; unit = unit.smaller()) {
            Period p = b.create((long)(approxDurations[unit.ordinal()]*2.5));
            assertTrue(null, p.isSet(unit));
        }

        pbf.setAvailableUnitRange(MINUTE, MONTH);
        // units that are not available are never set
        b = pbf.getSingleUnitBuilder();
        for (TimeUnit unit = YEAR; unit != null; unit = unit.smaller()) {
            Period p = b.create((long)(approxDurations[unit.ordinal()]*2.5));
            assertEquals(null, p.isSet(unit), unit.ordinal() >= MONTH.ordinal() && unit.ordinal() <= MINUTE.ordinal());
        }

        // fixed unit builder returns null when unit is not available
        for (TimeUnit unit = YEAR; unit != null; unit = unit.smaller()) {
            b = pbf.getFixedUnitBuilder(unit);
            if (unit.ordinal() >= MONTH.ordinal() && unit.ordinal() <= MINUTE.ordinal()) {
                assertNotNull(null, b);
            } else {
                assertNull(null, b);
            }
        }

        // can't set empty range
        try {
            pbf.setAvailableUnitRange(MONTH, MINUTE);
            fail("set empty range");
        } catch (IllegalArgumentException e) {
            // pass
        }
    }

    @Test
    public void testSetUnitIsAvailable() {
        pbf = BasicPeriodFormatterService.getInstance().newPeriodBuilderFactory();
        pbf.setAvailableUnitRange(MONTH, MONTH);
        assertNotNull(null, pbf.getSingleUnitBuilder());
        assertNotNull(null, pbf.getOneOrTwoUnitBuilder());
        assertNotNull(null, pbf.getMultiUnitBuilder(2));

        // now no units are available, make sure we can't generate a builder
        pbf.setUnitIsAvailable(MONTH, false);
        assertNull(null, pbf.getSingleUnitBuilder());
        assertNull(null, pbf.getOneOrTwoUnitBuilder());
        assertNull(null, pbf.getMultiUnitBuilder(2));

        pbf.setUnitIsAvailable(DAY, true);
        assertNotNull(null, pbf.getSingleUnitBuilder());
        assertNotNull(null, pbf.getOneOrTwoUnitBuilder());
        assertNotNull(null, pbf.getMultiUnitBuilder(2));
    }

    @Test
    public void testBuilderFactoryPeriodConstruction() {
        // see ticket #8307
        pbf = BasicPeriodFormatterService.getInstance().newPeriodBuilderFactory();
        pbf.setAvailableUnitRange(SECOND, DAY);
        PeriodBuilder pb = pbf.getOneOrTwoUnitBuilder();
        long H1M35S30M100 = 100 + 1000 * (30 + 35 * 60 + 1 * 60 * 60);
        Period p = pb.create(H1M35S30M100);
        assertEquals("hours", 1.0f, p.getCount(HOUR));
        assertEquals("minutes", 35.501f, p.getCount(MINUTE));
        assertFalse("seconds", p.isSet(SECOND));

        pb = pbf.getMultiUnitBuilder(3);
        p = pb.create(H1M35S30M100);
        assertEquals("hours", 1.0f, p.getCount(HOUR));
        assertEquals("minutes", 35f, p.getCount(MINUTE));
        assertEquals("seconds", 30.1f, p.getCount(SECOND));
        assertFalse("millis", p.isSet(MILLISECOND));
    }
}
