/*
 * 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 org.apache.jmeter.functions;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.jmeter.util.JMeterUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * File data container for CSV (and similar delimited) files Data is accessible
 * via row and column number
 *
 */
public class FileRowColContainer {

    private static final Logger log = LoggerFactory.getLogger(FileRowColContainer.class);

    private final List<List<String>> fileData; // Lines in the file, split into columns

    private final String fileName; // name of the file

    public static final String DELIMITER
        = JMeterUtils.getPropDefault("csvread.delimiter",  // $NON-NLS-1$
                ","); // $NON-NLS-1$

    /** Keeping track of which row is next to be read. */
    private int nextRow;

    /** Delimiter for this file */
    private final String delimiter;

    public FileRowColContainer(String file, String delim) throws IOException, FileNotFoundException {
        log.debug("FRCC(" + file + "," + delim + ")");
        fileName = file;
        delimiter = delim;
        nextRow = 0;
        fileData = new ArrayList<>();
        load();
    }

    public FileRowColContainer(String file) throws IOException, FileNotFoundException {
        log.debug("FRCC(" + file + ")[" + DELIMITER + "]");
        fileName = file;
        delimiter = DELIMITER;
        nextRow = 0;
        fileData = new ArrayList<>();
        load();
    }

    private void load() throws IOException, FileNotFoundException {
        try ( FileReader fis = new FileReader(fileName);
                BufferedReader myBread = new BufferedReader(fis);) {
            String line = myBread.readLine();
            /*
             * N.B. Stop reading the file if we get a blank line: This allows
             * for trailing comments in the file
             */
            while (line != null && line.length() > 0) {
                fileData.add(splitLine(line, delimiter));
                line = myBread.readLine();
            }
        } catch (IOException e) {
            fileData.clear();
            log.warn(e.toString());
            throw e;
        }
    }

    /**
     * Get the string for the column from the current row
     *
     * @param row
     *            row number (from 0)
     * @param col
     *            column number (from 0)
     * @return the string (empty if out of bounds)
     * @throws IndexOutOfBoundsException
     *             if the column number is out of bounds
     */
    public String getColumn(int row, int col) throws IndexOutOfBoundsException {
        String colData;
        colData = fileData.get(row).get(col);
        log.debug(fileName + "(" + row + "," + col + "): " + colData);
        return colData;
    }

    /**
     * Returns the next row to the caller, and updates it, allowing for wrap
     * round
     *
     * @return the first free (unread) row
     *
     */
    public int nextRow() {
        int row = nextRow;
        nextRow++;
        if (nextRow >= fileData.size())// 0-based
        {
            nextRow = 0;
        }
        log.debug("Row: " + row);
        return row;
    }

    /**
     * Splits the line according to the specified delimiter
     *
     * @return a List of Strings containing one element for each value in
     *         the line
     */
    private static List<String> splitLine(String theLine, String delim) {
        List<String> result = new ArrayList<>();
        StringTokenizer tokener = new StringTokenizer(theLine, delim, true);
        /*
         * the beginning of the line is a "delimiter" so that ,a,b,c returns ""
         * "a" "b" "c"
         */
        boolean lastWasDelim = true;
        while (tokener.hasMoreTokens()) {
            String token = tokener.nextToken();
            if (token.equals(delim)) {
                if (lastWasDelim) {
                    // two delimiters in a row; add an empty String
                    result.add("");
                }
                lastWasDelim = true;
            } else {
                lastWasDelim = false;
                result.add(token);
            }
        }
        if (lastWasDelim) // Catch the trailing delimiter
        {
            result.add(""); // $NON-NLS-1$
        }
        return result;
    }

    /**
     * @return the file name for this class
     */
    public String getFileName() {
        return fileName;
    }

    /**
     * @return Returns the delimiter.
     */
    final String getDelimiter() {
        return delimiter;
    }

    // Added to support external testing
    public int getSize(){
        return fileData.size();
    }
}

@@ -858,32 +858,53 @@
 BufferedReader;%0A
+import java.io.File;%0A
 import java.io.F
@@ -940,26 +940,27 @@
 java.io.
-FileReader
+IOException
 ;%0Aimport
@@ -961,38 +961,71 @@
 import java.
+n
 io.
-IOException
+charset.Charset;%0Aimport java.nio.file.Files
 ;%0Aimport jav
@@ -2032,36 +2032,28 @@
 RCC(
-%22 + file + %22,%22 + delim + %22)%22
+%7B%7D,%7B%7D)%22, file, delim
 );%0A 
@@ -2301,25 +2301,23 @@
 RCC(
-%22 + file + %22)%5B%22 +
+%7B%7D)%5B%7B%7D%5D%22, file,
  DEL
@@ -2326,14 +2326,8 @@
 ITER
- + %22%5D%22
 );%0A 
@@ -2548,117 +2548,153 @@
 ry (
- FileReader fis = new FileReader(fileName);%0A                BufferedReader myBread = new BufferedReader(fis);
+BufferedReader myBread = %0A                Files.newBufferedReader(new File(fileName).toPath(), %0A                        Charset.defaultCharset())
 ) %7B%0A
@@ -3724,50 +3724,43 @@
 bug(
-fileName + %22(%22 + row + %22,%22 + col + %22): %22 +
+%22%7B%7D(%7B%7D,%7B%7D):%7B%7D%22, fileName, row, col,
  col
@@ -4072,16 +4072,18 @@
 .size())
+ %7B
 // 0-bas
@@ -4085,26 +4085,16 @@
 0-based%0A
-        %7B%0A
         
@@ -4148,11 +4148,12 @@
 ow: 
-%22 +
+%7B%7D%22,
  row

Fix default charset use reported by antonio and some other code smells