/*
 * JBoss, Home of Professional Open Source.
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 * 
 * This library 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 2.1 of the License, or (at your option) any later version.
 * 
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 * Modified by
 * @author  Data Virtuality GmbH
 * @date    $Date$
 *  
 */
/*
 * EXTENSION
 * ISSUE: DVCORE-2521
 * FIXED BY: Roman Pedchenko
 * DATE: 2014-12-05
 * ADOPTED FROM: TEIID-2153, 2171, 2359, 2149, 2358, 2410, 2271, 2467, 2429, 2363, 2160, 2461, 2797, 2326, 1557
 * END EXTENSION
 */
package org.teiid.common.buffer.impl;

import static org.junit.jupiter.api.Assertions.*;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Date;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.junit.jupiter.api.Test;
import org.teiid.core.types.BinaryType;
import org.teiid.core.types.DataTypeManager;

public class TestSizeUtility {
	
	private static class SomeObject implements Serializable {
		private String state;
		public SomeObject(String state) {
			this.state = state;
		}
	}

    public void helpTestGetStaticSize(Object obj, long expectedSize) {
        helpTestGetSize(obj, expectedSize);
    }

    public void helpTestGetSize(Object obj, long expectedSize) {  
        long actualSize = new SizeUtility(null).getSize(obj, DataTypeManager.determineDataTypeClass(obj), true, false);
        assertEquals(expectedSize, actualSize, "Got unexpected size: "); //$NON-NLS-1$
    }

    @Test public void testGetSizeChar() {
        helpTestGetStaticSize(new Character('a'), 10);
    }

    @Test public void testGetSizeBoolean() {
        helpTestGetStaticSize(Boolean.TRUE, 1);
    }

    @Test public void testGetSizeByte() {
        helpTestGetStaticSize(new Byte((byte)0), 1);
    }

    @Test public void testGetSizeShort() {
        helpTestGetStaticSize(new Short((short)0), 10);
    }

    @Test public void testGetSizeInteger() {
        helpTestGetStaticSize(new Integer(0), 12);
    }

    @Test public void testGetSizeLong() {
        helpTestGetStaticSize(new Long(0l), 16);
    }
    
    @Test public void testGetSizeFloat() {
        helpTestGetStaticSize(new Float(0), 12);
    }

    @Test public void testGetSizeDouble() {
        helpTestGetStaticSize(new Double(0), 16);
    }

    @Test public void testGetSizeTimestamp() {
        helpTestGetStaticSize(new Timestamp(12301803), 28);
    }

    @Test public void testGetSizeDate() {
        helpTestGetStaticSize(new Date(12301803), 28);
    }

    @Test public void testGetSizeTime() {
        helpTestGetStaticSize(new Time(12301803), 28);
    }

    @Test public void testGetSizeEmptyString() {
        helpTestGetSize("", 40); //$NON-NLS-1$
    }

    @Test public void testGetSizeShortString() {
        helpTestGetSize("abcdefghij", 64); //$NON-NLS-1$
    }
    
    @Test public void testGetSizeObject() {
        helpTestGetStaticSize(new SomeObject(null), 16);
        helpTestGetStaticSize(new SomeObject("Hello world"), 56);  //$NON-NLS-1$
        Object obj = new SomeObject(null);
        //still biased toward the initial estimate
        assertEquals(160, new SizeUtility(null).getSize(obj, DataTypeManager.determineDataTypeClass(obj), false, false));
    }

    @Test public void testGetSizeRow1() {
        List<Object> row = new ArrayList<Object>(1);
        row.add(new Integer(0));
        helpTestGetStaticSize(row, 36);
    }
    
    @Test public void testGetSizeRow2() {
        List<Object> row = new ArrayList<Object>(4);
        row.add(new Integer(0));
        row.add(new Integer(101));
        row.add(Boolean.TRUE);
        row.add(new Double(1091203.00));
        helpTestGetStaticSize(row, 89);
    }
    
    @Test public void testGetSizeRows1() {
        helpTestGetStaticSize(new List[] { }, 16);
    }

    @Test public void testGetSizeRows2() {
        List<Object> row1 = new ArrayList<Object>(2);
        row1.add(new Integer(0));
        row1.add(new Integer(100));

        List<Object> row2 = new ArrayList<Object>(2);
        row2.add(new Integer(0));
        row2.add(new Integer(100));

        helpTestGetStaticSize(new List[] { row1, row2 }, 144);
    }
   
    @Test public void testGetSizeBigInteger() {
        BigInteger b = BigInteger.ONE;
                
        helpTestGetStaticSize(b, 48);
    }    
    
    @Test public void testGetSizeBigDecimal() {
        BigDecimal bd = new BigDecimal("1.0"); //$NON-NLS-1$
        
        helpTestGetStaticSize(bd, 96);
    }
    
    @Test public void testGetSizeByteArray() {
        byte[] bytes = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        helpTestGetSize(new BinaryType(bytes), 32);
    }
    
    @Test public void testResultSet() {
        List<?>[] expected = new List[] { 
                Arrays.asList(new Object[] { "a",   new Integer(0),     Boolean.FALSE,  new Double(2.0),    "a",    new Integer(0) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(0),     Boolean.FALSE,  new Double(2.0),    "a",    new Integer(0) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(0),     Boolean.FALSE,  new Double(2.0),    "a",    new Integer(0) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(0),     Boolean.FALSE,  new Double(2.0),    "a",    new Integer(0) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(0),     Boolean.FALSE,  new Double(2.0),    "a",    new Integer(3) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(0),     Boolean.FALSE,  new Double(2.0),    "a",    new Integer(3) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(3),     Boolean.TRUE,   new Double(7.0),    "a",    new Integer(0) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(3),     Boolean.TRUE,   new Double(7.0),    "a",    new Integer(0) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "a",   new Integer(3),     Boolean.TRUE,   new Double(7.0),    "a",    new Integer(3) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "b",   new Integer(2),     Boolean.FALSE,  new Double(0.0),    "b",    new Integer(2) }), //$NON-NLS-1$ //$NON-NLS-2$
                Arrays.asList(new Object[] { "c",   new Integer(1),     Boolean.FALSE,  new Double(0.0),    "c",    new Integer(1) })  //$NON-NLS-1$ //$NON-NLS-2$
           };     
        
        Class<?>[] types = {DataTypeManager.DefaultDataClasses.STRING,
        		DataTypeManager.DefaultDataClasses.INTEGER,
        		DataTypeManager.DefaultDataClasses.BOOLEAN,
        		DataTypeManager.DefaultDataClasses.DOUBLE,
        		DataTypeManager.DefaultDataClasses.STRING,
        		DataTypeManager.DefaultDataClasses.INTEGER};

        long actualSize = new SizeUtility(types).getBatchSize(false, Arrays.asList(expected));
        assertEquals(2667, actualSize, "Got unexpected size: "); //$NON-NLS-1$
    }
    
}