/*! ******************************************************************************
 *
 * Pentaho Data Integration
 *
 * Copyright (C) 2018 by Hitachi Vantara : http://www.pentaho.com
 *
 *******************************************************************************
 *
 * 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 org.pentaho.di.ui.trans.step.common;

import org.apache.commons.lang.StringUtils;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.util.Utils;
import org.pentaho.di.i18n.BaseMessages;
import org.pentaho.di.trans.TransMeta;
import org.pentaho.di.trans.steps.common.CsvInputAwareMeta;
import org.pentaho.di.trans.steps.csvinput.CsvInput;
import org.pentaho.di.trans.steps.fileinput.text.EncodingType;
import org.pentaho.di.trans.steps.fileinput.text.TextFileInputUtils;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DecimalFormat;

/**
 * A common interface for all step dialogs aware of the csv input format, such as {@link
 * org.pentaho.di.ui.trans.steps.csvinput.CsvInputDialog} and
 * {@link org.pentaho.di.ui.trans.steps.fileinput.text.TextFileInputDialog}
 */
public interface CsvInputAwareStepDialog {

  /**
   * @See {@link GetFieldsCapableStepDialog#getFieldNames(org.pentaho.di.trans.step.BaseStepMeta)}
   */
  default String[] getFieldNames( final CsvInputAwareMeta meta ) {
    String[] fieldNames = new String[] {};
    final InputStream inputStream = getInputStream( meta );
    final InputStreamReader reader = getReader( meta, inputStream );
    try {
      fieldNames = getFieldNamesImpl( reader, meta );
    } catch ( final KettleException e ) {
      logError( BaseMessages.getString( "Dialog.ErrorGettingFields.Message" ), e );
    } finally {
      try {
        inputStream.close();
      } catch ( Exception e ) {
        // Ignore close errors
      }
    }
    return fieldNames;
  }

  default String[] getFieldNamesImpl( final InputStreamReader reader, final CsvInputAwareMeta meta )
    throws KettleException {

    String[] fieldNames = new String[] {};
    if ( reader == null || meta == null ) {
      logError( BaseMessages.getString( "Dialog.ErrorGettingFields.Message" ) );
      return fieldNames;
    }
    final String delimiter = getTransMeta().environmentSubstitute( meta.getDelimiter() );
    final String enclosure = getTransMeta().environmentSubstitute( meta.getEncoding() );

    final EncodingType encodingType = EncodingType.guessEncodingType( reader.getEncoding() );

    // Read a line of data to determine the number of rows...
    final String line = TextFileInputUtils.getLine( getLogChannel(), reader, encodingType, meta.getFileFormatTypeNr(),
      new StringBuilder( 1000 ) );
    if ( !StringUtils.isBlank( line ) ) {
      fieldNames = CsvInput.guessStringsFromLine( getLogChannel(), line, delimiter, enclosure,
        meta.getEscapeCharacter() );
    }
    if ( Utils.isEmpty( fieldNames ) ) {
      logError( BaseMessages.getString( "Dialog.ErrorGettingFields.Message" ) );
      return fieldNames;
    }

    // Massage field names
    for ( int i = 0; i < fieldNames.length; i++ ) {
      fieldNames[ i ] = Const.trim( fieldNames[ i ] );
      if ( !meta.hasHeader() ) {
        final DecimalFormat df = new DecimalFormat( "000" );
        fieldNames[ i ] = "Field_" + df.format( i );
      } else if ( !Utils.isEmpty( meta.getEnclosure() ) && fieldNames[ i ].startsWith( meta.getEnclosure() )
        && fieldNames[ i ].endsWith( meta.getEnclosure() ) && fieldNames[ i ].length() > 1 ) {
        fieldNames[ i ] = fieldNames[ i ].substring( 1, fieldNames[ i ].length() - 1 );
      }
      // trim again, now that the enclosure characters have been removed
      fieldNames[ i ] = Const.trim( fieldNames[ i ] );
      fieldNames[ i ] = massageFieldName( fieldNames[ i ] );
    }
    return fieldNames;
  }

  /**
   * Custom handling of each field can be implemented here.
   */
  default String massageFieldName( final String fieldName ) {
    return fieldName;
  }

  /**
   * Returns the {@link InputStream} corresponding to the csv file, or null if the file cannot be read.
   *
   * @return the {@link InputStream} corresponding to the csv file, or null if the file cannot be read
   */
  InputStream getInputStream( final CsvInputAwareMeta meta );

  /**
   * Returns the {@link InputStreamReader} corresponding to the csv file, or null if the file cannot be read.
   *
   * @return the {@link InputStreamReader} corresponding to the csv file, or null if the file cannot be read
   */
  default InputStreamReader getReader( final CsvInputAwareMeta meta, final InputStream inputStream ) {
    InputStreamReader reader = null;
    try {
      String realEncoding = getTransMeta().environmentSubstitute( meta.getEncoding() );
      if ( Utils.isEmpty( realEncoding ) ) {
        reader = new InputStreamReader( inputStream );
      } else {
        reader = new InputStreamReader( inputStream, realEncoding );
      }
    } catch ( final Exception e ) {
      logError( BaseMessages.getString( "Dialog.ErrorGettingFileDesc.DialogMessage" ), e );
    }
    return reader;
  }

  /**
   * @See {@link GetFieldsCapableStepDialog#loadFieldsImpl(BaseStepMeta, int)}
   */
  default String loadFieldsImpl( final CsvInputAwareMeta meta, final int samples ) {

    InputStream inputStream = getInputStream( meta );
    try {
      final InputStreamReader reader = getReader( meta, inputStream );
      final CsvInputAwareImportProgressDialog pd = getCsvImportProgressDialog( meta, samples, reader );
      String message = pd.open( false );
      return message;
    } finally {
      try {
        inputStream.close();
      } catch ( Exception e ) {
        // Ignore close errors
      }
    }
  }

  CsvInputAwareImportProgressDialog getCsvImportProgressDialog(
    final CsvInputAwareMeta meta, final int samples, final InputStreamReader reader );

  default void logError( final String message, final Exception exception ) {
    getLogChannel().logError( message, exception );
  }

  default void logError( final String message ) {
    getLogChannel().logError( message );
  }

  LogChannel getLogChannel();

  TransMeta getTransMeta();
}

@@ -3062,29 +3062,30 @@
  meta.getEnc
-oding
+losure
 () );%0A%0A    f

Fix for encoding in get fields