/**
   * get the first match from the many delimiters give as input
   *
   * @param source
   * @param delimiters
   * @return String
   */
  public static String getFirstMatch(String source, String[] delimiters) {

    Vector<Delimiter> indices = new Vector<Delimiter>();

    for (int i = 0; i < delimiters.length; i++) {
      // we added the indices of all matches to the vector
      indices.add(new Delimiter(i, source.indexOf(delimiters[i]), delimiters[i]));
    }

    Delimiter delimiter = getFirstIndex(indices);
    if (delimiter.getValue() == null) {
      return null;
    }

    return source.substring(0, delimiter.getFoundAt() + 1);
  }
  @Override
  @SuppressWarnings("unchecked")
  protected void setup(Reducer.Context context) throws IOException, InterruptedException {
    this.context = context;
    String settingsStr = context.getConfiguration().get(ParameterProcessing.SETTINGS_STR);
    Settings settings = Settings.loadFromString(settingsStr);
    Settings.setSettings(settings);

    String projectStr = context.getConfiguration().get(ParameterProcessing.PROJECT);
    Project project = Project.loadFromString(projectStr);
    if (project.isEnvHadoop()) {
      String metadataFileContents =
          context.getConfiguration().get(ParameterProcessing.METADATA_FILE);
      new File(ColumnMetadata.metadataNamesFile).getParentFile().mkdirs();
      Files.write(metadataFileContents.getBytes(), new File(ColumnMetadata.metadataNamesFile));
    }
    columnMetadata = new ColumnMetadata();
    String fileSeparatorStr = project.getFieldSeparator();
    char fieldSeparatorChar = Delimiter.getDelim(fileSeparatorStr);
    columnMetadata.setFieldSeparator(String.valueOf(fieldSeparatorChar));
    columnMetadata.setAllMetadata(project.getMetadataCollect());
    // write standard metadata fields
    context.write(null, new Text(columnMetadata.delimiterSeparatedHeaders()));
    zipFileWriter.setup();
    zipFileWriter.openZipForWriting();

    luceneIndex = new LuceneIndex(settings.getLuceneIndexDir(), project.getProjectCode(), null);
    luceneIndex.init();
  }
  /**
   * Gets the first index of a match from the many delimiters given as input Takes many delimiters
   * returns the delimiter that occured first
   *
   * @param collection
   * @return instance of Delimiter class
   */
  private static Delimiter getFirstIndex(Collection<Delimiter> collection) {

    Delimiter delimiter = new Delimiter(-1, 999, null);
    Iterator it = collection.iterator();
    // comparing the matches to see which match occured first
    while (it.hasNext()) {
      Delimiter temp = (Delimiter) it.next();
      int indexOf = temp.foundAt;
      if (indexOf < delimiter.getFoundAt() && indexOf > -1) {
        delimiter = temp;
      }
    }

    if (delimiter == null) {
      return null;
    }
    return delimiter;
  }
  public void run() {
    boolean lookingForSduLength = true;
    int length = 0;
    byte[] sduLengthCandidate = new byte[MAX_SDU_LENGTH_SIZE];
    int sduLengthPosition = 0;
    byte nextByte = 0;
    int value = 0;

    byte[] pdu = null;
    int bytesRead = 0;
    int bytesToRead = 0;
    int offset = 0;

    BufferedInputStream bufInStream = null;
    // byte[] nextBytes = new byte[MAX_SDU_SIZE];
    // int numberOfBytesRead = 0;

    log.debug(
        "Reading socket from remote interface: "
            + socket.getInetAddress().getHostAddress()
            + "\n"
            + "Local port_id: "
            + socket.getLocalPort()
            + "\n"
            + "Remote port_id: "
            + socket.getPort());

    try {
      bufInStream = new BufferedInputStream(socket.getInputStream());
    } catch (Exception ex) {
      log.error("Socket reader stopping. " + ex.getMessage());
      return;
    }

    while (!end) {
      // Delimit the byte array that contains a serialized CDAP message
      try {
        if (lookingForSduLength) {
          value = bufInStream.read();
          if (value == -1) {
            break;
          }

          nextByte = (byte) value;
          sduLengthCandidate[sduLengthPosition] = nextByte;
          length = delimiter.readVarint32(sduLengthCandidate, sduLengthPosition + 1);
          if (length == -2) {
            sduLengthPosition++;
          } else if (length == -1) {
            log.error("Detected SDU with SDU length encoded in too many bytes");
            sduLengthPosition = 0;
          } else if (length == 0) {
            log.debug("Detected 0 length SDU");
            this.process0LengthSDU();
          } else {
            sduLengthPosition = 0;
            if (length > 0) {
              lookingForSduLength = false;
            }
          }
        } else {
          if (pdu == null) {
            pdu = new byte[length];
            bytesToRead = length;
            offset = 0;
          }

          bytesRead = bufInStream.read(pdu, offset, bytesToRead);
          if (bytesRead == -1) {
            break;
          }

          offset = offset + bytesRead;
          bytesToRead = bytesToRead - bytesRead;
          if (bytesToRead == 0) {
            try {
              processPDU(pdu);
            } catch (Exception ex) {
              log.error(
                  "Problems when processing PDU: "
                      + ex.getMessage()
                      + "\n.PDU: "
                      + printBytes(pdu));
            }

            lookingForSduLength = true;
            pdu = null;
          }
        }
      } catch (Exception ex) {
        end = true;
      }
    }

    try {
      log.debug("EOF detected, closing the socket");
      socket.close();
      log.debug("Socket closed");
    } catch (IOException ex) {
      log.error("Exception closing the socket: " + ex.getMessage());
    }

    log.info("The remote endpoint of socket " + socket.getPort() + " has disconnected");
    socketDisconnected();
  }