/*
 * Copyright 2015 Objectos, Fábrica de Software LTDA.
 *
 * Licensed 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 br.com.objectos.csv;

import static br.com.objectos.csv.annotation.LocalDatePattern.DD_MM_YYYY;
import static br.com.objectos.testing.MoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;

import java.time.LocalDate;
import java.util.Optional;

import com.google.common.collect.ImmutableList;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

/**
 * @author marcio.endo@objectos.com.br (Marcio Endo)
 */
public class ColumnTest {

  @DataProvider
  public Object[][] getProvider() {
    return new Object[][] {
        { DD_MM_YYYY, "01/02/2015", LocalDate.of(2015, 2, 1), null },
        { DD_MM_YYYY, "  01/02/2015  ", LocalDate.of(2015, 2, 1), null },
        { DD_MM_YYYY, "01xpto", null, "Could not convert '01xpto' to type 'java.time.LocalDate'" },

        { StringConverter.INSTANCE, "abc", "abc", null },
        { StringConverter.INSTANCE, "abc ", "abc ", null },
        { StringConverter.INSTANCE, "", null, "Field is mandatory but found ''" },
    };
  }

  @DataProvider
  public Object[][] getIfPresentProvider() {
    return new Object[][] {
        { DD_MM_YYYY, "01/02/2015", LocalDate.of(2015, 2, 1), null },
        { DD_MM_YYYY, "  01/02/2015  ", LocalDate.of(2015, 2, 1), null },
        { DD_MM_YYYY, "01xpto", null, "Could not convert '01xpto' to type 'java.time.LocalDate'" },
        { DD_MM_YYYY, "", null, null },
        { DD_MM_YYYY, "       ", null, null },

        { StringConverter.INSTANCE, "abc", "abc", null },
        { StringConverter.INSTANCE, "abc ", "abc ", null },
        { StringConverter.INSTANCE, "", null, null },
    };
  }

  @DataProvider
  public Object[][] intValueProvider() {
    return new Object[][] {
        { "123", 123, null },
        { "000", 0, null },
        { "023", 23, null },
        { "abc", 0, "Could not convert 'abc' to type 'int'" },
        { "", 0, "Field is mandatory but found ''" }
    };
  }

  @DataProvider
  public Object[][] longValueProvider() {
    return new Object[][] {
        { "123", 123l, null },
        { "000", 0l, null },
        { "023", 23l, null },
        { "abc", 0l, "Could not convert 'abc' to type 'long'" },
        { "", 0l, "Field is mandatory but found ''" }
    };
  }

  @Test(dataProvider = "getProvider")
  public void get(CsvConverter<Object> converter, String text, Object value, String exception) {
    Line line = line(text);
    AbstractColumn<String> column = column(line);
    Object res = column.get(converter);
    assertThat(res, equalTo(value));
    assertParseException(line, exception);
  }

  @Test(dataProvider = "getIfPresentProvider")
  public void get_if_present(CsvConverter<Object> converter, String text, Object value, String exception) {
    Line line = line(text);
    AbstractColumn<String> column = column(line);
    Optional<Object> res = column.getIfPresent(converter);
    assertThat(res, equalTo(Optional.ofNullable(value)));
    assertParseException(line, exception);
  }

  @Test(dataProvider = "intValueProvider")
  public void int_value(String text, int value, String exception) {
    Line line = line(text);
    AbstractColumn<String> column = column(line);
    int res = column.intValue();
    assertThat(res, equalTo(value));
    assertParseException(line, exception);
  }

  @Test(dataProvider = "longValueProvider")
  public void long_value(String text, long value, String exception) {
    Line line = line(text);
    AbstractColumn<String> column = column(line);
    long res = column.longValue();
    assertThat(res, equalTo(value));
    assertParseException(line, exception);
  }

  private void assertParseException(Line line, String exception) {
    Optional<ParseException> lastException = line.firstException();
    assertThat(lastException.isPresent(), equalTo(exception != null));

    if (exception != null) {
      assertThat(lastException.get().getMessage(), equalTo("012345::   fakeField::" + exception));
    }
  }

  private AbstractColumn<String> column(Line line) {
    return line.at(0, "fakeField");
  }

  private Line line(String text) {
    return new Line(12345, ImmutableList.of(text));
  }

}