/***********************************************************************
 * Copyright (c) 2013-2025 Commonwealth Computer Research, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, Version 2.0
 * which accompanies this distribution and is available at
 * http://www.opensource.org/licenses/apache2.0.php.
 ***********************************************************************/

package org.locationtech.geomesa.utils.conf

import com.typesafe.scalalogging.LazyLogging

import java.io.InputStream
import scala.util.control.NonFatal
import scala.util.{Failure, Try}
import scala.xml.XML

object ConfigLoader extends LazyLogging {

  val GEOMESA_CONFIG_FILE_PROP = "geomesa.config.file"
  val GEOMESA_CONFIG_FILE_NAME = "geomesa-site.xml"

  lazy val Config: Map[String, (String, Boolean)] =
    loadConfig(sys.props.getOrElse(GEOMESA_CONFIG_FILE_PROP, GEOMESA_CONFIG_FILE_NAME))

  def loadConfig(path: String): Map[String, (String, Boolean)] = {
    val input = getClass.getClassLoader.getResourceAsStream(path)
    val config: Map[String, (String, Boolean)] =
      if (input == null) {
        Map.empty
      } else {
        try {
          logger.debug(s"Loading config: $path")
          loadConfig(input, path)
        } catch {
          case NonFatal(e) =>
            logger.warn(s"Error reading config file at: $path", e)
            Map.empty
        }
      }
    logger.trace(s"Loaded ${config.mkString(",")}")
    config
  }

  def loadConfig(input: InputStream, path: String): Map[String, (String, Boolean)] = {
    val xml = XML.load(input)
    val properties = xml \\ "configuration" \\ "property"
    properties.flatMap { prop =>
      // Use try here so if we fail on a property the rest can still load
      val pair = Try {
        val key = (prop \ "name").text
        val value = (prop \ "value").text
        // don't overwrite properties, this gives commandline params preference
        val isFinal: Boolean = java.lang.Boolean.parseBoolean((prop \ "final").text)
        key -> (value, isFinal)
      }
      pair match {
        case Failure(e) => logger.warn(s"Unable to load property from: $path\n$prop", e)
        case _ => // no-op
      }
      pair.toOption.filter { case (_, (v, _)) => v != null && v.nonEmpty }
    }.toMap
  }
}
