/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datastax.driver.core;

import static org.assertj.core.api.Assertions.assertThat;

import com.datastax.driver.core.utils.Bytes;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * This class provides sample values for each primitive data type.
 *
 * <p>These values have no particular meaning, the goal is just to have an instance that can be used
 * in automated tests.
 */
public class PrimitiveTypeSamples {

  static Map<DataType, Object> samples(ProtocolVersion protocolVersion) {
    try {
      final Collection<DataType> primitiveTypes = TestUtils.allPrimitiveTypes(protocolVersion);
      ImmutableMap<DataType, Object> data =
          ImmutableMap.<DataType, Object>builder()
              .put(DataType.ascii(), "ascii")
              .put(DataType.bigint(), Long.MAX_VALUE)
              .put(DataType.blob(), Bytes.fromHexString("0xCAFE"))
              .put(DataType.cboolean(), Boolean.TRUE)
              .put(DataType.decimal(), new BigDecimal("12.3E+7"))
              .put(DataType.cdouble(), Double.MAX_VALUE)
              .put(DataType.cfloat(), Float.MAX_VALUE)
              .put(DataType.inet(), InetAddress.getByName("123.123.123.123"))
              .put(DataType.tinyint(), Byte.MAX_VALUE)
              .put(DataType.smallint(), Short.MAX_VALUE)
              .put(DataType.cint(), Integer.MAX_VALUE)
              .put(DataType.duration(), Duration.from("PT30H20M"))
              .put(DataType.text(), "text")
              .put(DataType.timestamp(), new Date(872835240000L))
              .put(DataType.date(), LocalDate.fromDaysSinceEpoch(16071))
              .put(DataType.time(), 54012123450000L)
              .put(DataType.timeuuid(), UUID.fromString("FE2B4360-28C6-11E2-81C1-0800200C9A66"))
              .put(DataType.uuid(), UUID.fromString("067e6162-3b6f-4ae2-a171-2470b63dff00"))
              .put(DataType.varint(), new BigInteger(Integer.toString(Integer.MAX_VALUE) + "000"))
              .build();

      // Only include data types that support the desired protocol version.
      Map<DataType, Object> result =
          Maps.filterKeys(
              data,
              new Predicate<DataType>() {
                @Override
                public boolean apply(DataType input) {
                  return primitiveTypes.contains(input);
                }
              });

      // Check that we cover all types (except counter and duration)
      // Duration is excluded because it can't be used in collections and udts.   It is tested
      // separately
      // in DurationIntegrationTest.
      List<DataType> tmp = Lists.newArrayList(primitiveTypes);
      tmp.removeAll(result.keySet());

      List<DataType> expectedFilteredTypes = Lists.newArrayList(DataType.counter());

      assertThat(tmp)
          .as("new datatype not covered in test")
          .containsOnlyElementsOf(expectedFilteredTypes);

      return result;
    } catch (UnknownHostException e) {
      throw new AssertionError(e);
    }
  }
}
