/*
 * 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.api

import org.apache.daffodil.exceptions.Assert
import org.apache.daffodil.schema.annotation.props.gen.ParseUnparsePolicy
import org.apache.daffodil.util.LogLevel
import org.apache.daffodil.util.Logging
import org.apache.daffodil.util.Misc
import org.apache.daffodil.xml.DaffodilXMLLoader

object DaffodilTunables {

  def apply(tunables: Map[String, String]): DaffodilTunables = {
    apply().setTunables(tunables)
  }

  def apply(tunable: String, value: String): DaffodilTunables = {
    apply().setTunable(tunable, value)
  }

  def apply(): DaffodilTunables = {
    // override tunables from the global configuration file on the class path, if it exists
    val (configOpt, _) = Misc.getResourceOption("/daffodil-config.xml")
    val configTunables: Map[String, String] =
      if (configOpt.isDefined) {
        val loader = new DaffodilXMLLoader()
        val node = loader.load(new URISchemaSource(configOpt.get))
        val trimmed = scala.xml.Utility.trim(node)
        val tunablesNode = (trimmed \ "tunables").headOption
        val tunablesMap: Map[String, String] = tunablesNode match {
          case None => Map.empty
          case Some(tunableNode) => {
            tunableNode.child.map { n => (n.label, n.text) }.toMap
          }
        }
        tunablesMap
      } else {
        Map.empty
      }

    new DaffodilTunables().setTunables(configTunables)
  }
}

case class DaffodilTunables(
  val maxSkipLengthInBytes: Long = 1024, // applicable to leadingSkip and trailingSkip
  val maxBinaryDecimalVirtualPoint: Int = 200, // Can be as large as Int.MaxValue
  val minBinaryDecimalVirtualPoint: Int = -200, // Can be as small as Int.MinValue
  val generatedNamespacePrefixStem: String = "tns",
  val readerByteBufferSize: Long = 8192,
  //
  // If true, require that the bitOrder property is specified. If false, use a
  // default value for bitOrder if not defined in a schema
  //
  // Looks to be compile-time as it gets 'tunable' from Term.
  //
  val requireBitOrderProperty: Boolean = false,
  //
  // If true, require that the encodingErrorPolicy property is specified. If
  // false, use a default value not defined in a schema
  //
  // Looks to be compile-time as it gets 'tunable' from Term.
  //
  val requireEncodingErrorPolicyProperty: Boolean = false,
  //
  // Whether to compile a schema to support parsing, unparsing, both, or to use
  // the daf:parseUnparsePolicy from the root node. None means to use the
  // policy from the schema, otherwise use whatever the value is
  //
  // Looks to be compile-time. Set in Compiler.
  ///
  val parseUnparsePolicy: Option[ParseUnparsePolicy] = None,
  val maxFieldContentLengthInBytes: Long = 1024 * 1024, // Can be as large as Int.MaxValue
  val defaultInitRegexMatchLimitInChars: Long = 32,
  val maxDataDumpSizeInBytes: Long = 256,
  val maxOccursBounds: Long = 1024, // Can be as large as Int.MaxValue
  //
  // When unexpected text is found where a delimiter is expected, this is the maximum
  // number of bytes (characters) to display when the expected delimiter is a variable
  // length delimiter.
  //
  val maxLengthForVariableLengthDelimiterDisplay: Int = 10, // will display this number of bytes
  //
  // In certain I/O optimized situations (text-only, encodingErrorPolicy='replace', fixed-width encoding)
  // input files larger than this will be mmapped. Input files smaller than this
  // will be simply read using ordinary I/O (because for small files that is just faster).
  // This exists because mmap is more expensive than ordinary I/O for small files.
  //
  val inputFileMemoryMapLowThreshold: Long = 32 * 1024 * 1024, // 32Meg
  //
  // TODO: In the future, when we can stream and handle input larger than the JVM single
  // object limits, input files larger than this will be streamed, i.e., using java.io.InputStream.
  // They will not be memory mapped. A CharBuffer 2x larger may be created, and that
  // cannot exceed the JVM maximum size, so this has to be no bigger (and perhaps quite a bit
  // smaller) than 1/2 the maximum JVM object size.
  //
  // val inputFileMemoryMapHighThreshold: Long = 256 * 1024 * 1024, // 256 Meg
  
  //
  // Initial array buffer size allocated for recurring elements (aka arrays)
  //
  // Applies to InfosetImpl, as such is a run-time thing
  //
  val initialElementOccurrencesHint: Long = 10,
  val unqualifiedPathStepPolicy: UnqualifiedPathStepPolicy.Type = UnqualifiedPathStepPolicy.NoNamespace,
  val suppressSchemaDefinitionWarnings: List[WarnID] = Nil,

  // By default, path expressions in Daffodil will only work correctly if path
  // steps are used in an expression defined in the schema when compiled. To
  // enable the use of other expressions (e.g. during debugging, where not all
  // expressions are known at schema compile time), set this tunable to true.
  // This may cause a degredation of performance in path expression evaluation,
  // so this should be avoided when in production. This flag is automatically
  // enabled when debugging is enabled.
  val allowExternalPathExpressions: Boolean = false,

  // A bug exists in Java 7 that causes unexpected behavior when decode errors
  // occur in the specific ways that Daffodil decodes data. For this reason,
  // Daffodil throws an exception when it detects that Daffodil is not running
  // under Java 8 or has this decoder bug. However, there are some cases where
  // a user has no choice but to run on Java 7. Setting this tunable to false
  // will cause Daffodil to log a warning rather than throw an exception so
  // that a user can run Daffodil on unsupported Java versions, with the
  // understanding that it is not fully tested and behavior may not be well
  // defined. This boolean is experimental and should only be used by those
  // that fully understand the risks.
  val errorOnUnsupportedJavaVersion: Boolean = true)
  extends Serializable
  with Logging
  with DataStreamLimits {

  /* Appear to be Compile-Time as the tunable is obtained from:
   *  Term, SchemaComponent, Element, etc.
   * 
   *  maxSkipLengthInBytes
   *  maxBinaryDecimalVirtualPoint
   *  minBinaryDecimalVirtualPoint
   *  requireEncodingErrorPolicyProperty
   *  requireBitOrderProperty
   *  generatedNamespacePrefixStem
   *  parseUnparsePolicy
   * 
   * Used by StepQNameFactory.  Appears to get tunable from:
   *  Expressions's DPathCompileInfo
   *  CompiledExpression's ElementRuntimeData
   *  
   *  unqualifiedPathStepPolicy
   * 
   * Appear to be Run-Time as the tunable is obtained from:
   *  PState/UState
   *  
   *  initialElementOccurrencesHint
   *  maxOccursBounds
   *  maxDataDumpSizeInBytes
   *  
   * Only used in Main.scala for DataInputStream:
   * 
   *  maxFieldContentLengthInBytes
   *  
   * DataInputStream objects:
   * 
   *  defaultInitRegexMatchLimitInChars
   *  
   * Unused?
   * 
   *  maxLengthForVariableLengthDelimiterDisplay
   * 
   *  */

  def setTunables(tunables: Map[String, String]): DaffodilTunables = {
    var t = this
    tunables.foreach { case (k, v) => t = t.setTunable(k, v) }
    t
  }

  def setTunable(tunable: String, value: String): DaffodilTunables = {
    tunable.toLowerCase match {
      case "maxfieldcontentlengthinbytes" => this.copy(maxFieldContentLengthInBytes = java.lang.Long.valueOf(value))
      case "defaultinitialregexmatchlimitinchars" => this.copy(defaultInitRegexMatchLimitInChars = java.lang.Long.valueOf(value))
      case "maxdatadumpsizeinbytes" => this.copy(maxDataDumpSizeInBytes = java.lang.Long.valueOf(value))
      case "maxoccursbounds" => this.copy(maxOccursBounds = java.lang.Long.valueOf(value))
      case "maxlengthforvariablelengthdelimiterdisplay" => this.copy(maxLengthForVariableLengthDelimiterDisplay = java.lang.Integer.valueOf(value))
      case "inputfilememorymaplowthreshold" => this.copy(inputFileMemoryMapLowThreshold = java.lang.Long.valueOf(value))
      case "initialelementoccurrenceshint" => this.copy(initialElementOccurrencesHint = java.lang.Long.valueOf(value))
      case "unqualifiedpathsteppolicy" => {
        val policy = value.toLowerCase match {
          case "nonamespace" => UnqualifiedPathStepPolicy.NoNamespace
          case "defaultnamespace" => UnqualifiedPathStepPolicy.DefaultNamespace
          case "preferdefaultnamespace" => UnqualifiedPathStepPolicy.PreferDefaultNamespace
          case _ => Assert.usageError("Unknown value for unqualifiedPathStepPolicy tunable. Value must be \"noNamespace\", \"defaultNamespace\", or \"perferDefaultNamespace\".")
        }
        this.copy(unqualifiedPathStepPolicy = policy)
      }
      case "requirebitorderproperty" => this.copy(requireBitOrderProperty = java.lang.Boolean.valueOf(value))
      case "requireencodingerrorpolicyproperty" => this.copy(requireEncodingErrorPolicyProperty = java.lang.Boolean.valueOf(value))
      case "maxskiplengthinbytes" => this.copy(maxSkipLengthInBytes = java.lang.Long.valueOf(value))
      case "maxbinarydecimalvirtualpoint" => this.copy(maxBinaryDecimalVirtualPoint = java.lang.Integer.valueOf(value))
      case "minbinarydecimalvirtualpoint" => this.copy(minBinaryDecimalVirtualPoint = java.lang.Integer.valueOf(value))
      case "generatednamespaceprefixstem" => this.copy(generatedNamespacePrefixStem = value)
      case "readerbytebuffersize" => this.copy(readerByteBufferSize = java.lang.Long.valueOf(value))
      case "parseunparsepolicy" => {
        val policy = value.toLowerCase match {
          case "parseonly" => Some(ParseUnparsePolicy.ParseOnly)
          case "unparseonly" => Some(ParseUnparsePolicy.UnparseOnly)
          case "both" => Some(ParseUnparsePolicy.Both)
          case "schema" => None
          case _ => Assert.usageError("Unknown value for parseUnparsePolicy tunable. Value must be \"parseOnly\", \"unparseOnly\", \"both\", or \"schema\".")
        }
        this.copy(parseUnparsePolicy = policy)
      }
      case "suppressschemadefinitionwarnings" => {
        val ws = """\s+"""
        // value is whitespace separated list of warning identifier strings
        val warnIDs = value.split(ws).toSeq

        var warningsList: List[WarnID] = Nil
        warnIDs.foreach { warnIDString =>
          {
            WarnID.find(warnIDString) match {
              case None => log(LogLevel.Warning, "Ignoring unknown warning identifier: %s", warnIDString)
              case Some(foundID) => warningsList = foundID :: warningsList
            }
          }
        }
        this.copy(suppressSchemaDefinitionWarnings = warningsList)
      }
      case "allowexternalpathexpressions" => this.copy(allowExternalPathExpressions = java.lang.Boolean.valueOf(value))
      case "erroronunsupportedjavaversion" => this.copy(errorOnUnsupportedJavaVersion = java.lang.Boolean.valueOf(value))
      case _ => {
        log(LogLevel.Warning, "Ignoring unknown tunable: %s", tunable)
        this
      }
    }
  }

  def notSuppressedWarning(warnID: WarnID) =
    !suppressSchemaDefinitionWarnings.contains(warnID) &&
      !suppressSchemaDefinitionWarnings.contains(WarnID.All)

  def maximumSimpleElementSizeInBytes: Long = this.maxFieldContentLengthInBytes
  def maximumSimpleElementSizeInCharacters: Long = this.maxFieldContentLengthInBytes
  def maximumForwardSpeculationLengthInBytes: Long = this.maxFieldContentLengthInBytes
  def maximumRegexMatchLengthInCharacters: Long = this.maxFieldContentLengthInBytes
  def defaultInitialRegexMatchLimitInChars: Long = this.defaultInitRegexMatchLimitInChars

}
