package edu.hawaii.ics415.problem2.tabulardata.util;

import java.util.StringTokenizer;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.File;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.util.ArrayList;
import java.util.Stack;
import java.util.Iterator;

/**
 * Provides the way to retrieve the data from a tabular based data. After the
 * data is retrieved, the data is stored in the ArrayList container
 *
 * @author   Takuya Yamashita
 */
public class DataContainer {

  /**
   * Provides the relative file path
   */
  private String relativeFileDir = "/WEB-INF/db/";
  /**
   * Provides the file name after instantiation
   */
  private String fileName = "";
  /**
   * Provides the delimiter which is used in the tabular based file.
   */
  private String delimiter = "";
  /**
   * Provides the file object of the fileName
   */
  private File file;
  /**
   * Provides the collection of the data upside down container.
   */
  private ArrayList dataUpSideDownContainer;
  /**
   * Provides the collection of the data container.
   */
  private ArrayList dataContainer;
  /**
   * Provides the ServletCotext object to retrieve the realpath.
   */
  ServletContext context;

  /**
   * Constructor for the DataContainer object. Instantilate the ArrayList
   * object.
   *
   * @param context  Description of the Parameter
   */
  public DataContainer(ServletContext context) {
    this.context = context;
    dataContainer = new ArrayList();
    dataUpSideDownContainer = new ArrayList();
  }

  /**
   * Initiallized the object with file name and delimiter to read a tabular
   * based file
   *
   * @param fileName         Description of the Parameter
   * @param delimiter        Description of the Parameter
   * @exception IOException  Description of the Exception
   */
  public void initDataContainer(String fileName, String delimiter) throws IOException {
    this.clear();
    setFileName(fileName);
    setDelimiter(delimiter);
    restoreFile();
  }

  /**
   * Clears the containers
   */
  private void clear() {
    dataContainer = new ArrayList();
    dataUpSideDownContainer = new ArrayList();
  }


  /**
   * Sets the fileName to be retrieved from a tabular based file
   *
   * @param fileName  The new fileName value
   */
  private void setFileName(String fileName) {
    this.fileName = fileName;
  }

  /**
   * Sets the delimiter which is used to separate each data in a tabular based
   * file
   *
   * @param delimiter  The new delimiter value
   */
  private void setDelimiter(String delimiter) {
    this.delimiter = delimiter;
  }

  /**
   * Restores a data from the tabular based file, and inserts all the data into
   * container object.
   *
   * @exception IOException  Thrown if the IOExcepion occurs.
   */
  private void restoreFile() throws IOException {
    String fileDir = this.context.getRealPath(relativeFileDir);

    this.file = new File(fileDir + "/" + this.fileName);
    try {
      FileInputStream fileStream = new FileInputStream(this.file);
      InputStreamReader streamReader = new InputStreamReader(fileStream);
      BufferedReader buffer = new BufferedReader(streamReader);
      // reads the line
      String line = buffer.readLine();

      // do while loop unless the line encounters the EOF.
      while (line != null) {
        StringTokenizer tokenizer = new StringTokenizer(line, delimiter);
        String[] data = new String[tokenizer.countTokens()];
        int i = 0;
        int j = 0;

        while (tokenizer.hasMoreElements()) {
          data[i++] = tokenizer.nextToken();
        }
        dataUpSideDownContainer.add(j++, data);
        line = buffer.readLine();
      }

      int k = 0;
      int index = dataUpSideDownContainer.size() - 1;

      while (dataUpSideDownContainer.size() > 0) {
        dataContainer.add(k++, dataUpSideDownContainer.remove(index--));
      }
    }
    catch (IOException e) {
      throw e;
    }
  }

  /**
   * Provides the Iterator object to iterate the container.
   *
   * @return   Iterator object which gives the String array.
   */
  public Iterator iterator() {
    return dataContainer.iterator();
  }

  /**
   * Provides the size of the container.
   *
   * @return   An integer value of the size of the container.
   */
  public int size() {
    return dataContainer.size();
  }
}