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

import scala.xml.Node
import scala.xml.NodeSeq
import org.apache.daffodil.xml.QName
import org.apache.daffodil.xml.XMLUtils
import org.apache.daffodil.xml.NamedQName

final class DFDLProperty(xmlArg: Node, formatAnnotation: DFDLFormatAnnotation)
  extends DFDLAnnotation(xmlArg, formatAnnotation.annotatedSC)
  with LocalNonElementComponentMixin {

  override lazy val namedQName: NamedQName = QName.createGlobal(name, XMLUtils.DFDL_NAMESPACE, xml.scope)

  override lazy val path = formatAnnotation.path + "::" + diagnosticDebugName

  //  override lazy val schemaComponent: LookupLocation = formatAnnotation.annotatedSC
  //
  //  override lazy val schemaDocument = formatAnnotation.schemaDocument
  //  override lazy val uriString = xmlSchemaDocument.uriString

  // TODO: if we grab the value from here, then any qnames inside that value
  // have to be resolved by THIS Object
  lazy val value = {
    lazy val values: Option[NodeSeq] = xml match {
      case <dfdl:property/> => None
      case <daf:property/> => None
      case <dfdl:property>{ valueNodes @ _* }</dfdl:property> => Some(valueNodes)
      case <daf:property>{ valueNodes @ _* }</daf:property> => Some(valueNodes)
    }

    values match {
      case None => ""
      case Some(valueNodes) => {
        //
        // We have to implement our own trim logic.
        // and that is somewhat subtle. E.g., textNumberPattern where
        // spaces are meaningful active characters. lengthPattern,
        // assert patterns, etc.
        //
        // Inside dfdl:property, since it is an element, XML's typical
        // whitespace fungibility applies. So use CDATA if you care
        // about space inside these.
        //
        val values = valueNodes.flatMap { valueNode =>
          valueNode match {
            case scala.xml.PCData(s) => Some(valueNode)
            case scala.xml.Text(s) => {
              if (s.matches("""\s+""")) {
                // all whitespace. Remove the node.
                None
              } else {
                val trimmed = s.trim
                if (trimmed.length == 0) None
                else Some(scala.xml.Text(trimmed))
              }
            }
            case scala.xml.Comment(_) => None
            case scala.xml.EntityRef(_) => Some(valueNode)
            case _: scala.xml.Atom[_] => Some(valueNode) // &lt; comes through as this... should be EntityRef
          }
        }
        val res = values.map { _.text }.mkString
        res
      }
    }
  }

  // override lazy val name = getAttributeRequired("name")

}
