package de.duehl.basics.text.xml;

/*
 * Copyright 2016 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.util.List;

import de.duehl.basics.text.Text;

/**
 * Diese Klasse kann XML-Parameter aus öffnenden XML-Tags extrahieren. Bei gegebenen XML
 *     <tag param1="1" param2="zwei">
 * würden hier die beiden Parameter mit den Namen "param1" und "param2" und den Werten "1" bzw.
 * "zwei" extrahiert.
 *
 * @version 1.01     2016-12-14
 * @author Christian Dühl
 */

public class XmlParameterExtractor {

    /** Zeilen aus einer XML-Datei, in der ersten davon muss der öffnende Tag sein. */
    private final List<String> xml;

    /** Tag dessen Id gesucht wird, muss in der ersten Zeile von xml stehen. */
    private final String tag;

    /**
     * Konstruktor.
     *
     * @param xml
     *            Zeilen aus einer XML-Datei, in der ersten davon muss der öffnende Tag sein.
     * @param tag
     *            Tag dessen Id gesucht wird, muss in der ersten Zeile von xml stehen.
     */
    public XmlParameterExtractor(List<String> xml, String tag) {
        this.xml = xml;
        this.tag = tag;
    }

    /**
     * Extrahiert alle Parameter des öffnenden Tags aus der ersten Zeile der XML-Zeilen.
     *
     * @return Liste aller Xml-Parameter.
     */
    public List<NamedXmlParameter> extractParameters() {
        String openingTagLine = xml.get(0);
        List<NamedXmlParameter> parameters = XmlAnalyser.getParametersFromOpeningTag(
                openingTagLine, tag);

        return parameters;
    }

    /**
     * Extrahiert alle Parameter des öffnenden Tags aus der ersten Zeile der XML-Zeilen.
     *
     * @param numberOfParameters
     *            Anzahl der erwarteten Parameter
     * @return Liste aller Xml-Parameter.
     */
    public List<NamedXmlParameter> extractParametersAndCheckNumberOfParameters(
            int numberOfParameters) {
        List<NamedXmlParameter> parameters = extractParameters();

        if (parameters.size() != numberOfParameters) {
            throw new RuntimeException("Es wurde nicht wie gewünscht " + numberOfParameters
                    + " Parameter im öffnenden Tag '" + tag + "' gefunden, sondern "
                    + parameters.size() + ". Die zu anlysierenden Zeilen sind:\n\t"
                    + Text.join("\n\t", xml));
        }

        return parameters;
    }

    /**
     * Extrahiert einen bestimmten Parameter mit dem angegebenen Namen aus der ersten Zeile der
     * XML-Zeilen.
     *
     * @param parameterName
     *            Name des gesuchten Parameters.
     * @return Gesuchter Parameter.
     */
    public NamedXmlParameter extractSpecialParameter(String parameterName) {
        List<NamedXmlParameter> parameters = extractParameters();

        return findTheWantedParameter(parameterName, parameters);
    }

    /**
     * Extrahiert einen bestimmten Parameter mit dem angegebenen Namen aus der ersten Zeile der
     * XML-Zeilen.
     *
     * @param parameterName
     *            Name des gesuchten Parameters.
     * @return Gesuchter Parameter.
     */
    public NamedXmlParameter extractSpecialParameterAndCheckNumberOfParametersIsOne(
            String parameterName) {
        List<NamedXmlParameter> parameters = extractParametersAndCheckNumberOfParameters(1);

        return findTheWantedParameter(parameterName, parameters);
    }

    /**
     * Sucht den gewünschten Parameter heraus.
     *
     * @param parameterName
     *            Name des gesuchten Parameters.
     * @param parameters
     *            Parameter in denen gesucht wird.
     * @return Gewünschter Parameter
     */
    private NamedXmlParameter findTheWantedParameter(String parameterName,
            List<NamedXmlParameter> parameters) {
        for (NamedXmlParameter parameter : parameters) {
            String name = parameter.getName();
            if (name.equals(parameterName)) {
                return parameter;
            }
        }

        throw new RuntimeException("Es wurde kein Parameter mit dem Namen '" + parameterName
                + "' im öffnenden Tag '" + tag + "' gefunden. Die zu anlysierenden Zeilen sind:\n\t"
                + Text.join("\n\t", xml));
    }

}
