content: /*
   * CSVeed (https://github.com/42BV/CSVeed)
   *
   * Copyright 2013-2023 CSVeed.
   *
   * All rights reserved. This program and the accompanying materials
   * are made available under the terms of The Apache Software License,
   * Version 2.0 which accompanies this distribution, and is available at
   * https://www.apache.org/licenses/LICENSE-2.0.txt
   */
  package org.csveed.bean;
  
  import java.lang.annotation.Annotation;
  import java.lang.reflect.Field;
  import java.util.Locale;
  
  import org.csveed.annotations.CsvCell;
  import org.csveed.annotations.CsvConverter;
  import org.csveed.annotations.CsvDate;
  import org.csveed.annotations.CsvFile;
  import org.csveed.annotations.CsvHeaderName;
  import org.csveed.annotations.CsvHeaderValue;
  import org.csveed.annotations.CsvIgnore;
  import org.csveed.annotations.CsvLocalizedNumber;
  import org.csveed.common.Column;
  
  /**
   * The Class BeanParser.
   */
  public class BeanParser {
  
      /** The bean instructions. */
      private BeanInstructions beanInstructions;
  
      /** The current column. */
      private Column currentColumn = new Column();
  
      /**
       * Gets the bean instructions.
       *
       * @param beanClass
       *            the bean class
       *
       * @return the bean instructions
       */
      public BeanInstructions getBeanInstructions(Class beanClass) {
  
          this.beanInstructions = new BeanInstructionsImpl(beanClass);
  
          Annotation[] annotations = beanClass.getAnnotations();
          for (Annotation annotation : annotations) {
              if (annotation instanceof CsvFile) {
                  parseCsvFile((CsvFile) annotation);
              }
          }
  
          for (BeanProperty beanProperty : beanInstructions.getProperties()) {
              checkForAnnotations(beanProperty);
          }
  
          return this.beanInstructions;
      }
  
      /**
       * Check for annotations.
       *
       * @param beanProperty
       *            the bean property
       */
      public void checkForAnnotations(BeanProperty beanProperty) {
  
          Field currentField = beanProperty.getField();
          Annotation[] annotations = currentField.getDeclaredAnnotations();
          String propertyName = beanProperty.getPropertyName();
          String columnName = propertyName;
          for (Annotation annotation : annotations) {
              if (annotation instanceof CsvCell) {
                  columnName = parseCsvCell(propertyName, (CsvCell) annotation);
              } else if (annotation instanceof CsvConverter) {
                  parseCsvConverter(propertyName, (CsvConverter) annotation);
              } else if (annotation instanceof CsvDate) {
                  parseCsvDate(propertyName, (CsvDate) annotation);
              } else if (annotation instanceof CsvLocalizedNumber) {
                  parseCsvLocalizedNumber(propertyName, (CsvLocalizedNumber) annotation);
              } else if (annotation instanceof CsvHeaderName) {
                  this.beanInstructions.setHeaderNameToProperty(propertyName);
              } else if (annotation instanceof CsvHeaderValue) {
                  this.beanInstructions.setHeaderValueToProperty(propertyName);
              } else if (annotation instanceof CsvIgnore) {
                  this.beanInstructions.ignoreProperty(propertyName);
                  return;
              }
          }
          this.beanInstructions.mapColumnNameToProperty(columnName, propertyName);
          this.beanInstructions.mapColumnIndexToProperty(currentColumn.getColumnIndex(), propertyName);
          currentColumn = currentColumn.nextColumn();
      }
  
      /**
       * Parses the csv localized number.
       *
       * @param propertyName
       *            the property name
       * @param annotation
       *            the annotation
       */
      private void parseCsvLocalizedNumber(String propertyName, CsvLocalizedNumber annotation) {
          final Locale locale;
          if (annotation.country().isEmpty()) {
              locale = new Locale(annotation.language());
          } else if (annotation.variant().isEmpty()) {
              locale = new Locale(annotation.language(), annotation.country());
          } else {
              locale = new Locale(annotation.language(), annotation.country(), annotation.variant());
          }
          this.beanInstructions.setLocalizedNumber(propertyName, locale);
      }
  
      /**
       * Parses the csv file.
       *
       * @param csvFile
       *            the csv file
       */
      private void parseCsvFile(CsvFile csvFile) {
  
          this.beanInstructions.setEscape(csvFile.escape()).setQuote(csvFile.quote())
                  .setQuotingEnabled(csvFile.quotingEnabled()).setSeparator(csvFile.separator())
                  .setComment(csvFile.comment()).setEndOfLine(csvFile.endOfLine()).setMapper(csvFile.mappingStrategy())
                  .setStartRow(csvFile.startRow()).setUseHeader(csvFile.useHeader())
                  .skipEmptyLines(csvFile.skipEmptyLines()).skipCommentLines(csvFile.skipCommentLines())
                  .setStartIndexDynamicColumns(csvFile.startIndexDynamicColumns());
      }
  
      /**
       * Parses the csv date.
       *
       * @param propertyName
       *            the property name
       * @param csvDate
       *            the csv date
       */
      private void parseCsvDate(String propertyName, CsvDate csvDate) {
          this.beanInstructions.setDate(propertyName, csvDate.format());
      }
  
      /**
       * Parses the csv converter.
       *
       * @param propertyName
       *            the property name
       * @param csvConverter
       *            the csv converter
       */
      private void parseCsvConverter(String propertyName, CsvConverter csvConverter) {
          try {
              this.beanInstructions.setConverter(propertyName,
                      csvConverter.converter().getDeclaredConstructor().newInstance());
          } catch (Exception err) {
              throw new RuntimeException(err);
          }
      }
  
      /**
       * Parses the csv cell.
       *
       * @param propertyName
       *            the property name
       * @param csvCell
       *            the csv cell
       *
       * @return the string
       */
      private String parseCsvCell(String propertyName, CsvCell csvCell) {
          String columnName = csvCell.columnName() == null || csvCell.columnName().isEmpty() ? propertyName
                  : csvCell.columnName();
          this.beanInstructions.setRequired(propertyName, csvCell.required());
          currentColumn = csvCell.columnIndex() != -1 ? new Column(csvCell.columnIndex()) : currentColumn;
          return columnName;
      }
  
  }
  