/*
 * Copyright (C) 2010 Teleal GmbH, Switzerland
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 3 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.teleal.cling.test.model;

import org.teleal.cling.model.types.Base64Datatype;
import org.teleal.cling.model.types.Datatype;
import org.teleal.cling.model.types.DateTimeDatatype;
import org.teleal.cling.model.types.IntegerDatatype;
import org.teleal.cling.model.types.InvalidValueException;
import org.teleal.cling.model.types.TimeDatatype;
import org.teleal.cling.model.types.UnsignedIntegerFourBytesDatatype;
import org.teleal.cling.model.types.UnsignedIntegerOneByteDatatype;
import org.teleal.cling.model.types.UnsignedIntegerTwoBytesDatatype;
import org.teleal.cling.model.types.csv.CSVBoolean;
import org.teleal.cling.model.types.csv.CSVString;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import static org.testng.Assert.assertEquals;


public class DatatypesTest {

    @Test
    public void upperLowerCase() {
        // Broken devices do this
        assertEquals(Datatype.Builtin.getByDescriptorName("String"), Datatype.Builtin.STRING);
        assertEquals(Datatype.Builtin.getByDescriptorName("strinG"), Datatype.Builtin.STRING);
        assertEquals(Datatype.Builtin.getByDescriptorName("STRING"), Datatype.Builtin.STRING);
        assertEquals(Datatype.Builtin.getByDescriptorName("string"), Datatype.Builtin.STRING);
    }

    @Test
    public void validUnsignedIntegers() {

        UnsignedIntegerOneByteDatatype typeOne = new UnsignedIntegerOneByteDatatype();
        assertEquals(typeOne.fromString("123").getValue(),  Long.valueOf(123l));

        UnsignedIntegerTwoBytesDatatype typeTwo = new UnsignedIntegerTwoBytesDatatype();
        assertEquals(typeTwo.fromString("257").getValue(),  Long.valueOf(257l));

        UnsignedIntegerFourBytesDatatype typeFour = new UnsignedIntegerFourBytesDatatype();
        assertEquals(typeFour.fromString("65536").getValue(),  Long.valueOf(65536l));
        assertEquals(typeFour.fromString("4294967295").getValue(),  Long.valueOf(4294967295l));

        // Well, no need to write another test for that
        assertEquals(typeFour.fromString("4294967295").increment(true).getValue(),  Long.valueOf(1));

    }

    @Test(expectedExceptions = InvalidValueException.class)
    public void invalidUnsignedIntegersOne() {
        UnsignedIntegerOneByteDatatype typeOne = new UnsignedIntegerOneByteDatatype();
        typeOne.fromString("256");
    }

    @Test(expectedExceptions = InvalidValueException.class)
    public void invalidUnsignedIntegersTwo() {
        UnsignedIntegerTwoBytesDatatype typeTwo = new UnsignedIntegerTwoBytesDatatype();
        typeTwo.fromString("65536");
    }

    @Test
    public void signedIntegers() {

        IntegerDatatype type = new IntegerDatatype(1);
        assert type.isValid(123);
        assert type.isValid(-124);
        assert type.fromString("123") == 123;
        assert type.fromString("-124") == -124;
        assert !type.isValid(256);

        type = new IntegerDatatype(2);
        assert type.isValid(257);
        assert type.isValid(-257);
        assert type.fromString("257") == 257;
        assert type.fromString("-257") == -257;
        assert !type.isValid(32768);

    }

    @Test
    public void dateAndTime() {
        DateTimeDatatype type = (DateTimeDatatype) Datatype.Builtin.DATE.getDatatype();
        assert type.fromString("2009-06-26").getTime() == 1245967200000l;
        assert type.getString(new Date(109, 5, 26)).equals("2009-06-26");

        type = (DateTimeDatatype) Datatype.Builtin.DATETIME.getDatatype();
        assert type.fromString("2009-06-26").getTime() == 1245967200000l;
        assert type.fromString("2009-06-26T12:13:14").getTime() == 1246011194000l;
        assert type.getString(new Date(109, 5, 26, 12, 13, 14)).equals("2009-06-26T12:13:14");

        // I refuse to use the timezone API in Java. So no tests, good luck! Send a Thank You letter to the IBM clowns.
    }

    @Test
    public void time() {
        TimeDatatype type = (TimeDatatype) Datatype.Builtin.TIME.getDatatype();

        Date expected = new Date(0); // Epoch
        expected.setHours(13); // Whatever...
        expected.setMinutes(13);
        expected.setSeconds(14);
        assert type.fromString("12:13:14") == expected.getTime();
        assert type.getString(43994000l).equals("12:13:14");

    }

    @Test
    public void base64() {
        Base64Datatype type = (Base64Datatype) Datatype.Builtin.BIN_BASE64.getDatatype();
        assert Arrays.equals(type.fromString("a1b2"), new Byte[]{ 107, 86, -10} );
        assert type.getString(new Byte[]{ 107, 86, -10}).equals("a1b2");
    }

    @Test
    public void simpleCSV() {
        List<String> csv = new CSVString("foo,bar,baz");
        assert csv.size() == 3;
        assert csv.get(0).equals("foo");
        assert csv.get(1).equals("bar");
        assert csv.get(2).equals("baz");
        assert csv.toString().equals("foo,bar,baz");

        csv = new CSVString("f\\\\oo,b\\,ar,b\\\\az");
        assert csv.size() == 3;
        assertEquals(csv.get(0), "f\\oo");
        assertEquals(csv.get(1), "b,ar");
        assertEquals(csv.get(2), "b\\az");

        List<Boolean> csvBoolean = new CSVBoolean("1,1,0");
        assert csvBoolean.size() == 3;
        assertEquals(csvBoolean.get(0), new Boolean(true));
        assertEquals(csvBoolean.get(1), new Boolean(true));
        assertEquals(csvBoolean.get(2), new Boolean(false));
        assertEquals(csvBoolean.toString(), "1,1,0");
    }


}
