/*
 * RiskScape™ Copyright New Zealand Institute for Earth Science Limited
 * (Earth Sciences New Zealand) is distributed for research purposes only
 * under the terms of AGPLv3.
 *
 * RiskScape™ Copyright 2026 New Zealand Institute for Earth Science
 * Limited (Earth Sciences New Zealand). All rights reserved. Source code
 * available under the AGPLv3.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 *  the terms of the GNU Affero General Public License as published by the Free
 *  Software Foundation, either version 3 of the License, or (at your option) any
 *  later version.
 * 
 * This program is distributed for RESEARCH PURPOSES ONLY, in the hope that it will
 * be useful for research and education initiatives.
 * 
 * If you are not a researcher, or you are a researcher who wishes to use this
 * program on terms other than AGPLv3 (including those who wish to restrict the
 * distribution of any source code created using this program), please contact:
 * https://riskscape.org.nz
 * 
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Affero General Public License for more details.  You should have received a copy
 * of the GNU Affero General Public License along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 * 
 * By way of summary only, under the AGPLv3:
 *     • Permissions of this strongest copyleft license are conditioned
 *       on making available complete source code of licensed works and
 *       modifications, which include larger works using a licensed work,
 *       under the same license.
 *     • Copyright and license notices must be preserved.
 *     • Contributors provide an express grant of patent rights.
 *     • When a modified version is used to provide a service over a
 *       network, the complete source code of the modified version must be made
 *       available.
 */
package nz.org.riskscape.engine.ini;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Set;

import org.ini4j.Config;
import org.ini4j.Ini;
import org.ini4j.Profile.Section;

import nz.org.riskscape.engine.RiskscapeIOException;

/**
 * Provides methods to parse INI files with defined settings
 * - multi section enabled allowing duplicate sections and keys
 * - escape new lines allowing values to span multiple lines
 * - set escape false, so Windows paths don't need excessive escaping.
 */
public class IniParser {

  /**
   * Parses resource at {@link URI} as INI format.
   * @param uri to object ini content from
   * @return ini
   * @throws RiskscapeIOException if input is not valid INI format or not accessible
   */
  public static Ini parse(URI uri) throws RiskscapeIOException {
    try {
      return parse(uri.toURL().openStream());
    } catch (IOException e) {
      throw new RiskscapeIOException("Could not load INI resource. Cause: " + e.getMessage(), e);
    }
  }

  /**
   * Parses {@link InputStream} as INI format.
   * @param input stream to parse
   * @return ini
   * @throws RiskscapeIOException if input is not valid INI format or not accessible
   */
  public static Ini parse(InputStream input) throws RiskscapeIOException {
    try {
      Ini ini = new Ini();
      // we enable multi section just so we can detect its use and tell the user off
      Config config = new Config();
      config.setMultiSection(true);
      config.setEscape(false);  //Bookmark files should not have characters that need escaping
                                //and we don't want users to have to escape Windows path separaters. EG "\"
      config.setEscapeNewline(true);
      ini.setConfig(config);
      ini.load(input);
      return ini;
    } catch (IOException e) {
      throw new RiskscapeIOException("Could not load INI resource. Cause: " + e.getMessage(), e);
    }
  }

  /**
   * Helper method for converting an ini section to a map, preserving all the values with the same key, but losing all
   * the ordering information.
   */
  public static LinkedHashMap<String, List<?>> toMap(Section section) {
    Set<String> keySet = section.keySet();
    LinkedHashMap<String, List<?>> toReturn = new LinkedHashMap<>(section.size());

    for (String key : keySet) {
      toReturn.put(key, section.getAll(key));
    }

    return toReturn;
  }

}
