/*
 * 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.daffodil.processors.input

import junit.framework.Assert._
import scala.util.parsing.combinator._
import java.io.StringReader
import org.junit.Test
import org.apache.daffodil.exceptions.Assert

class TestRegex extends RegexParsers {

  /**
   * Scala combinator parsers can do longest match via the '|||' combinator
   * Let's be sure we get longest match.
   */

  override def skipWhitespace = skipWS
  var skipWS = false // assign this to turn on/off whitespace skipping.

  @Test def testEscapeRemoval_Blocks = {
    // Assumptions:
    //	1. Delimiter and padding removed
    //	2. Valid start-end blocks were already removed
    //	3. Because valid start-end blocks were already removed
    //		an escapeEscape character preceding the escapeBlockEnd
    //		must occur at the end of the string input.
    //
    // Step 1:
    //	Remove escapeEscapeCharacters preceding escapeBlockEnd
    // val blockStart = "T"
    val blockEnd = "N"
    val escapeEscape = "E"
    val rRemoveEscape = """(%1$s$)|(%1$s(?=%2$s))""" // Replace escape at end of line OR replace escapeEscape preceding escapeBlockEnd
    val removeEscapes = rRemoveEscape.format(escapeEscape, blockEnd)

    def test(regex: String, input: String) = {
      input.replaceAll(regex, "")
    }

    assertEquals("abc", test(removeEscapes, "abc"))
    assertEquals("abc", test(removeEscapes, "abcE"))
    assertEquals("abcE", test(removeEscapes, "abcEE"))
    assertEquals("TabcN", test(removeEscapes, "TabcENE"))
    assertEquals("TabEc", test(removeEscapes, "TabEcE"))
    assertEquals("EabcN", test(removeEscapes, "EabcENE"))
    assertEquals("Tblah1Eblah2N", test(removeEscapes, "Tblah1Eblah2EN"))
    assertEquals("Tblah1ENblah2N", test(removeEscapes, "Tblah1EENblah2EN"))
    assertEquals("blah1Eblah2", test(removeEscapes, "blah1Eblah2"))
    assertEquals("blah1EEblah2", test(removeEscapes, "blah1EEblah2"))
    assertEquals("blah1ETblah2", test(removeEscapes, "blah1ETblah2"))
  }

  @Test def testEscapeRemoval_SameCharacter = {
    // This might not be possible using regex replacement
    // may have to stick with existing code in DelimParser
    //
    // Assumptions:
    //	1. Delimiter and padding removed
    //
    // Step
    //	1.	Remove escape characters not preceded by escapeEscape
    //	2.	Remove escapeEscape characters
    val escape = "E"
    // val escapeEscape = "E"
    // val rRemoveSingleEscapes = """(?<!(%s%s)+)%s(?!(%s+))""" // (?<!(EE+))E(?!E+)
    // used to cleanup escape characters
    val ERSplit = """(.*?)%1$s(.)(.*)""".format(escape).r

    def removeActiveEscapes(str: String): String = {
      // if contains ER, replace with just R
      val str2 = removeActiveEscapes1(str)
      str2
    }

    def removeActiveEscapes1(str: String): String = {
      val res = str match {
        case ERSplit(before, delim, after) => {
          val rest = removeActiveEscapes1(after)
          before + delim + rest
        }
        case _ => str
      }
      res
    }

    def test(input: String) = {
      removeActiveEscapes(input)
    }

    assertEquals("text1Etext2", test("text1EEtext2"))
    assertEquals("text1Etext2Etext3", test("text1EEtext2EEtext3"))
    assertEquals("text1EEtext2", test("text1EEEEtext2"))
    assertEquals("text1E;text2", test("text1EEE;text2"))
    assertEquals("text1;text2", test("text1E;text2"))
    assertEquals("text1Etext2E", test("text1EEtext2EE"))
    assertEquals("text1text2", test("text1Etext2"))
  }

  @Test def testEscapeRemoval_DiffCharacter = {
    // Assumptions:
    //	1. Delimiter and padding removed
    //
    // Step
    //	1.	Remove escape characters not preceded by escapeEscape
    //	2.	Remove escapeEscape characters that precede escapes
    val escape = "E"
    val escapeEscape = "S"
    // val rRemoveEscape = """(%1$s$)|(%1$s(?=%2$s))""" // Replace escape at end of line OR replace escapeEscape preceding escapeBlockEnd
    //val rRemoveUnescapedEscapes = """((?<!S)E)"""
    val rRemoveUnescapedEscapes = """((?<!%1$s)%2$s)"""
    val removeUnescapedEscapes = rRemoveUnescapedEscapes.format(escapeEscape, escape)
    //val rRemoveEscapeEscapesThatEscape = """(S(?=E))"""
    val rRemoveEscapeEscapesThatEscape = """(%1$s(?=%2$s))"""
    val removeEscapeEscapesThatEscape = rRemoveEscapeEscapesThatEscape.format(escapeEscape, escape)

    def test(regex1: String, regex2: String, input: String) = {
      val r1 = input.replaceAll(regex1, "")
      val r2 = r1.replaceAll(regex2, "")
      r2
    }

    assertEquals("text1Etext2", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1SEtext2"))
    assertEquals("text1Etext2Etext3", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1SEtext2SEtext3"))
    assertEquals("text1EEtext2", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1SESEtext2"))
    assertEquals("text1E;text2", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1SEE;text2"))
    assertEquals("text1;text2", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1E;text2"))
    assertEquals("text1Etext2E", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1SEtext2SE"))
    assertEquals("text1SEtext2", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1SSEtext2"))
    assertEquals("text1Stext2", test(removeUnescapedEscapes, removeEscapeEscapesThatEscape, "text1Stext2"))
  }

  // Need to capture everything to get length of parsed data
  @Test def testParser_CaptureEverything = {
    var testNum = 0
    def test(theParser: Parser[(Vector[String], String)], theInput: String, isPadLeft: Boolean, isPadRight: Boolean) = {
      testNum = testNum + 1
      // val result = this.parse(this.log(theParser)("testParserEscapeSchemes_DiffEscapesWithPadding." + testNum), theInput)
      val result = this.parse(theParser, theInput)
      if (result.isEmpty) { None }
      else {
        val (c, delim) = result.get
        // System.err.println(c)
        val res = (isPadLeft -> isPadRight) match {
          case (true, true) => {
            // Pad ~ content ~ pad
            val field = c(1)
            (field, delim, c.mkString)
          }
          case (true, false) => {
            val field = c(1)
            (field, delim, c.mkString)
          }
          case (false, true) => {
            val field = c(0)
            (field, delim, c.mkString)
          }
          case (false, false) => {
            val field = c(0)
            (field, delim, c.mkString)
          }
        }

        Some(res._1, res._2, res._3)
      }
    }
    val padChar = "P"
    val delim = "(DD)|(D)"
    val rPadChar = """(%s*)"""
    val pPadChar: Parser[String] = rPadChar.format(padChar).r
    // Everything until:
    // 1.	PadChar ~ delim
    // 2.	PadChar ~ End of Data/File
    // 3.	delim
    // 4.	End of Data/File
    //
    // (.*?)(?=(1 | 2 | 3 | 4))
    // 1 = P*d
    // 2 = P*\z
    // 3 = d
    // 4 = \z
    val rBefore = """(.*?)(?=(%1$s+(%2$s))|(%1$s+\z)|(%2$s)|(\z))"""
    val pBefore: Parser[String] = rBefore.format(padChar, delim).r
    val pDelims: Parser[String] = """D""".r ||| """DD""".r
    //    val pEOF: Parser[String] = """\z""".r

    val paddedContent = pPadChar ~ pBefore ~ pPadChar ^^ { case (lp ~ c ~ rp) => Vector(lp, c, rp) }
    val leftPaddedContent = pPadChar ~ pBefore ^^ { case (lp ~ c) => Vector(lp, c) }
    val rightPaddedContent = pBefore ~ pPadChar ^^ { case (c ~ rp) => Vector(c, rp) }

    //    val content = pBefore ~ (pDelims | pEOF) ^^ { case (c ~ d) => (Vector(c), d) }
    //    val contentLeft = rightPaddedContent ~ (pDelims | pEOF) ^^ { case (c ~ d) => (c, d) }
    //    val contentRight = leftPaddedContent ~ (pDelims | pEOF) ^^ { case (c ~ d) => (c, d) }
    //    val contentCenter = paddedContent ~ (pDelims | pEOF) ^^ { case (c ~ d) => (c, d) }

    val contentDelimReq = pBefore ~ pDelims ^^ { case (c ~ d) => (Vector(c), d) }
    val contentLeftDelimReq = rightPaddedContent ~ pDelims ^^ { case (c ~ d) => (c, d) }
    val contentRightDelimReq = leftPaddedContent ~ pDelims ^^ { case (c ~ d) => (c, d) }
    val contentCenterDelimReq = paddedContent ~ pDelims ^^ { case (c ~ d) => (c, d) }

    assertEquals(Some("abc", "D", "abc"), test(contentDelimReq, "abcDefg", false, false))
    assertEquals(Some("abc", "D", "PPPabc"), test(contentRightDelimReq, "PPPabcDefg", true, false))
    assertEquals(Some("abc", "D", "abcPPP"), test(contentLeftDelimReq, "abcPPPDefg", false, true))
    assertEquals(Some("abc", "D", "PPPabcPPP"), test(contentCenterDelimReq, "PPPabcPPPDefg", true, true))

  }

  // Need to capture everything to get length of parsed data
  @Test def testParserEscapeSchemes_DiffEscapesWithPaddingCapturesEverything = {
    var testNum = 0
    def test(theParser: Parser[(Vector[String], String)], theInput: String, isPadLeft: Boolean, isPadRight: Boolean) = {
      testNum = testNum + 1
      // val result = this.parse(this.log(theParser)("testParserEscapeSchemes_DiffEscapesWithPadding." + testNum), theInput)
      val result = this.parse(theParser, theInput)
      if (result.isEmpty) { None }
      else {
        val (c, delim) = result.get
        val res = (isPadLeft -> isPadRight) match {
          case (true, true) => {
            // Pad ~ content ~ pad
            val field = c(1)
            (field, delim, c.mkString)
          }
          case (true, false) => {
            val field = c(1)
            (field, delim, c.mkString)
          }
          case (false, true) => {
            val field = c(0)
            (field, delim, c.mkString)
          }
          case (false, false) => {
            val field = c(0)
            (field, delim, c.mkString)
          }
        }

        Some(res._1, res._2, res._3)
      }
    }

    val escapeEscape = """S"""
    val escape = """E"""
    val delim = """D"""
    val padChar = """P"""

    val rPadChar = """(%s*)"""
    val pPadChar: Parser[String] = rPadChar.format(padChar).r
    val rLeftPadChar = """(%1$s*)(?=([^%1$s]))""" // LeftPad precedes non pad characters
    val pLeftPadChar: Parser[String] = rLeftPadChar.format(padChar).r
    val pEOF: Parser[String] = """\z""".r

    // Content is anything until:
    // 1. Padding ~ delimiter
    // 2. unescaped delimiter
    // 3. Optional Padding ~ EndOfData
    val rBefore = """(.*?)(?=(%4$s+%3$s)|((?<!(?<!%1$s)%2$s)%3$s)|(%4$s*\z))"""
    val pBefore: Parser[String] = rBefore.format(escapeEscape, escape, delim, padChar).r

    //    val rBeforeIgnoreTrailingPadding = """(.*?)(?=(?:(?<!(?<!%1$s)%2$s)%3$s)|\z)"""
    //    val pBeforeIgnoreTrailingPadding: Parser[String] = rBeforeIgnoreTrailingPadding.format(escapeEscape, escape, delim).r
    //
    val pDelims: Parser[String] = """D""".r ||| """DD""".r
    val pEscape: Parser[String] = """E""".r
    val pEscapeEscape: Parser[String] = """S""".r
    //        val pEscapedEscape = pEscapeEscape ~ pEscape
    val pUnescapedDelims = ((pEscapeEscape ~ pEscape) ~> pDelims) | (not(pEscape) ~> pDelims) | (pEscapeEscape ~> pDelims) | pDelims
    //
    //    // Here ^^ { case(b ~ d) => (b -> d) } changes the output of a successful parse to a Tuple2 of String (before, delimiter)
    val paddedContent: Parser[Vector[String]] = pLeftPadChar ~ pBefore ~ pPadChar ^^ { case (lp ~ c ~ rp) => Vector(lp, c, rp) }
    //    val leftPaddedContent: Parser[Vector[String]] = pLeftPadChar ~ pBefore ^^ { case (lp ~ c) => Vector(lp, c) }
    //    val rightPaddedContent: Parser[Vector[String]] = pBefore ~ pPadChar ^^ { case (c ~ rp) => Vector(c, rp) }

    //    val content: Parser[(Vector[String], String)] = (pBeforeIgnoreTrailingPadding ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (Vector(b) -> d) }
    val contentCenter: Parser[(Vector[String], String)] = paddedContent ~ (pUnescapedDelims | pEOF) ^^ { case (c ~ d) => (c, d) }
    //    val contentLeft: Parser[(Vector[String], String)] = rightPaddedContent ~ (pUnescapedDelims | pEOF) ^^ { case (c ~ d) => (c, d) }
    //    val contentRight: Parser[(Vector[String], String)] = leftPaddedContent ~ (pUnescapedDelims | pEOF) ^^ { case (c ~ d) => (c, d) }
    //
    //    val contentDelimReq: Parser[(Vector[String], String)] = pBeforeIgnoreTrailingPadding ~ pUnescapedDelims ^^ { case (b ~ d) => (Vector(b) -> d) }
    //    val contentCenterDelimReq: Parser[(Vector[String], String)] = paddedContent ~ pUnescapedDelims ^^ { case (c ~ d) => (c, d) }
    //    val contentLeftDelimReq: Parser[(Vector[String], String)] = rightPaddedContent ~ pUnescapedDelims ^^ { case (c ~ d) => (c, d) }
    //    val contentRightDelimReq: Parser[(Vector[String], String)] = leftPaddedContent ~ pUnescapedDelims ^^ { case (c ~ d) => (c, d) }

    // NOTE: At this point we've left the escapes in the content
    // we can probably go a step further and execute a regex replace on
    // the escape characters.  But order will likely matter.
    //
    // 1. Escapes should be removed unless preceded by an escapeEscape
    // 2. EscapeEscapes should be removed when they precede an escape.

    // Test padding blind escape
    // Encounter non-pad char amongst padding
    assertEquals(Some("text", "", "PPPtextPPP"), test(contentCenter, "PPPtextPPP", true, true))
    assertEquals(Some("/PPPtext/", "", "/PPPtext/PPP"), test(contentCenter, "/PPPtext/PPP", true, true))
    assertEquals(Some("/PPtextP/", "", "P/PPtextP/PP"), test(contentCenter, "P/PPtextP/PP", true, true))
    assertEquals(Some("/PtextPP/", "", "PP/PtextPP/P"), test(contentCenter, "PP/PtextPP/P", true, true))
    assertEquals(Some("/textPPP/", "", "PPP/textPPP/"), test(contentCenter, "PPP/textPPP/", true, true))

    // Encounter non-pad char amongst padding (verify no dependence on /)
    assertEquals(Some("text", "", "PPPtextPPP"), test(contentCenter, "PPPtextPPP", true, true))
    assertEquals(Some("^PPPtext^", "", "^PPPtext^PPP"), test(contentCenter, "^PPPtext^PPP", true, true))
    assertEquals(Some("^PPtextP^", "", "P^PPtextP^PP"), test(contentCenter, "P^PPtextP^PP", true, true))
    assertEquals(Some("^PtextPP^", "", "PP^PtextPP^P"), test(contentCenter, "PP^PtextPP^P", true, true))
    assertEquals(Some("^textPPP^", "", "PPP^textPPP^"), test(contentCenter, "PPP^textPPP^", true, true))
  }

  // Need to capture everything
  @Test def testParserEscapeSchemes_BlockEscapeWithPaddingCapturesEverything = {
    var testNum = 0
    def test(theParser: Parser[(Vector[String], String)], theInput: String, isPadLeft: Boolean, isPadRight: Boolean) = {
      testNum = testNum + 1
      // val result = this.parse(this.log(theParser)("testParserEscapeSchemes_BlockEscapeWithPaddingCapturesEverything." + testNum), theInput)
      val result = this.parse(theParser, theInput)
      if (result.isEmpty) { None }
      else {
        val (bc, delim) = result.get
        val res = (isPadLeft -> isPadRight) match {
          case (true, true) => {
            val field = bc(2)
            (field, delim, bc.mkString)
          }
          case (true, false) => {
            val field = bc(2)
            (field, delim, bc.mkString)
          }
          case (false, true) => {
            val field = bc(1)
            (field, delim, bc.mkString)
          }
          case (false, false) => {
            val field = bc(1)
            (field, delim, bc.mkString)
          }
        }

        Some(res._1, res._2, res._3)
      }
    }

    val blockStart = "T"
    val blockEnd = "N"
    val escapeEscape = "S"
    val padChar = "P"

    val rPadChar = """(%s*)"""
    val pPadChar: Parser[String] = rPadChar.format(padChar).r

    val rUnescapedBlockStart = """(?<!%1$s)%2$s"""
    val pUnescapedBlockStart: Parser[String] = rUnescapedBlockStart.format(escapeEscape, blockStart).r

    val rUnescapedBlockEnd = """(?<!%1$s)%2$s"""
    val pUnescapedBlockEnd: Parser[String] = rUnescapedBlockEnd.format(escapeEscape, blockEnd).r

    //    val rBeforeUnescapedBlockEnd = """(.*?)(?=((?<!%1$s)%2$s))"""
    val rBeforeUnescapedBlockEnd = """(.*?)(?=(""" + rUnescapedBlockEnd + """))"""
    val pBeforeUnescapedBlockEnd: Parser[String] = rBeforeUnescapedBlockEnd.format(escapeEscape, blockEnd).r

    val pDelims: Parser[String] = """D""".r ||| """DDD""".r

    //    val pEscape: Parser[String] = escapeEscape.r
    //    val pBlockStart: Parser[String] = blockStart.r
    //    val pBlockEnd: Parser[String] = blockEnd.r
    val pEOF: Parser[String] = """\z""".r

    val blockedContent: Parser[Vector[String]] = pUnescapedBlockStart ~ pBeforeUnescapedBlockEnd ~ pUnescapedBlockEnd ^^ { case (bs ~ c ~ be) => Vector(bs, c, be) }

    // Here the ^^ { case (b ~ d) => (b -> d) } statements allow us to control the output of a successful parse
    // in this particular case we want the output to be a Tuple2 of String (blockedContent, delimiter)
    //    val content: Parser[(Vector[String], String)] = blockedContent ~ (pDelims | pEOF) ^^ { case (bc ~ d) => (bc -> d) }
    //    val contentDelimReq: Parser[(Vector[String], String)] = blockedContent ~ pDelims ^^ { case (bc ~ d) => (bc -> d) }

    val paddedBlockedContent: Parser[Vector[String]] = pPadChar ~ blockedContent ~ pPadChar ^^ { case (lp ~ bc ~ rp) => Vector(lp) ++ bc ++ Vector(rp) }
    val contentCenter: Parser[(Vector[String], String)] = paddedBlockedContent ~ (pDelims | pEOF) ^^ { case (bc ~ d) => (bc -> d) }
    //    val contentCenterDelimReq: Parser[(Vector[String], String)] = paddedBlockedContent ~ pDelims ^^ { case (bc ~ d) => (bc -> d) }

    //    val leftPaddedBlockedContent: Parser[Vector[String]] = pPadChar ~ blockedContent ^^ { case (lp ~ bc) => Vector(lp) ++ bc }
    //    val contentRight: Parser[(Vector[String], String)] = leftPaddedBlockedContent ~ (pDelims | pEOF) ^^ { case (bc ~ d) => (bc -> d) }
    //    val contentRightDelimReq: Parser[(Vector[String], String)] = leftPaddedBlockedContent ~ pDelims ^^ { case (bc ~ d) => (bc -> d) }

    //    val rightPaddedBlockedContent: Parser[Vector[String]] = blockedContent ~ pPadChar ^^ { case (bc ~ rp) => bc ++ Vector(rp) }
    //    val contentLeft: Parser[(Vector[String], String)] = rightPaddedBlockedContent ~ (pDelims | pEOF) ^^ { case (bc ~ d) => (bc -> d) }
    //    val contentLeftDelimReq: Parser[(Vector[String], String)] = rightPaddedBlockedContent ~ pDelims ^^ { case (bc ~ d) => (bc -> d) }

    //    val contentCenter: Parser[(String, String)] = (pPadChar ~> blockedContent <~ pPadChar) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentCenterDelimReq: Parser[(String, String)] = (pPadChar ~> blockedContent <~ pPadChar) ~ pDelims ^^ { case (b ~ d) => (b -> d) }
    //
    //    val contentLeft: Parser[(String, String)] = (blockedContent <~ pPadChar) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentLeftDelimReq: Parser[(String, String)] = (blockedContent <~ pPadChar) ~ pDelims ^^ { case (b ~ d) => (b -> d) }
    //
    //    val contentRight: Parser[(String, String)] = (pPadChar ~> blockedContent) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentRightDelimReq: Parser[(String, String)] = (pPadChar ~> blockedContent) ~ pDelims ^^ { case (b ~ d) => (b -> d) }
    //
    //    val content: Parser[(String, String)] = (blockedContent) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentDelimReq: Parser[(String, String)] = (blockedContent) ~ pDelims ^^ { case (b ~ d) => (b -> d) }

    // Testing Center justification
    assertEquals(Some("beforeafter", "", "PPPTbeforeafterNPPP"), test(contentCenter, "PPPTbeforeafterNPPP", true, true))
    assertEquals(Some("before", "D", "PPPTbeforeNPPP"), test(contentCenter, "PPPTbeforeNPPPDafter", true, true))
    assertEquals(None, test(contentCenter, "TbeforeDafter", true, true)) // Fails because we expect a valid escapeBlockStart AND escapeBlockEnd
    assertEquals(Some("TbeforeSN", "D", "PPPTTbeforeSNNPPP"), test(contentCenter, "PPPTTbeforeSNNPPPDafter", true, true))
    assertEquals(Some("TbeforeDPPPstillbeforeSN", "D", "PPPTTbeforeDPPPstillbeforeSNNPPP"), test(contentCenter, "PPPTTbeforeDPPPstillbeforeSNNPPPDafter", true, true))
    assertEquals(None, test(contentCenter, "PPPTTbeforeDPPPstillbeforeNNPPPDafter", true, true)) // escapeBlockEnd is not escaped
    assertEquals(None, test(contentCenter, "PPPTbeforeNafterNPPP", true, true)) // escapeBlockEnd is not escaped
    assertEquals(Some("before1SNbefore2", "", "PPPTbefore1SNbefore2NPPP"), test(contentCenter, "PPPTbefore1SNbefore2NPPP", true, true))
    //    assertEquals(None, test(content, "PPPTbeforeSNafterNPPP", false, false))
    //    assertEquals(Some("before1SNbefore2", ""), test(content, "Tbefore1SNbefore2N", false, false))
    //    assertEquals(Some("before1SNbefore2PP", ""), test(content, "Tbefore1SNbefore2PPN", false, false))
  }

  @Test def testParserEscapeSchemes_BlockEscapeWithPadding = {
    var testNum = 0
    def test(theParser: Parser[(String, String)], theInput: String) = {
      testNum = testNum + 1
      // val result = this.parse(this.log(theParser)("testParserEscapeSchemes_BlockEscapeWithPadding." + testNum), theInput)
      val result = this.parse(theParser, theInput)
      if (result.isEmpty) { None }
      else {
        val res = result.get
        Some(res._1, res._2)
      }
    }

    val blockStart = "T"
    val blockEnd = "N"
    val escapeEscape = "S"
    val padChar = "P"

    val rPadChar = """(%s*)"""
    val pPadChar: Parser[String] = rPadChar.format(padChar).r

    val rUnescapedBlockStart = """(?<!%1$s)%2$s"""
    val pUnescapedBlockStart: Parser[String] = rUnescapedBlockStart.format(escapeEscape, blockStart).r

    val rUnescapedBlockEnd = """(?<!%1$s)%2$s"""
    val pUnescapedBlockEnd: Parser[String] = rUnescapedBlockEnd.format(escapeEscape, blockEnd).r

    //    val rBeforeUnescapedBlockEnd = """(.*?)(?=((?<!%1$s)%2$s))"""
    val rBeforeUnescapedBlockEnd = """(.*?)(?=(""" + rUnescapedBlockEnd + """))"""
    val pBeforeUnescapedBlockEnd: Parser[String] = rBeforeUnescapedBlockEnd.format(escapeEscape, blockEnd).r

    val pDelims: Parser[String] = """D""".r ||| """DDD""".r

    //    val pEscape: Parser[String] = escapeEscape.r
    //    val pBlockStart: Parser[String] = blockStart.r
    //    val pBlockEnd: Parser[String] = blockEnd.r
    val pEOF: Parser[String] = """\z""".r

    val blockedContent: Parser[String] = pUnescapedBlockStart ~> pBeforeUnescapedBlockEnd <~ pUnescapedBlockEnd

    // Here the ^^ { case (b ~ d) => (b -> d) } statements allow us to control the output of a successful parse
    // in this particular case we want the output to be a Tuple2 of String (blockedContent, delimiter)
    val contentCenter: Parser[(String, String)] = (pPadChar ~> blockedContent <~ pPadChar) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    val contentCenterDelimReq: Parser[(String, String)] = (pPadChar ~> blockedContent <~ pPadChar) ~ pDelims ^^ { case (b ~ d) => (b -> d) }

    //    val contentLeft: Parser[(String, String)] = (blockedContent <~ pPadChar) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentLeftDelimReq: Parser[(String, String)] = (blockedContent <~ pPadChar) ~ pDelims ^^ { case (b ~ d) => (b -> d) }

    //    val contentRight: Parser[(String, String)] = (pPadChar ~> blockedContent) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentRightDelimReq: Parser[(String, String)] = (pPadChar ~> blockedContent) ~ pDelims ^^ { case (b ~ d) => (b -> d) }

    val content: Parser[(String, String)] = (blockedContent) ~ (pDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    //    val contentDelimReq: Parser[(String, String)] = (blockedContent) ~ pDelims ^^ { case (b ~ d) => (b -> d) }

    // Testing Center justification
    assertEquals(Some("beforeafter", ""), test(contentCenter, "PPPTbeforeafterNPPP"))
    assertEquals(Some("before", "D"), test(contentCenterDelimReq, "PPPTbeforeNPPPDafter"))
    assertEquals(None, test(contentCenter, "TbeforeDafter")) // Fails because we expect a valid escapeBlockStart AND escapeBlockEnd
    assertEquals(Some("TbeforeSN", "D"), test(contentCenterDelimReq, "PPPTTbeforeSNNPPPDafter"))
    assertEquals(Some("TbeforeDPPPstillbeforeSN", "D"), test(contentCenterDelimReq, "PPPTTbeforeDPPPstillbeforeSNNPPPDafter"))
    assertEquals(None, test(contentCenterDelimReq, "PPPTTbeforeDPPPstillbeforeNNPPPDafter")) // escapeBlockEnd is not escaped
    assertEquals(None, test(contentCenter, "PPPTbeforeNafterNPPP")) // escapeBlockEnd is not escaped
    assertEquals(Some("before1SNbefore2", ""), test(contentCenter, "PPPTbefore1SNbefore2NPPP"))
    assertEquals(None, test(content, "PPPTbeforeSNafterNPPP"))
    assertEquals(Some("before1SNbefore2", ""), test(content, "Tbefore1SNbefore2N"))
    assertEquals(Some("before1SNbefore2PP", ""), test(content, "Tbefore1SNbefore2PPN"))
  }

  @Test def testParserEscapeSchemes_SameEscapeWithPadding = {
    var testNum = 0
    def test(theParser: Parser[(String, String)], theInput: String) = {
      testNum = testNum + 1
      // val result = this.parse(this.log(theParser)("testParserEscapeSchemes_SameEscapeWithPadding." + testNum), theInput)
      val result = this.parse(theParser, theInput)
      if (result.isEmpty) { None }
      else {
        val res = result.get
        Some(res._1, res._2)
      }
    }
    val escape = """E"""
    val delim = """D"""
    val padChar = """P"""

    val rPadChar = """(%s*)"""
    val pPadChar: Parser[String] = rPadChar.format(padChar).r
    val rLeftPadChar = """(%1$s*)(?=([^%1$s]))"""
    val pLeftPadChar: Parser[String] = rLeftPadChar.format(padChar).r

    // Need to tolerate reading to end of data here
    //
    // Assumptions:
    //	A field can be terminated by...
    //		Unescaped delimiter
    //		Padding followed by unescaped delimiter
    //		Padding followed by end of data
    //		End of data
    //
    //    val rBefore = """(.*?)(?=(?:(?<!%1$s)((%1$s%1$s)*)(%3$s*)(((?<!%1$s)(%2$s))|(\z)))|(%1$s(%3$s+)(%2$s|\z))|((?<!%1$s)((%1$s%1$s)*)(%2$s))|\z)"""
    val rBefore = """(.*?)(?=""" + // Give me everything from this point until...
      """(?:(%1$s*)(%3$s*)(((?<!%1$s)(%2$s))|(\z)))""" + // An unescaped/escaped pad char followed by either an unescaped delimiter or end of data
      """|""" + // OR
      """(%1$s(%3$s+)(%2$s|\z))""" + // escape followed by one or more pad chars followed by a delimiter or end of data
      """|""" + // OR
      """((?<!%1$s)((%1$s%1$s)*)(%2$s))""" + // unescaped delimiter
      """|""" + // OR
      """\z)""" // End of data/file

    val pBefore: Parser[String] = rBefore.format(escape, delim, padChar).r

    val rBeforeIgnoreTrailingPadding = """(.*?)(?=((?<!%1$s)((%1$s%1$s)*)(%2$s))|(\z))"""
    val pBeforeIgnoreTrailingPadding: Parser[String] = rBeforeIgnoreTrailingPadding.format(escape, delim).r

    val pDelims: Parser[String] = """D""".r ||| """DD""".r
    val pEscape: Parser[String] = """E""".r
    val pEOF: Parser[String] = """\z""".r

    val pEscapedEscape = (pEscape ~ pEscape) ^^ { case (e1 ~ e2) => (e1 + e2) } // concatenate escapes
    //val pEscapedDelims = not(pEscapedEscape) ~> (pEscape ~> pDelims)
    val pUnescapedDelims = ((pEscapedEscape) ~> pDelims) | (not(pEscape) ~> pDelims) | pDelims

    // Parser captures and creates a string representation of the escapes
    val pEscapes = ((pEscapedEscape.*) ~ opt(pEscape)) ^^ {
      case (l ~ None) => l.mkString
      case (l ~ Some(esc)) => l.mkString + esc
    }

    // Here because of the nature of using the same character for escape and escapeEscape
    // we need to capture the escapes if they exist and make them part of the 'before'
    val pBeforeAndEscsIgnoreTrailingPadding = (pBeforeIgnoreTrailingPadding ~ opt(pEscapes)) ^^ {
      case (b ~ None) => b
      case (b ~ Some(e)) => (b + e)
    }

    val pBeforeAndEscs = (pBefore ~ opt(pEscapes | pEscapedEscape | pEscape)) ^^ {
      case (b ~ None) => b
      case (b ~ Some(e)) => (b + e)
    }
    val contentDelimReq = pBeforeAndEscsIgnoreTrailingPadding ~ pUnescapedDelims ^^ { case (b ~ d) => (b -> d) }
    val contentCenterDelimReq = (((pLeftPadChar ~> pBeforeAndEscs) <~ pPadChar) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
    val contentLeftDelimReq = ((pBeforeAndEscs <~ pPadChar) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
    val contentRightDelimReq = ((pLeftPadChar ~> pBeforeAndEscsIgnoreTrailingPadding) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }

    val content = pBeforeAndEscsIgnoreTrailingPadding ~ (pUnescapedDelims | pEOF) ^^ { case (b ~ d) => (b -> d) }
    val contentCenter = (((pLeftPadChar ~> pBeforeAndEscs) <~ pPadChar) ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }
    val contentLeft = ((pBeforeAndEscs <~ pPadChar) ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }
    val contentRight = ((pLeftPadChar ~> pBeforeAndEscsIgnoreTrailingPadding) ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }

    // Test Delim required works
    assertEquals(None, test(contentDelimReq, "abcEEEEEdefghi"))

    // Testing proper escaping of pads
    assertEquals(Some("textP/", "D"), test(contentLeftDelimReq, "textP/PPDafter"))
    assertEquals(Some("textPP/", "D"), test(contentLeftDelimReq, "textPP/PDafter"))
    assertEquals(Some("textPPP/", "D"), test(contentLeftDelimReq, "textPPP/Dafter"))
    assertEquals(Some("text/", "D"), test(contentLeftDelimReq, "text/PPPDafter"))
    assertEquals(Some("text", "D"), test(contentLeftDelimReq, "textPPPDafter"))
    assertEquals(Some("text", "D"), test(contentLeftDelimReq, "textDafter"))

    assertEquals(Some("/PPPtext", "D"), test(contentRightDelimReq, "/PPPtextDafter"))
    assertEquals(Some("/PPtext", "D"), test(contentRightDelimReq, "P/PPtextDafter"))
    assertEquals(Some("/Ptext", "D"), test(contentRightDelimReq, "PP/PtextDafter"))
    assertEquals(Some("/text", "D"), test(contentRightDelimReq, "PPP/textDafter"))
    assertEquals(Some("text", "D"), test(contentRightDelimReq, "PPPtextDafter"))
    assertEquals(Some("text", "D"), test(contentRightDelimReq, "textDafter"))

    // Verifying that the escapes are working correctly in conjunction with padding on right
    // various combinations attempting to break regex
    assertEquals(Some("textPPEE", "D"), test(contentCenterDelimReq, "PPPtextPPEEDafter")) // escaped escape, padding part of content
    assertEquals(Some("textEE", "D"), test(contentCenterDelimReq, "PPPtextEEPPPDafter"))
    assertEquals(Some("textEPEPEDafter", ""), test(contentCenter, "PPPtextEPEPEDafter")) // escaped delim, padding interwoven with escapes
    assertEquals(Some("textEPEPEE", "D"), test(contentCenter, "PPPtextEPEPEEDafter")) // unescaped delim, padding interwoven with escapes
    assertEquals(Some("textPPEDafter", ""), test(contentCenter, "PPPtextPPEDafter")) // escaped delim, padding part of content
    assertEquals(Some("textEEEDafter", ""), test(contentCenter, "PPPtextEEEDafter")) // escaped delim
    assertEquals(Some("textEE", "D"), test(contentCenter, "PPPtextEEDafter")) // escaped escape
    assertEquals(Some("textEDafter", ""), test(contentCenter, "PPPtextEDafter")) // escaped delim
    assertEquals(Some("text", "D"), test(contentCenter, "PPPtextDafter"))
    assertEquals(Some("text", "D"), test(contentCenter, "PPPtextPDafter")) // 'unescaped' pad char
    assertEquals(Some("textE", "D"), test(contentCenter, "PPPtextEPDafter")) // 'escaped' pad char

    assertEquals(Some("/PPPtextPPP/", "D"), test(contentCenterDelimReq, "/PPPtextPPP/Dafter"))
    assertEquals(Some("/PPtextPP/", "D"), test(contentCenterDelimReq, "P/PPtextPP/PDafter"))
    assertEquals(Some("/PtextP/", "D"), test(contentCenterDelimReq, "PP/PtextP/PPDafter"))
    assertEquals(Some("/text/", "D"), test(contentCenterDelimReq, "PPP/text/PPPDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "PPPtextPPPDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "PPPtextDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "textPPPDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "textDafter"))

    assertEquals(Some("textP/", ""), test(contentLeft, "textP/PP"))
    assertEquals(Some("textPP/", ""), test(contentLeft, "textPP/P"))
    assertEquals(Some("textPPP/", ""), test(contentLeft, "textPPP/"))
    assertEquals(Some("text/", ""), test(contentLeft, "text/PPP"))
    assertEquals(Some("text", ""), test(contentLeft, "textPPP"))
    assertEquals(Some("text", ""), test(contentLeft, "text"))

    assertEquals(Some("/PPPtext", ""), test(contentRight, "/PPPtext"))
    assertEquals(Some("/PPtext", ""), test(contentRight, "P/PPtext"))
    assertEquals(Some("/Ptext", ""), test(contentRight, "PP/Ptext"))
    assertEquals(Some("/text", ""), test(contentRight, "PPP/text"))
    assertEquals(Some("text", ""), test(contentRight, "PPPtext"))
    assertEquals(Some("text", ""), test(contentRight, "text"))

    assertEquals(Some("/PPPtextPPP/", ""), test(contentCenter, "/PPPtextPPP/"))
    assertEquals(Some("/PPtextPP/", ""), test(contentCenter, "P/PPtextPP/P"))
    assertEquals(Some("/PtextP/", ""), test(contentCenter, "PP/PtextP/PP"))
    assertEquals(Some("/text/", ""), test(contentCenter, "PPP/text/PPP"))
    assertEquals(Some("text", ""), test(contentCenter, "PPPtextPPP"))
    assertEquals(Some("text", ""), test(contentCenter, "PPPtext"))
    assertEquals(Some("text", ""), test(contentCenter, "textPPP"))
    assertEquals(Some("text", ""), test(contentCenter, "text"))

    // Pad char occur in middle of content
    assertEquals(Some("tePxt", ""), test(contentCenter, "PPPtePxtPPP"))
    assertEquals(Some("^PPPtePxt^", ""), test(contentCenter, "^PPPtePxt^PPP"))
    assertEquals(Some("^PPtePxtP^", ""), test(contentCenter, "P^PPtePxtP^PP"))
    assertEquals(Some("^PtePxtPP^", ""), test(contentCenter, "PP^PtePxtPP^P"))
    assertEquals(Some("^tePxtPPP^", ""), test(contentCenter, "PPP^tePxtPPP^"))

    // Verify that the escaping of delimiters still works with padding
    assertEquals(Some("teEDxt", ""), test(contentCenter, "PPPteEDxtPPP"))
    assertEquals(Some("^PPPteEDPxt^", ""), test(contentCenter, "^PPPteEDPxt^PPP"))
    assertEquals(Some("^PPteEDPxtP^", ""), test(contentCenter, "P^PPteEDPxtP^PP"))
    assertEquals(Some("^PteEDPxtPP^", ""), test(contentCenter, "PP^PteEDPxtPP^P"))
    assertEquals(Some("^teEDPxtPPP^", ""), test(contentCenter, "PPP^teEDPxtPPP^"))

    // Tests
    assertEquals(Some("textPE", "D"), test(contentCenterDelimReq, "PPPtextPEPPD"))

    // Testing no justification, padding is treated as part of content
    assertEquals(Some("before", "D"), test(contentDelimReq, "beforeDafter"))
    assertEquals(Some("PPPbefore", "D"), test(contentDelimReq, "PPPbeforeDafter"))
    assertEquals(Some("beforePPP", "D"), test(contentDelimReq, "beforePPPDafter"))
    assertEquals(Some("PPPbeforePPP", "D"), test(contentDelimReq, "PPPbeforePPPDafter"))

    // Testing no justification, padding is treated as part of content w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentDelimReq, "abcEEEEEdefDghi"))
    assertEquals(Some("abcSESESEdef", "D"), test(content, "abcSESESEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentDelimReq, "beforeEDstillbeforeDafter"))
    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(contentDelimReq, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentDelimReq, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("PPPbeforePPPEDstillbeforePPP", "D"), test(contentDelimReq, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing no justification, padding is treated as part of content w/ escaped escaping
    assertEquals(Some("beforeEE", "D"), test(contentDelimReq, "beforeEEDafter1Dafter2"))
    assertEquals(Some("PPPbeforeEE", "D"), test(contentDelimReq, "PPPbeforeEEDafter1Dafter2"))
    assertEquals(Some("beforePPPEE", "D"), test(contentDelimReq, "beforePPPEEDafter1PPPDafter2"))
    assertEquals(Some("PPPbeforePPPEE", "D"), test(contentDelimReq, "PPPbeforePPPEEDafter1PPPDafter2"))

    // Testing Center justification, padding is not part of content
    assertEquals(Some("before", "D"), test(contentCenterDelimReq, "beforeDafter"))
    assertEquals(Some("before", "D"), test(contentCenterDelimReq, "PPPbeforeDafter"))
    assertEquals(Some("before", "D"), test(contentCenterDelimReq, "beforePPPDafter"))
    assertEquals(Some("before", "D"), test(contentCenterDelimReq, "PPPbeforePPPDafter"))

    // Testing Center justification, padding part of content w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentCenterDelimReq, "abcEEEEEdefDghi"))
    assertEquals(Some("abcEEEEdef", "D"), test(contentCenterDelimReq, "abcEEEEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenterDelimReq, "beforeEDstillbeforeDafter"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenterDelimReq, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenterDelimReq, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenterDelimReq, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing Center justification, padding is part of content w/ escaped escaping
    assertEquals(Some("beforeEE", "D"), test(contentCenterDelimReq, "beforeEEDafter1Dafter2"))
    assertEquals(Some("beforeEE", "D"), test(contentCenterDelimReq, "PPPbeforeEEDafter1Dafter2"))
    assertEquals(Some("beforePPPEE", "D"), test(contentCenterDelimReq, "beforePPPEEDafter1PPPDafter2"))
    assertEquals(Some("beforePPPEE", "D"), test(contentCenterDelimReq, "PPPbeforePPPEEDafter1PPPDafter2"))

    // Testing Left justification, padding on right removed only
    assertEquals(Some("before", "D"), test(contentLeftDelimReq, "beforeDafter"))
    assertEquals(Some("PPPbefore", "D"), test(contentLeftDelimReq, "PPPbeforeDafter"))
    assertEquals(Some("before", "D"), test(contentLeftDelimReq, "beforePPPDafter"))
    assertEquals(Some("PPPbefore", "D"), test(contentLeftDelimReq, "PPPbeforePPPDafter"))

    // Testing Left justification, padding on right removed only w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentLeftDelimReq, "abcEEEEEdefDghi"))
    assertEquals(Some("abcEEEEEEdef", "D"), test(contentLeftDelimReq, "abcEEEEEEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentLeftDelimReq, "beforeEDstillbeforeDafter"))
    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(contentLeftDelimReq, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentLeftDelimReq, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("PPPbeforePPPEDstillbefore", "D"), test(contentLeftDelimReq, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing Left justification, padding on right removed only w/ escaped escaping
    assertEquals(Some("beforeEE", "D"), test(contentLeftDelimReq, "beforeEEDafter1Dafter2"))
    assertEquals(Some("PPPbeforeEE", "D"), test(contentLeftDelimReq, "PPPbeforeEEDafter1Dafter2"))
    assertEquals(Some("beforePPPEE", "D"), test(contentLeftDelimReq, "beforePPPEEDafter1PPPDafter2"))
    assertEquals(Some("PPPbeforePPPEE", "D"), test(contentLeftDelimReq, "PPPbeforePPPEEDafter1PPPDafter2"))

    // Testing Right justification, padding on left removed only
    assertEquals(Some("before", "D"), test(contentRightDelimReq, "beforeDafter"))
    assertEquals(Some("before", "D"), test(contentRightDelimReq, "PPPbeforeDafter"))
    assertEquals(Some("beforePPP", "D"), test(contentRightDelimReq, "beforePPPDafter"))
    assertEquals(Some("beforePPP", "D"), test(contentRightDelimReq, "PPPbeforePPPDafter"))

    // Testing Right justification, padding on left removed only w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentRightDelimReq, "abcEEEEEdefDghi"))
    assertEquals(Some("abcEEEEEEdef", "D"), test(contentRightDelimReq, "abcEEEEEEdefDghi"))
    assertEquals(Some("abcEE", "D"), test(contentRightDelimReq, "abcEEDefDghi"))
    assertEquals(Some("abcEEEDef", "D"), test(contentRightDelimReq, "abcEEEDefDghi"))
    assertEquals(Some("abcEEEE", "D"), test(contentRightDelimReq, "abcEEEEDefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRightDelimReq, "beforeEDstillbeforeDafter"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRightDelimReq, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRightDelimReq, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRightDelimReq, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing Right justification, padding on left removed only w/ escaped escaping
    assertEquals(Some("beforeEE", "D"), test(contentRightDelimReq, "beforeEEDstillbeforeDafter"))
    assertEquals(Some("beforeEE", "D"), test(contentRightDelimReq, "PPPbeforeEEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEE", "D"), test(contentRightDelimReq, "beforePPPEEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPEE", "D"), test(contentRightDelimReq, "PPPbeforePPPEEDstillbeforePPPDafter"))

    // Testing Escaped Padding
    assertEquals(Some("beforeEEPPP", "D"), test(contentRightDelimReq, "PPPbeforeEEPPPDafter1Dafter2"))
    assertEquals(Some("beforeEPPP", "D"), test(contentRightDelimReq, "PPPbeforeEPPPDafter1Dafter2"))
    assertEquals(Some("PPPbeforeEE", "D"), test(contentLeftDelimReq, "PPPbeforeEEPPPDafter1Dafter2"))
    assertEquals(Some("PPPbeforeE", "D"), test(contentLeftDelimReq, "PPPbeforeEPPPDafter1Dafter2"))
    assertEquals(Some("beforeEE", "D"), test(contentCenterDelimReq, "PPPbeforeEEPPPDafter1Dafter2"))
    assertEquals(Some("beforeE", "D"), test(contentCenterDelimReq, "PPPbeforeEPPPDafter1Dafter2"))
    assertEquals(Some("EEPPPbeforeEE", "D"), test(contentCenterDelimReq, "EEPPPbeforeEEPPPDafter1Dafter2"))
    assertEquals(Some("EPPPbeforeE", "D"), test(contentCenterDelimReq, "EPPPbeforeEPPPDafter1Dafter2"))
  }

  @Test def testParserEscapeSchemes_DiffEscapesWithPadding = {
    var testNum = 0
    def test(theParser: Parser[(String, String)], theInput: String) = {
      testNum = testNum + 1
      //val result = this.parse(this.log(theParser)("testParserEscapeSchemes_DiffEscapesWithPadding." + testNum), theInput)
      val result = this.parse(theParser, theInput)
      if (result.isEmpty) { None }
      else {
        val res = result.get
        Some(res._1, res._2)
      }
    }

    val escapeEscape = """S"""
    val escape = """E"""
    val delim = """D"""
    val padChar = """P"""

    val rPadChar = """(%s*)"""
    val pPadChar: Parser[String] = rPadChar.format(padChar).r
    val rLeftPadChar = """(%1$s*)(?=([^%1$s]))""" // LeftPad precedes non pad characters
    val pLeftPadChar: Parser[String] = rLeftPadChar.format(padChar).r
    val pEOF: Parser[String] = """\z""".r

    // Content is anything until:
    // 1. Padding ~ delimiter
    // 2. unescaped delimiter
    // 3. Optional Padding ~ EndOfData
    val rBefore = """(.*?)(?=(%4$s+%3$s)|((?<!(?<!%1$s)%2$s)%3$s)|(%4$s*\z))"""
    val pBefore: Parser[String] = rBefore.format(escapeEscape, escape, delim, padChar).r

    val rBeforeIgnoreTrailingPadding = """(.*?)(?=(?:(?<!(?<!%1$s)%2$s)%3$s)|\z)"""
    val pBeforeIgnoreTrailingPadding: Parser[String] = rBeforeIgnoreTrailingPadding.format(escapeEscape, escape, delim).r

    val pDelims: Parser[String] = """D""".r ||| """DD""".r
    val pEscape: Parser[String] = """E""".r
    val pEscapeEscape: Parser[String] = """S""".r
    //    val pEscapedEscape = pEscapeEscape ~ pEscape
    //    val pEscapedDelims = not(pEscapedEscape) ~> (pEscape ~> pDelims)
    val pUnescapedDelims = ((pEscapeEscape ~ pEscape) ~> pDelims) | (not(pEscape) ~> pDelims) | (pEscapeEscape ~> pDelims) | pDelims

    // Here ^^ { case(b ~ d) => (b -> d) } changes the output of a successful parse to a Tuple2 of String (before, delimiter)
    val content = (pBeforeIgnoreTrailingPadding ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }
    val contentCenter = (((pLeftPadChar ~> pBefore) <~ pPadChar) ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }
    val contentLeft = ((pBefore <~ pPadChar) ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }
    val contentRight = ((pLeftPadChar ~> pBeforeIgnoreTrailingPadding) ~ (pUnescapedDelims | pEOF)) ^^ { case (b ~ d) => (b -> d) }

    //    val contentDelimReq = (pBeforeIgnoreTrailingPadding ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
    val contentCenterDelimReq = (((pLeftPadChar ~> pBefore) <~ pPadChar) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
    val contentLeftDelimReq = ((pBefore <~ pPadChar) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
    val contentRightDelimReq = ((pLeftPadChar ~> pBeforeIgnoreTrailingPadding) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }

    // NOTE: At this point we've left the escapes in the content
    // we can probably go a step further and execute a regex replace on
    // the escape characters.  But order will likely matter.
    //
    // 1. Escapes should be removed unless preceded by an escapeEscape
    // 2. EscapeEscapes should be removed when they precede an escape.

    // Test padding blind escape
    // Encounter non-pad char amongst padding
    assertEquals(Some("text", ""), test(contentCenter, "PPPtextPPP"))
    assertEquals(Some("/PPPtext/", ""), test(contentCenter, "/PPPtext/PPP"))
    assertEquals(Some("/PPtextP/", ""), test(contentCenter, "P/PPtextP/PP"))
    assertEquals(Some("/PtextPP/", ""), test(contentCenter, "PP/PtextPP/P"))
    assertEquals(Some("/textPPP/", ""), test(contentCenter, "PPP/textPPP/"))

    // Encounter non-pad char amongst padding (verify no dependence on /)
    assertEquals(Some("text", ""), test(contentCenter, "PPPtextPPP"))
    assertEquals(Some("^PPPtext^", ""), test(contentCenter, "^PPPtext^PPP"))
    assertEquals(Some("^PPtextP^", ""), test(contentCenter, "P^PPtextP^PP"))
    assertEquals(Some("^PtextPP^", ""), test(contentCenter, "PP^PtextPP^P"))
    assertEquals(Some("^textPPP^", ""), test(contentCenter, "PPP^textPPP^"))

    // Encounter escape amongst padding
    assertEquals(Some("text", ""), test(contentCenter, "PPPtextPPP"))
    assertEquals(Some("EPPPtextE", ""), test(contentCenter, "EPPPtextEPPP"))
    assertEquals(Some("EPPtextPE", ""), test(contentCenter, "PEPPtextPEPP"))
    assertEquals(Some("EPtextPPE", ""), test(contentCenter, "PPEPtextPPEP"))
    assertEquals(Some("EtextPPPE", ""), test(contentCenter, "PPPEtextPPPE"))

    // Encounter escape and escapeEscape amongst padding
    assertEquals(Some("text", ""), test(contentCenter, "PPPtextPPP"))
    assertEquals(Some("SEPPPtextSE", ""), test(contentCenter, "SEPPPtextSEPPP"))
    assertEquals(Some("SEPPtextPSE", ""), test(contentCenter, "PSEPPtextPSEPP"))
    assertEquals(Some("SEPtextPPSE", ""), test(contentCenter, "PPSEPtextPPSEP"))
    assertEquals(Some("SEtextPPPSE", ""), test(contentCenter, "PPPSEtextPPPSE"))

    // Pad char occur in middle of content
    assertEquals(Some("tePxt", ""), test(contentCenter, "PPPtePxtPPP"))
    assertEquals(Some("^PPPtePxt^", ""), test(contentCenter, "^PPPtePxt^PPP"))
    assertEquals(Some("^PPtePxtP^", ""), test(contentCenter, "P^PPtePxtP^PP"))
    assertEquals(Some("^PtePxtPP^", ""), test(contentCenter, "PP^PtePxtPP^P"))
    assertEquals(Some("^tePxtPPP^", ""), test(contentCenter, "PPP^tePxtPPP^"))

    // Verify that the escaping of delimiters still works with padding
    assertEquals(Some("teEDxt", ""), test(contentCenter, "PPPteEDxtPPP"))
    assertEquals(Some("^PPPteEDPxt^", ""), test(contentCenter, "^PPPteEDPxt^PPP"))
    assertEquals(Some("^PPteEDPxtP^", ""), test(contentCenter, "P^PPteEDPxtP^PP"))
    assertEquals(Some("^PteEDPxtPP^", ""), test(contentCenter, "PP^PteEDPxtPP^P"))
    assertEquals(Some("^teEDPxtPPP^", ""), test(contentCenter, "PPP^teEDPxtPPP^"))

    // Verify that delim required works
    assertEquals(None, test(contentCenterDelimReq, "textafter"))

    // Testing proper escaping of pads when delimiter required
    assertEquals(Some("textP/", "D"), test(contentLeftDelimReq, "textP/PPDafter"))
    assertEquals(Some("textPP/", "D"), test(contentLeftDelimReq, "textPP/PDafter"))
    assertEquals(Some("textPPP/", "D"), test(contentLeftDelimReq, "textPPP/Dafter"))
    assertEquals(Some("text/", "D"), test(contentLeftDelimReq, "text/PPPDafter"))
    assertEquals(Some("text", "D"), test(contentLeftDelimReq, "textPPPDafter"))
    assertEquals(Some("text", "D"), test(contentLeftDelimReq, "textDafter"))

    assertEquals(Some("/PPPtext", "D"), test(contentRightDelimReq, "/PPPtextDafter"))
    assertEquals(Some("/PPtext", "D"), test(contentRightDelimReq, "P/PPtextDafter"))
    assertEquals(Some("/Ptext", "D"), test(contentRightDelimReq, "PP/PtextDafter"))
    assertEquals(Some("/text", "D"), test(contentRightDelimReq, "PPP/textDafter"))
    assertEquals(Some("text", "D"), test(contentRightDelimReq, "PPPtextDafter"))
    assertEquals(Some("text", "D"), test(contentRightDelimReq, "textDafter"))

    assertEquals(Some("/PPPtextPPP/", "D"), test(contentCenterDelimReq, "/PPPtextPPP/Dafter"))
    assertEquals(Some("/PPtextPP/", "D"), test(contentCenterDelimReq, "P/PPtextPP/PDafter"))
    assertEquals(Some("/PtextP/", "D"), test(contentCenterDelimReq, "PP/PtextP/PPDafter"))
    assertEquals(Some("/text/", "D"), test(contentCenterDelimReq, "PPP/text/PPPDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "PPPtextPPPDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "PPPtextDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "textPPPDafter"))
    assertEquals(Some("text", "D"), test(contentCenterDelimReq, "textDafter"))

    assertEquals(Some("textP/", ""), test(contentLeft, "textP/PP"))
    assertEquals(Some("textPP/", ""), test(contentLeft, "textPP/P"))
    assertEquals(Some("textPPP/", ""), test(contentLeft, "textPPP/"))
    assertEquals(Some("text/", ""), test(contentLeft, "text/PPP"))
    assertEquals(Some("text", ""), test(contentLeft, "textPPP"))
    assertEquals(Some("text", ""), test(contentLeft, "text"))

    assertEquals(Some("/PPPtext", ""), test(contentRight, "/PPPtext"))
    assertEquals(Some("/PPtext", ""), test(contentRight, "P/PPtext"))
    assertEquals(Some("/Ptext", ""), test(contentRight, "PP/Ptext"))
    assertEquals(Some("/text", ""), test(contentRight, "PPP/text"))
    assertEquals(Some("text", ""), test(contentRight, "PPPtext"))
    assertEquals(Some("text", ""), test(contentRight, "text"))

    // Testing no justification, padding is treated as part of content
    assertEquals(Some("before", "D"), test(content, "beforeDafter"))
    assertEquals(Some("PPPbefore", "D"), test(content, "PPPbeforeDafter"))
    assertEquals(Some("beforePPP", "D"), test(content, "beforePPPDafter"))
    assertEquals(Some("PPPbeforePPP", "D"), test(content, "PPPbeforePPPDafter"))

    // Testing no justification, padding is treated as part of content w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(content, "abcEEEEEdefDghi"))
    assertEquals(Some("abcSESESEdef", "D"), test(content, "abcSESESEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(content, "beforeEDstillbeforeDafter"))
    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(content, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(content, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("PPPbeforePPPEDstillbeforePPP", "D"), test(content, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing no justification, padding is treated as part of content w/ escaped escaping
    assertEquals(Some("beforeSE", "D"), test(content, "beforeSEDstillbeforeDafter"))
    assertEquals(Some("PPPbeforeSE", "D"), test(content, "PPPbeforeSEDstillbeforeDafter"))
    assertEquals(Some("beforePPPSE", "D"), test(content, "beforePPPSEDstillbeforePPPDafter"))
    assertEquals(Some("PPPbeforePPPSE", "D"), test(content, "PPPbeforePPPSEDstillbeforePPPDafter"))

    // Testing Center justification, padding is not part of content
    assertEquals(Some("before", "D"), test(contentCenter, "beforeDafter"))
    assertEquals(Some("before", "D"), test(contentCenter, "PPPbeforeDafter"))
    assertEquals(Some("before", "D"), test(contentCenter, "beforePPPDafter"))
    assertEquals(Some("before", "D"), test(contentCenter, "PPPbeforePPPDafter"))

    // Testing Center justification, padding part of content w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentCenter, "abcEEEEEdefDghi"))
    assertEquals(Some("abcSESESEdef", "D"), test(contentCenter, "abcSESESEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenter, "beforeEDstillbeforeDafter"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenter, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenter, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenter, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing Center justification, padding is part of content w/ escaped escaping
    assertEquals(Some("beforeSE", "D"), test(contentCenter, "beforeSEDstillbeforeDafter"))
    assertEquals(Some("beforeSE", "D"), test(contentCenter, "PPPbeforeSEDstillbeforeDafter"))
    assertEquals(Some("beforePPPSE", "D"), test(contentCenter, "beforePPPSEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPSE", "D"), test(contentCenter, "PPPbeforePPPSEDstillbeforePPPDafter"))

    // Testing Left justification, padding on right removed only
    assertEquals(Some("before", "D"), test(contentLeft, "beforeDafter"))
    assertEquals(Some("PPPbefore", "D"), test(contentLeft, "PPPbeforeDafter"))
    assertEquals(Some("before", "D"), test(contentLeft, "beforePPPDafter"))
    assertEquals(Some("PPPbefore", "D"), test(contentLeft, "PPPbeforePPPDafter"))

    // Testing Left justification, padding on right removed only w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentLeft, "abcEEEEEdefDghi"))
    assertEquals(Some("abcSESESEdef", "D"), test(contentLeft, "abcSESESEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentLeft, "beforeEDstillbeforeDafter"))
    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(contentLeft, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentLeft, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("PPPbeforePPPEDstillbefore", "D"), test(contentLeft, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing Left justification, padding on right removed only w/ escaped escaping
    assertEquals(Some("beforeSE", "D"), test(contentLeft, "beforeSEDstillbeforeDafter"))
    assertEquals(Some("PPPbeforeSE", "D"), test(contentLeft, "PPPbeforeSEDstillbeforeDafter"))
    assertEquals(Some("beforePPPSE", "D"), test(contentLeft, "beforePPPSEDstillbeforePPPDafter"))
    assertEquals(Some("PPPbeforePPPSE", "D"), test(contentLeft, "PPPbeforePPPSEDstillbeforePPPDafter"))

    // Testing Right justification, padding on left removed only
    assertEquals(Some("before", "D"), test(contentRight, "beforeDafter"))
    assertEquals(Some("before", "D"), test(contentRight, "PPPbeforeDafter"))
    assertEquals(Some("beforePPP", "D"), test(contentRight, "beforePPPDafter"))
    assertEquals(Some("beforePPP", "D"), test(contentRight, "PPPbeforePPPDafter"))

    // Testing Right justification, padding on left removed only w/ escaping
    assertEquals(Some("abcEEEEEdef", "D"), test(contentRight, "abcEEEEEdefDghi"))
    assertEquals(Some("abcSESESEdef", "D"), test(contentRight, "abcSESESEdefDghi"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRight, "beforeEDstillbeforeDafter"))
    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRight, "PPPbeforeEDstillbeforeDafter"))
    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRight, "beforePPPEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRight, "PPPbeforePPPEDstillbeforePPPDafter"))

    // Testing Right justification, padding on left removed only w/ escaped escaping
    assertEquals(Some("beforeSE", "D"), test(contentRight, "beforeSEDstillbeforeDafter"))
    assertEquals(Some("beforeSE", "D"), test(contentRight, "PPPbeforeSEDstillbeforeDafter"))
    assertEquals(Some("beforePPPSE", "D"), test(contentRight, "beforePPPSEDstillbeforePPPDafter"))
    assertEquals(Some("beforePPPSE", "D"), test(contentRight, "PPPbeforePPPSEDstillbeforePPPDafter"))
  }

  //  @Test def testParserEscapeSchemes_SameEscapeWithPadding = {
  //    var testNum = 0
  //    def test(theParser: Parser[(String, String)], theInput: String) = {
  //      testNum = testNum + 1
  //      val result = this.parse(this.log(theParser)("testParserEscapeSchemes_SameEscapeWithPadding." + testNum), theInput)
  //      if (result.isEmpty) { None }
  //      else {
  //        val res = result.get
  //        Some(res._1, res._2)
  //      }
  //    }
  //    val escape = """E"""
  //    val delim = """D"""
  //    val padChar = """P"""
  //
  //    val rPadChar = """(%s*)"""
  //    val pPadChar: Parser[String] = rPadChar.format(padChar).r
  //
  //    // (.*?)(?=(?:P+(?<!E)((?:EE)*)(?:P*)(?<!E)(D))|(?:(?<!E)((?:EE)*)(D)))
  //    val rBefore = """(.*?)(?=(?:(?<!%1$s)((%1$s%1$s)*)(%3$s*)(?<!%1$s)(%2$s))|(?<!%1$s)((%1$s%1$s)*)(%2$s))"""
  //    val rBeforeIgnoreTrailingPadding = """(.*?)(?=(?<!%1$s)((%1$s%1$s)*)(%2$s))"""
  //    val pBefore: Parser[String] = rBefore.format(escape, delim, padChar).r
  //    val pBeforeIgnoreTrailingPadding: Parser[String] = rBeforeIgnoreTrailingPadding.format(escape, delim).r
  //
  //    val pDelims: Parser[String] = """D""".r ||| """DD""".r
  //    val pEscape: Parser[String] = """E""".r
  //
  //    val pEscapedEscape = (pEscape ~ pEscape) ^^ { e => (e._1 + e._2) }
  //    val pEscapedDelims = not(pEscapedEscape) ~> (pEscape ~> pDelims)
  //    val pUnescapedDelims = ((pEscapedEscape) ~> pDelims) | (not(pEscape) ~> pDelims) | pDelims
  //
  //    val pEscapes = ((pEscapedEscape*) ~ opt(pEscape)) ^^ {
  //      case (l ~ None) => {
  //        val escEscs = new StringBuilder
  //        l.foreach(x => escEscs.append(x))
  //        (escEscs)
  //      }
  //      case (l ~ Some(esc)) => {
  //        val escEscs = new StringBuilder
  //        l.foreach(x => escEscs.append(x))
  //        (escEscs + esc)
  //      }
  //    }
  //
  //    // Here because of the nature of using the same character for escape and escapeEscape
  //    // we need to capture the escapes
  //    val pBeforeAndEscsIgnoreTrailingPadding = (pBeforeIgnoreTrailingPadding ~ opt(pEscapes)) ^^ {
  //      case (b ~ None) => b
  //      case (b ~ Some(e)) => (b + e)
  //    }
  //
  //    val pBeforeAndEscs = (pBefore ~ opt(pEscapes | pEscapedEscape | pEscape)) ^^ {
  //      case (b ~ None) => b
  //      case (b ~ Some(e)) => (b + e)
  //    }
  //    val content = pBeforeAndEscsIgnoreTrailingPadding ~ pUnescapedDelims ^^ { case (b ~ d) => (b -> d) }
  //    val contentCenterJustified = (((pPadChar ~> pBeforeAndEscs) <~ pPadChar) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
  //    val contentLeftJustified = ((pBeforeAndEscs <~ pPadChar) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
  //    val contentRightJustified = ((pPadChar ~> pBeforeAndEscsIgnoreTrailingPadding) ~ pUnescapedDelims) ^^ { case (b ~ d) => (b -> d) }
  //
  //    assertEquals(Some("textPE", "D"), test(contentCenterJustified, "PPPtextPEPPD"))
  //
  //    // Testing no justification, padding is treated as part of content
  //    assertEquals(Some("before", "D"), test(content, "beforeDafter"))
  //    assertEquals(Some("PPPbefore", "D"), test(content, "PPPbeforeDafter"))
  //    assertEquals(Some("beforePPP", "D"), test(content, "beforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPP", "D"), test(content, "PPPbeforePPPDafter"))
  //
  //    // Testing no justification, padding is treated as part of content w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(content, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcSESESEdef", "D"), test(content, "abcSESESEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(content, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(content, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(content, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPEDstillbeforePPP", "D"), test(content, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing no justification, padding is treated as part of content w/ escaped escaping
  //    assertEquals(Some("beforeEE", "D"), test(content, "beforeEEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEE", "D"), test(content, "PPPbeforeEEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEE", "D"), test(content, "beforePPPEEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPEE", "D"), test(content, "PPPbeforePPPEEDstillbeforePPPDafter"))
  //
  //    // Testing Center justification, padding is not part of content
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "beforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "PPPbeforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "beforePPPDafter"))
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "PPPbeforePPPDafter"))
  //
  //    // Testing Center justification, padding part of content w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(contentCenterJustified, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcEEEEdef", "D"), test(contentCenterJustified, "abcEEEEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenterJustified, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenterJustified, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenterJustified, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenterJustified, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing Center justification, padding is part of content w/ escaped escaping
  //    assertEquals(Some("beforeEE", "D"), test(contentCenterJustified, "beforeEEDstillbeforeDafter"))
  //    assertEquals(Some("beforeEE", "D"), test(contentCenterJustified, "PPPbeforeEEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEE", "D"), test(contentCenterJustified, "beforePPPEEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPEE", "D"), test(contentCenterJustified, "PPPbeforePPPEEDstillbeforePPPDafter"))
  //
  //    // Testing Left justification, padding on right removed only
  //    assertEquals(Some("before", "D"), test(contentLeftJustified, "beforeDafter"))
  //    assertEquals(Some("PPPbefore", "D"), test(contentLeftJustified, "PPPbeforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentLeftJustified, "beforePPPDafter"))
  //    assertEquals(Some("PPPbefore", "D"), test(contentLeftJustified, "PPPbeforePPPDafter"))
  //
  //    // Testing Left justification, padding on right removed only w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(contentLeftJustified, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcEEEEEEdef", "D"), test(contentLeftJustified, "abcEEEEEEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentLeftJustified, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(contentLeftJustified, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentLeftJustified, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPEDstillbefore", "D"), test(contentLeftJustified, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing Left justification, padding on right removed only w/ escaped escaping
  //    assertEquals(Some("beforeEE", "D"), test(contentLeftJustified, "beforeEEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEE", "D"), test(contentLeftJustified, "PPPbeforeEEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEE", "D"), test(contentLeftJustified, "beforePPPEEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPEE", "D"), test(contentLeftJustified, "PPPbeforePPPEEDstillbeforePPPDafter"))
  //
  //    // Testing Right justification, padding on left removed only
  //    assertEquals(Some("before", "D"), test(contentRightJustified, "beforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentRightJustified, "PPPbeforeDafter"))
  //    assertEquals(Some("beforePPP", "D"), test(contentRightJustified, "beforePPPDafter"))
  //    assertEquals(Some("beforePPP", "D"), test(contentRightJustified, "PPPbeforePPPDafter"))
  //
  //    // Testing Right justification, padding on left removed only w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(contentRightJustified, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcEEEEEEdef", "D"), test(contentRightJustified, "abcEEEEEEdefDghi"))
  //    assertEquals(Some("abcEE", "D"), test(contentRightJustified, "abcEEDefDghi"))
  //    assertEquals(Some("abcEEEDef", "D"), test(contentRightJustified, "abcEEEDefDghi"))
  //    assertEquals(Some("abcEEEE", "D"), test(contentRightJustified, "abcEEEEDefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRightJustified, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRightJustified, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRightJustified, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRightJustified, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing Right justification, padding on left removed only w/ escaped escaping
  //    assertEquals(Some("beforeEE", "D"), test(contentRightJustified, "beforeEEDstillbeforeDafter"))
  //    assertEquals(Some("beforeEE", "D"), test(contentRightJustified, "PPPbeforeEEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEE", "D"), test(contentRightJustified, "beforePPPEEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPEE", "D"), test(contentRightJustified, "PPPbeforePPPEEDstillbeforePPPDafter"))
  //
  //    // Testing Escaped Padding
  //    assertEquals(Some("beforeEEPPP", "D"), test(contentRightJustified, "PPPbeforeEEPPPDstillbeforeDafter"))
  //    assertEquals(Some("beforeEPPP", "D"), test(contentRightJustified, "PPPbeforeEPPPDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEE", "D"), test(contentLeftJustified, "PPPbeforeEEPPPDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEP", "D"), test(contentLeftJustified, "PPPbeforeEPPPDstillbeforeDafter"))
  //    assertEquals(Some("beforeEE", "D"), test(contentCenterJustified, "PPPbeforeEEPPPDstillbeforeDafter"))
  //    assertEquals(Some("beforeEP", "D"), test(contentCenterJustified, "PPPbeforeEPPPDstillbeforeDafter"))
  //    assertEquals(Some("EEPPPbeforeEE", "D"), test(contentCenterJustified, "EEPPPbeforeEEPPPDstillbeforeDafter"))
  //    assertEquals(Some("EPPPbeforeEP", "D"), test(contentCenterJustified, "EPPPbeforeEPPPDstillbeforeDafter"))
  //
  //    //    val str =
  //    //        """(?<!%1$s)((?:%1$s%1$s)*)(?:%3$s*)""" + // trim unescaped pad char. aka right or center justified.
  //    //          """(.*?)""" + // content [before]. lazy so it won't absorb pad characters
  //    //          """(?:""" +
  //    //          """(?<!%1$s)((?:%1$s%1$s)*)(?:%3$s*)(?<!%1$s)(%2$s)""" + // trim unescaped pad char. aka left or center justified. Then delim. (and if pad is size zero, then delimiter must be unescaped.)
  //    //          """|""" + // OR
  //    //          """(?<!%1$s)((?:%1$s%1$s)*)(%2$s)""" + // unescaped delimiter [delim] which is delim preceded by NOT an odd number of escapes.
  //    //          """)""" +
  //    //          """(.*)""" // trailing stuff [after]
  //    //      val ContentPattern = str.format(escape, delimiter, padChar).r
  //  }

  //  @Test def testParserEscapeSchemes_DiffEscapesWithPadding = {
  //    var testNum = 0
  //    def test(theParser: Parser[(String, String)], theInput: String) = {
  //      testNum = testNum + 1
  //      val result = this.parse(this.log(theParser)("testParserEscapeSchemes_DiffEscapesWithPadding." + testNum), theInput)
  //      if (result.isEmpty) { None }
  //      else {
  //        val res = result.get
  //        Some(res._1, res._2)
  //      }
  //    }
  //
  //    val escapeEscape = """S"""
  //    val escape = """E"""
  //    val delim = """D"""
  //    val padChar = """P"""
  //
  //    val rPadChar = """(%s*)"""
  //    val pPadChar: Parser[String] = rPadChar.format(padChar).r
  //
  //    val rBefore = """(.*?)(?=(?:%4$s+(?<!(?<!%1$s)%2$s)%3$s)|(?:(?<!(?<!%1$s)%2$s)%3$s))"""
  //    val rBeforeIgnoreTrailingPadding = """(.*?)(?=(?:(?<!(?<!%1$s)%2$s)%3$s))"""
  //    val pBefore: Parser[String] = rBefore.format(escapeEscape, escape, delim, padChar).r
  //    val pBeforeIgnoreTrailingPadding: Parser[String] = rBeforeIgnoreTrailingPadding.format(escapeEscape, escape, delim).r
  //
  //    val pDelims: Parser[String] = """D""".r ||| """DD""".r
  //    val pEscape: Parser[String] = """E""".r
  //    val pEscapeEscape: Parser[String] = """S""".r
  //    val pEscapedEscape = pEscapeEscape ~ pEscape
  //    val pEscapedDelims = not(pEscapedEscape) ~> (pEscape ~> pDelims)
  //    val pUnescapedDelims = ((pEscapeEscape ~ pEscape) ~> pDelims) | (not(pEscape) ~> pDelims) | (pEscapeEscape ~> pDelims) | pDelims
  //
  //    val content = (pBeforeIgnoreTrailingPadding ~ pUnescapedDelims) ^^ { c => (c._1 -> c._2) }
  //    val contentCenterJustified = (((pPadChar ~> pBefore) <~ pPadChar) ~ pUnescapedDelims) ^^ { c => (c._1 -> c._2) }
  //    val contentLeftJustified = ((pBefore <~ pPadChar) ~ pUnescapedDelims) ^^ { c => (c._1 -> c._2) }
  //    val contentRightJustified = ((pPadChar ~> pBeforeIgnoreTrailingPadding) ~ pUnescapedDelims) ^^ { c => (c._1 -> c._2) }
  //
  //    // Testing no justification, padding is treated as part of content
  //    assertEquals(Some("before", "D"), test(content, "beforeDafter"))
  //    assertEquals(Some("PPPbefore", "D"), test(content, "PPPbeforeDafter"))
  //    assertEquals(Some("beforePPP", "D"), test(content, "beforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPP", "D"), test(content, "PPPbeforePPPDafter"))
  //
  //    // Testing no justification, padding is treated as part of content w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(content, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcSESESEdef", "D"), test(content, "abcSESESEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(content, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(content, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(content, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPEDstillbeforePPP", "D"), test(content, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing no justification, padding is treated as part of content w/ escaped escaping
  //    assertEquals(Some("beforeSE", "D"), test(content, "beforeSEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeSE", "D"), test(content, "PPPbeforeSEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPSE", "D"), test(content, "beforePPPSEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPSE", "D"), test(content, "PPPbeforePPPSEDstillbeforePPPDafter"))
  //
  //    // Testing Center justification, padding is not part of content
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "beforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "PPPbeforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "beforePPPDafter"))
  //    assertEquals(Some("before", "D"), test(contentCenterJustified, "PPPbeforePPPDafter"))
  //
  //    // Testing Center justification, padding part of content w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(contentCenterJustified, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcSESESEdef", "D"), test(contentCenterJustified, "abcSESESEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenterJustified, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentCenterJustified, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenterJustified, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentCenterJustified, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing Center justification, padding is part of content w/ escaped escaping
  //    assertEquals(Some("beforeSE", "D"), test(contentCenterJustified, "beforeSEDstillbeforeDafter"))
  //    assertEquals(Some("beforeSE", "D"), test(contentCenterJustified, "PPPbeforeSEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPSE", "D"), test(contentCenterJustified, "beforePPPSEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPSE", "D"), test(contentCenterJustified, "PPPbeforePPPSEDstillbeforePPPDafter"))
  //
  //    // Testing Left justification, padding on right removed only
  //    assertEquals(Some("before", "D"), test(contentLeftJustified, "beforeDafter"))
  //    assertEquals(Some("PPPbefore", "D"), test(contentLeftJustified, "PPPbeforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentLeftJustified, "beforePPPDafter"))
  //    assertEquals(Some("PPPbefore", "D"), test(contentLeftJustified, "PPPbeforePPPDafter"))
  //
  //    // Testing Left justification, padding on right removed only w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(contentLeftJustified, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcSESESEdef", "D"), test(contentLeftJustified, "abcSESESEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentLeftJustified, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeEDstillbefore", "D"), test(contentLeftJustified, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbefore", "D"), test(contentLeftJustified, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPEDstillbefore", "D"), test(contentLeftJustified, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing Left justification, padding on right removed only w/ escaped escaping
  //    assertEquals(Some("beforeSE", "D"), test(contentLeftJustified, "beforeSEDstillbeforeDafter"))
  //    assertEquals(Some("PPPbeforeSE", "D"), test(contentLeftJustified, "PPPbeforeSEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPSE", "D"), test(contentLeftJustified, "beforePPPSEDstillbeforePPPDafter"))
  //    assertEquals(Some("PPPbeforePPPSE", "D"), test(contentLeftJustified, "PPPbeforePPPSEDstillbeforePPPDafter"))
  //
  //    // Testing Right justification, padding on left removed only
  //    assertEquals(Some("before", "D"), test(contentRightJustified, "beforeDafter"))
  //    assertEquals(Some("before", "D"), test(contentRightJustified, "PPPbeforeDafter"))
  //    assertEquals(Some("beforePPP", "D"), test(contentRightJustified, "beforePPPDafter"))
  //    assertEquals(Some("beforePPP", "D"), test(contentRightJustified, "PPPbeforePPPDafter"))
  //
  //    // Testing Right justification, padding on left removed only w/ escaping
  //    assertEquals(Some("abcEEEEEdef", "D"), test(contentRightJustified, "abcEEEEEdefDghi"))
  //    assertEquals(Some("abcSESESEdef", "D"), test(contentRightJustified, "abcSESESEdefDghi"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRightJustified, "beforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforeEDstillbefore", "D"), test(contentRightJustified, "PPPbeforeEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRightJustified, "beforePPPEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPEDstillbeforePPP", "D"), test(contentRightJustified, "PPPbeforePPPEDstillbeforePPPDafter"))
  //
  //    // Testing Right justification, padding on left removed only w/ escaped escaping
  //    assertEquals(Some("beforeSE", "D"), test(contentRightJustified, "beforeSEDstillbeforeDafter"))
  //    assertEquals(Some("beforeSE", "D"), test(contentRightJustified, "PPPbeforeSEDstillbeforeDafter"))
  //    assertEquals(Some("beforePPPSE", "D"), test(contentRightJustified, "beforePPPSEDstillbeforePPPDafter"))
  //    assertEquals(Some("beforePPPSE", "D"), test(contentRightJustified, "PPPbeforePPPSEDstillbeforePPPDafter"))
  //  }

  //  @Test def testParserEscapeSchemes = {
  //    //                escEsc     esc       delim        padChar
  //    //val test = tester("""S""", """E""", """\_*D\_*""", """P""") // put any regex in there for the delimiter
  //    val escapeEscape = """S"""
  //    val escape = """E"""
  //    val delim = """D"""
  //    val padChar = """P"""
  //
  //    val rPadChar = """(%s*)"""
  //    val pPadChar: Parser[String] = rPadChar.format(padChar).r
  //    // (?:(?:(?<!(?:(?<!(?:S))E))(?:D))?)
  //    //
  //    //val rBefore = """(.*?)(?:%4$s*)(?:(?<!(?:(?<!%1$s)%2$s))(%3$s))"""
  //    //val rBefore = """(.*?)"""
  //    //val rBefore = """(.*?)(?:%4$s*)(?:(?:(?<!(?:(?<!(?:%1$s))%2$s))(?:%3$s)(?:.*))?)"""
  //    //val pBefore: Parser[String] = rBefore.format(escapeEscape, escape, delim, padChar).r
  //    //val pBefore = """(.*?)(?=P+)""".r
  //    //val pBefore = """(.*?)(?=P+)""".r
  //    //val pBefore = """(.*?)(?=(?:P+(?<!(?<!S)E)D)|(?:(?<!(?<!S)E)D))""".r
  //
  //    // Before:
  //    // (.*?)(?=(?:P+(?<!(?<!S)E)D)|(?:(?<!(?<!S)E)D))
  //    // Give me everything until Padding followed by an unescaped delimiter OR
  //    // Give me everything until an unescaped delimiter
  //    val rBefore = """(.*?)(?=(?:%4$s+(?<!(?<!%1$s)%2$s)%3$s)|(?:(?<!(?<!%1$s)%2$s)%3$s))"""
  //    val pBefore: Parser[String] = rBefore.format(escapeEscape, escape, delim, padChar).r
  //    val rUnescapedDelim = """(?<!(?:(?<!%1$s)%2$s))(%3$s)"""
  //    val pUnescapedDelim: Parser[String] = rUnescapedDelim.format(escapeEscape, escape, delim).r
  //    val pTrailingStuff: Parser[String] = """(.*)""".r
  //
  //    // We ought to decompose the pUnescapedDelim because we care about longest match
  //    val pDelims: Parser[String] = """D""".r ||| """DD""".r
  //    val pEscape: Parser[String] = """E""".r
  //    val pEscapeEscape: Parser[String] = """S""".r
  //    val pEscapedEscape = pEscapeEscape ~ pEscape
  //    val pEscapedDelims = not(pEscapedEscape) ~> (pEscape ~> pDelims)
  //    val pUnescapedDelims = ((pEscapeEscape ~ pEscape) ~> pDelims) | (not(pEscape) ~> pDelims) | (pEscapeEscape ~> pDelims) | pDelims
  //
  //    //val content = pPadChar ~ pBefore ~ pPadChar //~ pUnescapedDelim ~ pTrailingStuff
  //    val contentCenterJustified = ((pPadChar ~> pBefore) <~ pPadChar) ~ pUnescapedDelim
  //    val content = pBefore ~ pUnescapedDelim
  //    val contentLeftJustified = (pBefore <~ pPadChar) ~ pUnescapedDelim
  //    val contentRightJustified = (pPadChar ~> pBefore) ~ pUnescapedDelim
  //
  //    // Uses decomposed pUnescapedDelim because we care about longest match
  //    val contentCenterJustified2 = ((pPadChar ~> pBefore) <~ pPadChar) ~ pUnescapedDelims
  //
  //    //val result = this.parse(pUnescapedDelims, "SD")
  //    //val result = this.parse(pDelims, "DD") // Longest match
  //    //val result = this.parse(content, "PPPbeforePPPDafter")
  //    //    val result = this.parse(content, "PPPbeforeDafter")
  //    //    val result = this.parse(content, "PPPbeforePPP")
  //    //val result = this.parse(content, "beforeDafter")
  //    //val result = this.parse(contentCenterJustified2, "PPPbefEDorePPPDafter")
  //    val result = this.parse(contentCenterJustified2, "befEDoreDafter")
  //
  //    println(result)
  //
  //    val str =
  //      """(?:%4$s*)""" + // trim pad char. aka right or center justified.
  //        """(.*?)""" + // content [before]. lazy so it won't absorb pad characters
  //        """(?:%4$s*)""" + // trim pad char. aka left or center justified.
  //        """(?:(?<!(?:(?<!%1$s)%2$s))(%3$s))""" + // unescaped delimiter [delim]
  //        """(.*)""" // trailing stuff [after]
  //    val ContentPattern = str.format(escapeEscape, escape, delim, padChar).r
  //
  //    //assertEquals(Some(("before", "D", "after")), test("PPPbeforePPPDafter"))
  //
  //  }

  /**
   * First let's avoid everything about whitespace and use _ (underscores)
   * instead.
   */

  def delim0 = """_*+;_*+""" // greedy whitespace consumption

  def anyUntil(delim: String) = {
    // at begining of string, anything repeated (lazy), followed by the delim
    """^((?>.*?""" + """(?=(?:""" + delim + """))))"""
    // the atomic group begining with (?> is used to reduce possibilities of backtracking
    // but may not be doing anything.
    // There's one capture group here
  }

  // def t0 = log(anyUntil(delim0).r)("before") ~! log(delim0.r)("delim") ~! log("""(.*)""".r)("after")
  def t0 = anyUntil(delim0).r ~! delim0.r ~! """(.*)""".r

  // test data. Stuff including whitespace, followed by the delimiter, followed by more stuff
  // also containing whitespace
  val rdr0 = new StringReader("b e f o r e ___;___ a f t e r")

  lazy val parsed0 = parseAll(t0, rdr0)

  @Test def testParsingDelims() {
    skipWS = false // keep all the whitespace
    assertTrue(parsed0.successful)
    val a = parsed0.get
    // println(a)
    a match {
      // We need 'ending' here, not 'end'
      case (("b e f o r e " ~ "___;___") ~ " a f t e r") => {
        // we're ok
      }
      case _ => fail("not expected result: " + a)
    }
  }

  /**
   * First let's avoid everything about whitespace and use _ (underscores)
   * instead.
   */

  // two regex expressions with common prefix. 2nd is longer of the two
  // so first match would get the shorter match
  def delim1 = ("""_*end_*""".r ||| """_*ending_*""".r)

  def t1 = delim1 ~ "more"

  // test data has our longer delimiter string, followed by more stuff
  val rdr1 = new StringReader("___ending___more")

  lazy val parsed1 = parseAll(t1, rdr1)

  @Test def testRegexNoWSLongestMatch() {
    skipWS = true // this is the default setting for scala comb. parsers, but we have no ws so it doesn't matter really.
    assertTrue(parsed1.successful)
    val a = parsed1.get
    // println(a)
    a match {
      // We need 'ending' here, not 'end'
      case ("___ending___" ~ "more") => {
        // we're ok
      }
      case _ => fail("not expected result: " + a)
    }
  }

  /**
   * Now let's put whitespace absorption into the definition of
   * our delimiters. So we'll turn off scala comb. parser whitespace skipping explicitly.
   */
  // two regex expressions with common prefix. 2nd is longer of the two
  // so first match would get the shorter match
  def endWS = """\s*end\s*""".r // note use \s for whiteSpace. \w is "word character" not whitespace
  def endingWS = """\s*ending\s*""".r
  // def delimWS = (log(endWS)("end") ||| log(endingWS)("ending"))
  def delimWS = (endWS ||| endingWS)

  def t2 = delimWS ~! "more"

  val rdr2 = new StringReader("   ending   more")

  lazy val parsed2 = parseAll(t2, rdr2)

  @Test def testRegexWSLongestMatch() {
    skipWS = false // we want our delimiters to contain the whitespace.
    // (parsed2)
    assertTrue(parsed2.successful)
    val a = parsed2.get
    // println(a)
    a match {
      // We need 'ending' here, not 'end'
      case ("   ending   " ~ "more") => {
        // ok.
      }
      case _ => fail("not expected result: " + a)
    }
  }

  /*
   * Next we have tests that handle complexities of escape schemes of the
   * escape character kind and block escape kind.
   */

  /**
   * Tests a regular experssion to match a delimiter but taking
   * into account escape characters and padChar trimming.
   */
  @Test def testRegexToMatchOneDelimiterWithEscapeChars() {

    /**
     * tester regexps and postprocessing algorithms are different
     * depending on whether you have escapeBlock or escapeCharacter type
     * escaping.
     */
    def tester(escapeEscape: String, escape: String, delim: String, padChar: String) = {
      Assert.usage(padChar.length == 1)
      //
      // Let S be the escape escape character
      // Let E be the escape character
      // Let D be the delimiter
      //
      // (.*?)(?=X) means anything (but looking ahead for X) lazy, not greedy.
      // where X is an unescaped delimiter so
      // X = (?<!Y)D
      // Y is an escape, which itself cannot be escaped
      // Y = (?<!S)E where E is the escape character, preceded by anything but S, the escape
      // escape character.
      //
      // Putting that all together
      //  (.*)(?=(?<!(?<!S)E)D)
      // matches data followed by an unescaped delimiter D.
      //   Note that looking ahead doesn't consume anything.
      //   We're left before the lookahead part of the match.
      // followed by delimiter,
      // followed by anything leftover
      val str =
        """(?:%4$s*)""" + // trim pad char. aka right or center justified.
          """(.*?)""" + // content [before]. lazy so it won't absorb pad characters
          """(?:%4$s*)""" + // trim pad char. aka left or center justified.
          """(?:(?<!(?:(?<!%1$s)%2$s))(%3$s))""" + // unescaped delimiter [delim]
          """(.*)""" // trailing stuff [after]
      val ContentPattern = str.format(escapeEscape, escape, delim, padChar).r
      // println("Pattern = " + ContentPattern.pattern)

      // used to cleanup active escape characters
      val EDSplit = """(.*)%1$s(%2$s)(.*)""".format(escape, delim).r

      /**
       * Really really we want to use the java APIs that let us construct a matcher from
       * a pattern (which 'compiles' the pattern), then use that over and over.
       *
       * This code is just about figuring out the right regex, and putting
       * groups inside it that let us get at what we need.
       */
      def test(x: String) = x match {
        case ContentPattern(before, delim, after) => {
          // println("'%s' parsed to b = '%s', d = '%s', a = '%s'".format(x, before, delim, after))
          val before1 = removeActiveEscapes(before)
          Some((before1, delim, after))
        }
        case z => {
          // println("no match: " + z);
          None
        }
      }

      /**
       * postprocessing to remove active escape characters
       */
      def removeActiveEscapes(str: String): String = {
        // if ends with SE (an escaped escape), then change to end with just E
        // because the S was active.
        val str1 = if (str.endsWith(escapeEscape + escape)) {
          str.slice(0, str.length() - 2) + escape
        } else str
        // if contains ED, replace with just D
        val str2 = removeActiveEscapes1(str1)
        str2
      }

      def removeActiveEscapes1(str: String): String = {
        val res = str match {
          case EDSplit(before, delim, after) => {
            val rest = removeActiveEscapes1(after)
            before + delim + rest
          }
          case _ => str
        }
        res
      }

      test _
    }

    //                escEsc     esc       delim        padChar
    val test = tester("""S""", """E""", """\_*D\_*""", """P""") // put any regex in there for the delimiter

    assertEquals(Some(("before", "D", "after")), test("PPPbeforePPPDafter"))

    // Notice how (.*?) is non-greedy matching. SO we don't get "before_", we get "before"
    assertEquals(Some(("before", "_D_", "after")), test("PPPbefore_D_after"))

    assertEquals(Some(("beforeE", "__D_", "after")), test("PPPbeforeSE__D_after"))

    assertEquals(Some(("beforeDstillBefore", "D", "after")), test("PPPbeforeEDstillBeforePPPDafter"))

    // In the test below. Note that S does NOT escape D.
    assertEquals(Some(("beforeS", "D", "after")), test("PPPbeforeSDafter"))

    // In the test below note that SE is just data because D doesn't follow E
    assertEquals(Some(("beforeSEstillBefore", "D", "after")), test("PPPbeforeSEstillBeforePPPDafter"))

    // to keep out of slash hell, just pretend RN is a \r\n, and N is a \n, and _ is a whitespace.
    //                 escEsc     esc          delim           padChar
    val test2 = tester("""S""", """E""", """(?>RN|\_*N\_*)""", """P""")
    // in the above note careful use of ?> in delim, which is disjunction with no backtracking.

    assertEquals(Some(("before", "RN", "after")), test2("PPPbeforePPPRNafter")) // works because (.*?) is lazy not greedy

    assertEquals(Some(("beforeRNstillBefore", "__N_", "after")), test2("PPPbeforeRENstillBeforePPP__N_after"))

  }

  /**
   * Tests a regular experssion to match a delimiter but taking
   * into account escape characters and padChar trimming.
   *
   * Special case for when EEC and EC are same.
   */
  @Test def testRegexToMatchOneDelimiterWithEscapeCharsWhenEECAndECAreSame() {

    /**
     * tester regexps and postprocessing algorithms are different
     * depending on whether you have escapeBlock or escapeCharacter type
     * escaping.
     */
    def tester(escape: String, delimiter: String, padChar: String) = {
      Assert.usage(padChar.length == 1)
      //
      // Let E be the escape character
      // Let D be the delimiter
      // Let P be the pad char
      //
      // (?<!E)((?:EE)*)P matches unescaped pad characters

      val str =
        """(?<!%1$s)((?:%1$s%1$s)*)(?:%3$s*)""" + // trim unescaped pad char. aka right or center justified.
          """(.*?)""" + // content [before]. lazy so it won't absorb pad characters
          """(?:""" +
          """(?<!%1$s)((?:%1$s%1$s)*)(?:%3$s*)(?<!%1$s)(%2$s)""" + // trim unescaped pad char. aka left or center justified. Then delim. (and if pad is size zero, then delimiter must be unescaped.)
          """|""" + // OR
          """(?<!%1$s)((?:%1$s%1$s)*)(%2$s)""" + // unescaped delimiter [delim] which is delim preceded by NOT an odd number of escapes.
          """)""" +
          """(.*)""" // trailing stuff [after]
      val ContentPattern = str.format(escape, delimiter, padChar).r
      // println("Pattern = " + ContentPattern.pattern)

      // used to cleanup escape characters
      val ERSplit = """(.*?)%1$s(.)(.*)""".format(escape).r

      /**
       * Really really we want to use the java APIs that let us construct a matcher from
       * a pattern (which 'compiles' the pattern), then use that over and over.
       *
       * This code is just about figuring out the right regex, and putting
       * groups inside it that let us get at what we need.
       */
      def test(x: String) = x match {
        case ContentPattern(ee1s, before, ee2s, delimAfterPad, ee3s, delimAfterEEs, after) => {
          //          println("'%s' parsed to ee1s = '%s', b = '%s', ee2s = '%s', delimAfterPad = '%s', ee3s = '%s', delimAfterEEs = '%s', a = '%s'".format(
          //            x, ee1s, before, ee2s, delimAfterPad, ee3s, delimAfterEEs, after))
          val before1 = removeActiveEscapes(
            (if (ee1s == null) "" else ee1s) +
              before +
              (if (ee2s == null) "" else ee2s) +
              (if (ee3s == null) "" else ee3s))
          val delim1 = if (delimAfterPad == null) delimAfterEEs else delimAfterPad
          Some((before1, delim1, after))
        }
        case z => {
          // println("no match: " + z);
          None
        }
      }

      /**
       * postprocessing to remove active escape characters
       */
      // TBD: Are we supposed to remove ALL escape characters?
      // DFDL spec seems to say so. Only escape-escaped escape characters are preserved.
      //
      def removeActiveEscapes(str: String): String = {
        // System.err.println(str)
        // if contains ER, replace with just R
        val str2 = removeActiveEscapes1(str)
        str2
      }

      def removeActiveEscapes1(str: String): String = {
        val res = str match {
          case ERSplit(before, delim, after) => {
            val rest = removeActiveEscapes1(after)
            before + delim + rest
          }
          case _ => str
        }
        res
      }

      test _
    }
    val test3 = tester("""E""", """D""", """P""")
    val test4 = tester("""/""", """;""", """P""")

    assertEquals(Some("before", "D", "after"), test3("beforeDafter"))

    assertEquals(Some("beforeDstillBefore", "D", "after"), test3("beforeEDstillBeforeDafter"))

    assertEquals(Some("beforeE", "D", "after"), test3("beforeEEDafter"))

    assertEquals(Some("beforeEDstillBefore", "D", "after"), test3("beforeEEEDstillBeforeDafter"))

    assertEquals(Some("beforeEE", "D", "after"), test3("beforeEEEEDafter"))

    assertEquals(Some("beforeEE", "D", "after"), test3("PPPbeforeEEEEPPPDafter"))

    // We can escape a pad character (thereby making it "non pad")
    assertEquals(Some("PbeforeP", "D", "after"), test3("PPEPbeforeEPPPDafter"))

    assertEquals(Some("PPPbeforePPP", "D", "after"), test3("PEPPEPbeforeEPPEPDafter"))

    assertEquals(Some("before1EDbefore2", "D", "after"), test3("before1EEEDbefore2Dafter"))
    assertEquals(Some("..../;....", ";", "after"), test4("....///;....;after"))
  }

  /**
   * We assume here that a blockStart must be the very first thing in the string, and a blockEnd the
   * very last before the delimiter. For example, if , is delimiter, and [ and ] are block start and end:
   * @example {{{
   * [aaa,bbb],...
   * }}}is allowed but not
   * @example {{{ aaa[,]bbb,...
   * }}}
   *
   * We also assume that you can escape the block start or block end.
   * Or, if you choose not to use the block escapes, you can still escape the delimiter.
   *
   * Also illustrates how one would add padChar absorbing into the mix on the left, right, or both
   *
   */
  @Test def testRegexToMatchOneDelimiterWithBlockEscapesAndPaddingCharacters() {

    def tester(bStart: String, bEnd: String, escapeEscape: String, escape: String, delim: String, padChar: String) = {
      Assert.usage(padChar.length == 1)
      val str = """(?>""" +
        // First alternative is if the start is an unescaped Block start. In that case you must
        // have an unescaped block end followed directly by an unescaped delimiter as the termination.
        """(?:%6$s*)""" + // trim padChar off on the left. Aka right or center justified.
        """(?<!(?<!%1$s)%2$s)%4$s""" + // unescaped block start
        """(.*)""" + // captured content (before)
        """(?<!(?<!%1$s)%2$s)%5$s""" + // unescaped block end
        """(?:%6$s*)""" + // trim padChar off on the right. aka left or center justified.
        """(?<!(?<!%1$s)%2$s)(%3$s)""" + // unescaped delimiter (delim)
        """(.*)""" + // trailing stuff (after)
        """|""" +
        // Second alternative is if the start is NOT a block start, in which case we are looking
        // for an unescaped delimiter at the end.
        """(?:%6$s*)""" + // trim padChar off. Aka right or center justified.
        """(?<!%4$s)""" + // not a block start
        """(.*?)""" + // lazy content so it won't absorb the padChars (before2)
        """(?:%6$s*)""" + // trim padChar off. aka left or center justified.
        """(?<!(?<!%1$s)%2$s)(%3$s)""" + // unescaped delimiter (delim2)
        """(.*)""" + // trailing stuff (after2)
        """)"""

      val ContentPattern = str.format(escapeEscape, escape, delim, bStart, bEnd, padChar).r
      // println("Pattern = " + ContentPattern.pattern)

      // used to cleanup active escape characters
      val EDSplit = """(.*)%1$s(%2$s)(.*)""".format(escape, delim).r
      val ENSplit = """(.*)%1$s(%2$s)(.*)""".format(escape, bEnd).r

      def test(x: String) = x match {
        case ContentPattern(before, delim, after, null, null, null) => {
          val before1 = removeActiveEscapesBlocked(before)
          //          println("'%s' parsed to b = '%s', d = '%s', a = '%s'".
          //            format(x, before1, delim, after))
          Some((before1, delim, after))
        }
        case ContentPattern(null, null, null, before, delim, after) => {
          val before1 = removeActiveEscapesUnblocked(before)
          //          println("'%s' parsed to b = '%s', d = '%s', a = '%s'".
          //            format(x, before1, delim, after))
          Some((before1, delim, after))
        }
        case z => {
          // println("no match: " + z);
          None
        }
      }

      // postprocessing to remove active escape characters
      def removeActiveEscapesUnblocked(str: String): String = {
        if (str == null) return str
        // if ends with SE (an escaped escape), then change to end with just E
        // because the S was active.
        val str1 = if (str.endsWith(escapeEscape + escape)) {
          str.slice(0, str.length() - 2) + escape
        } else str
        val str2 = if (str.startsWith(escape + bStart)) {
          str1.slice(1, str1.length())
        } else str1
        // if contains ED, replace with just D
        val str3 = removeActiveEscapesUnblocked1(str2)
        str3
      }

      def removeActiveEscapesUnblocked1(str: String): String = {
        val res = str match {
          case EDSplit(before, delim, after) => {
            val rest = removeActiveEscapesUnblocked1(after)
            before + delim + rest
          }
          case _ => str
        }
        res
      }

      // postprocessing to remove active escape characters
      def removeActiveEscapesBlocked(str: String): String = {
        if (str == null) return str
        // if ends with SE (an escaped escape), then change to end with just E
        // because the S was active.
        val str1 = if (str.endsWith(escapeEscape + escape)) {
          str.slice(0, str.length() - 2) + escape
        } else str
        // if contains EN, replace with just N
        val str2 = removeActiveEscapesBlocked1(str1)
        str2
      }

      def removeActiveEscapesBlocked1(str: String): String = {
        val res = str match {
          case ENSplit(before, delim, after) => {
            val rest = removeActiveEscapesBlocked1(after)
            before + delim + rest
          }
          case _ => str
        }
        res
      }

      test _
    }

    //                blkStart blkEnd   escEsc   esc      delim    padChar
    val test = tester("""T""", """N""", """S""", """E""", """D""", """P""")

    // This particular regex lets you escape either the blockstart or blockend, or the delimiter

    // no blockstart/end
    assertEquals(Some(("before", "D", "after")), test("PPPbeforePPPDafter"))

    // no blockstart/end, but escape the delimiter
    assertEquals(Some(("beforeDstillBefore", "D", "after")), test("PPPbeforeEDstillBeforePPPDafter"))

    // with blockstart/end
    assertEquals(Some(("beforeDstillBefore", "D", "after")), test("PPPTbeforeDstillBeforeNPPPDafter"))

    // with blockstart/end and esc and escEsc found inside (where they are inactive)
    assertEquals(Some(("beforeEDstillBeforeSEDstillBefore", "D", "after")), test("PPPTbeforeEDstillBeforeSEDstillBeforeNPPPDafter"))
    // Note: in the above, the SED is ok. No postprocessing. It is escaped in entirety by the T---N pair.

    // with blockstart/end, escape the first block end
    assertEquals(Some(("beforeDstillBeforeNstillBefore", "D", "after")), test("PPPTbeforeDstillBeforeENstillBeforeNPPPDafter"))

    // with blockstart/end, escapeEscape the escape of the first block end
    assertEquals(Some(("beforeDstillBeforeTstillBeforeE", "D", "after")), test("PPPTbeforeDstillBeforeTstillBeforeSENPPPDafter"))

    // with blockstart, but escape it so it's not really a block.
    assertEquals(Some(("Tbefore", "D", "afterNstillafter")), test("PPPETbeforePPPDafterNstillafter"))
  }

}
