/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.jaspic.config.factory;

import com.sun.jaspic.config.helper.JASPICLogManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import jakarta.security.auth.message.config.AuthConfigFactory.RegistrationContext;


/**
 * Used by GFServerConfigProvider to parse the configuration file. If
 * a file does not exist originally, the default providers are not used.
 * A file is only created if needed, which happens if providers are
 * registered or unregistered through the store() or delete() methods.
 *
 * @author Bobby Bissett
 */
public final class RegStoreFileParser {

    private static final Logger logger =
            Logger.getLogger(JASPICLogManager.JASPIC_LOGGER, JASPICLogManager.RES_BUNDLE);

    private static final String SEP = ":";
    private static final String CON_ENTRY = "con-entry";
    private static final String REG_ENTRY = "reg-entry";
    private static final String REG_CTX = "reg-ctx";
    private static final String LAYER = "layer";
    private static final String APP_CTX = "app-ctx";
    private static final String DESCRIPTION = "description";
    private static final String [] INDENT = { "", "  ", "    " };

    private final File confFile;
    private List<EntryInfo> entries;
    private List<EntryInfo> defaultEntries;

    /*
     * Loads the configuration file from the given filename.
     * If a file is not found, then the default entries
     * are used. Otherwise the file is parsed to load the entries.
     *
     */
    public RegStoreFileParser(String pathParent, String pathChild,List<EntryInfo> defaultEntries) {
        confFile = new File(pathParent, pathChild);
        this.defaultEntries = defaultEntries == null ? new ArrayList<EntryInfo>() : defaultEntries;
        try {
            loadEntries();
        } catch (IOException ioe) {
            logWarningDefault(ioe);
        } catch (IllegalArgumentException iae) {
            logWarningDefault(iae);
        }
    }

    private void logWarningUpdated(Exception exception) {
        if (logger.isLoggable(Level.WARNING)) {
            logger.log(Level.WARNING,
                "jmac.factory_could_not_persist", exception.toString());
        }
    }

    private void logWarningDefault(Exception exception) {
        if (logger.isLoggable(Level.WARNING)) {
            logger.log(Level.WARNING,
                "jmac.factory_could_not_read", exception.toString());
        }
    }

    /*
     * Returns the in-memory list of entries.
     * MUST Hold exclusive lock on calling factory while processing entries
     */
    List<EntryInfo> getPersistedEntries() {
        return entries;
    }

    /*
     * Adds the provider to the entry list if it is not already
     * present, creates the configuration file if necessary, and
     * writes the entries to the file.
     */
    void store(String className, RegistrationContext ctx, Map properties) {
        synchronized (confFile) {
            if (checkAndAddToList(className, ctx, properties)) {
                try {
                    writeEntries();
                } catch (IOException ioe) {
                    logWarningUpdated(ioe);
                }
            }
        }
    }

    /*
     * Removes the provider from the entry list if it is already
     * present, creates the configuration file if necessary, and
     * writes the entries to the file.
     */
    void delete(RegistrationContext ctx) {
        synchronized (confFile) {
            if (checkAndRemoveFromList(ctx)) {
                try {
                    writeEntries();
                } catch (IOException ioe) {
                    logWarningUpdated(ioe);
                }
            }
        }
    }

    /*
     * If this entry does not exist, this method stores it in
     * the entries list and returns true to indicate that the
     * configuration file should be written.
     */
    private boolean checkAndAddToList(String className,
        RegistrationContext ctx, Map props) {

        // convention is to use null for empty properties
        if (props != null && props.isEmpty()) {
            props = null;
        }
        EntryInfo newEntry = new EntryInfo(className, props, ctx);
        EntryInfo entry = getMatchingRegEntry(newEntry);

        // there is no matching entry, so add to list
        if (entry == null) {
            entries.add(newEntry);
            return true;
        }

        // otherwise, check reg contexts to see if there is a match
        if (entry.getRegContexts().contains(ctx)) {
            return false;
        }

        // no matching context in existing entry, so add to existing entry
        entry.getRegContexts().add(new RegistrationContextImpl(ctx));
        return true;
    }

    /*
     * If this registration context does not exist, this method
     * returns false. Otherwise it removes the entry and returns
     * true to indicate that the configuration file should be written.
     *
     * This only makes sense for registry entries.
     */
    private boolean checkAndRemoveFromList(RegistrationContext target) {
        boolean retValue = false;
        try {
            ListIterator<EntryInfo> lit = entries.listIterator();
            while (lit.hasNext()) {

                EntryInfo info = lit.next();
                if (info.isConstructorEntry()) {
                    continue;
                }

                Iterator<RegistrationContext> iter =
                        info.getRegContexts().iterator();
                while (iter.hasNext()) {
                    RegistrationContext ctx = iter.next();
                    if (ctx.equals(target)) {
                        iter.remove();
                        if (info.getRegContexts().isEmpty()) {
                            lit.remove();
                        }
                        retValue = true;
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return retValue;
    }

    /*
     * Used to find a matching registration entry in the 'entries'
     * list without including registration contexts. If there is not
     * a matching entry, return null.
     */
    private EntryInfo getMatchingRegEntry(EntryInfo target) {
        for (EntryInfo info : entries) {
            if (!info.isConstructorEntry() && info.matchConstructors(target)) {
                return info;
            }
        }
        return null;
    }

    /*
     * This method overwrites the existing file with the
     * current entries.
     */
    private void writeEntries() throws IOException {
        if (confFile.exists() && !confFile.canWrite()
                && logger.isLoggable(Level.WARNING)) {
            logger.log(Level.WARNING, "jmac.factory_cannot_write_file",
                    confFile.getPath());
        }
        clearExistingFile();
        PrintWriter out = new PrintWriter(confFile);
        int indent = 0;
        for (EntryInfo info : entries) {
            if (info.isConstructorEntry()) {
                writeConEntry(info, out, indent);
            } else {
                writeRegEntry(info, out, indent);
            }
        }
        out.close();
    }

    /*
     * Writes constructor entry output of the form:
     * <pre>
     * con-entry {
     *   className
     *   key:value
     *   key:value
     * }
     * </pre>
     * The first appearance of a colon ":" separates
     * the key and value of the property (so a value may
     * contain a colon as part of the string). For instance:
     * "mydir:c:foo" would have key "mydir" and value "c:foo".
     */
    private void writeConEntry(EntryInfo info, PrintWriter out, int i) {
        out.println(INDENT[i++] + CON_ENTRY + " {");
        out.println(INDENT[i] + info.getClassName());
        Map<String, String> props = info.getProperties();
        if (props != null) {
            for (Map.Entry<String,String> val : props.entrySet()) {
                out.println(INDENT[i] + val.getKey() + SEP + val.getValue());
            }
        }
        out.println(INDENT[--i] + "}");
    }

    /*
     * Write registration entry output of the form:
     * <pre>
     * reg-entry {
     *   con-entry { see writeConEntry() for detail }
     *   reg-ctx {
     *     layer:HttpServlet
     *     app-ctx:security-jmac-https
     *     description:My provider
     *   }
     * }
     * </pre>
     */
    private void writeRegEntry(EntryInfo info, PrintWriter out, int i) {
        out.println(INDENT[i++] + REG_ENTRY + " {");
        if (info.getClassName() != null) {
            writeConEntry(info, out, i);
        }
        for (RegistrationContext ctx : info.getRegContexts()) {
            out.println(INDENT[i++] + REG_CTX + " {");
            if (ctx.getMessageLayer() != null) {
                out.println(INDENT[i] + LAYER + SEP + ctx.getMessageLayer());
            }
            if (ctx.getAppContext() != null) {
                out.println(INDENT[i] + APP_CTX + SEP + ctx.getAppContext());
            }
            if (ctx.getDescription() != null) {
                out.println(INDENT[i] + DESCRIPTION +
                    SEP + ctx.getDescription());
            }
            out.println(INDENT[--i] + "}");
        }
        out.println(INDENT[--i] + "}");
    }

    private void clearExistingFile() throws IOException {
        boolean newCreation = !confFile.exists();
        if (!newCreation) {
            if(!confFile.delete()) {
                throw new IOException();
            }
        }
        if (newCreation) {
            logger.log(Level.INFO, "jmac.factory_creating_conf_file",
                    confFile.getPath());
        }
        if (!confFile.createNewFile()) {
            throw new IOException();
        }
    }

    /*
     * Called from the constructor. This is the only time
     * the file is read, though it is written when new
     * entries are stored or deleted.
     */
    private void loadEntries() throws IOException {
        synchronized (confFile) {
            entries = new ArrayList<EntryInfo>();
            if (confFile.exists()) {
                try (BufferedReader reader = new BufferedReader(new FileReader(confFile))) {
                    String line = reader.readLine();
                    while (line != null) {
                        String trimLine = line.trim(); // can't trim readLine() result
                        if (trimLine.startsWith(CON_ENTRY)) {
                            entries.add(readConEntry(reader));
                        } else if (trimLine.startsWith(REG_ENTRY)) {
                            entries.add(readRegEntry(reader));
                        }
                        line = reader.readLine();
                    }
                }
            } else {
                if (logger.isLoggable(Level.FINER)) {
                    logger.log(Level.FINER, "jmac.factory_file_not_found",
                            confFile.getParent() + File.pathSeparator
                            + confFile.getPath());

                }
                for (EntryInfo e : defaultEntries) {
                    entries.add(new EntryInfo(e));
                }
            }
        }
    }

    private EntryInfo readConEntry(BufferedReader reader) throws IOException {
        // entry must contain class name as next line
        String className = reader.readLine();
        if(className != null) {
            className = className.trim();
        }
        Map<String, String> properties = readProperties(reader);
        return new EntryInfo(className, properties);
    }

    /*
     * Properties must be of the form "key:value." While the key
     * String cannot contain a ":" character, the value can. The
     * line will be broken into key and value based on the first
     * appearance of the ":" character.
     */
    private Map<String, String> readProperties(BufferedReader reader)
        throws IOException {

        String line = reader.readLine();
        if(line != null) {
            line = line.trim();
        }

        if ("}".equals(line)) {
            return null;
        }
        Map<String, String> properties = new HashMap<String, String>();
        while (!"}".equals(line)) {
            properties.put(line.substring(0, line.indexOf(SEP)),
                line.substring(line.indexOf(SEP) + 1, line.length()));
            line = reader.readLine();
            if (line != null) {
                line = line.trim();
            }
        }
        return properties;
    }

    private EntryInfo readRegEntry(BufferedReader reader) throws IOException {
        String className = null;
        Map<String, String> properties = null;
        List<RegistrationContext> ctxs =
            new ArrayList<RegistrationContext>();
        String line = reader.readLine();
        if(line != null) {
            line = line.trim();
        }
        while (!"}".equals(line)) {
            if (line.startsWith(CON_ENTRY)) {
                EntryInfo conEntry = readConEntry(reader);
                className = conEntry.getClassName();
                properties = conEntry.getProperties();
            } else if (line.startsWith(REG_CTX)) {
                ctxs.add(readRegContext(reader));
            }
            line = reader.readLine();
            if(line != null) {
                line = line.trim();
            }

        }
        return new EntryInfo(className, properties, ctxs);
    }

    private RegistrationContext readRegContext(BufferedReader reader)
        throws IOException {

        String layer = null;
        String appCtx = null;
        String description = null;
        String line = reader.readLine();
        if(line != null) {
            line = line.trim();
        }
        while (!"}".equals(line)) {
            String value = line.substring(line.indexOf(SEP) + 1,
                line.length());
            if (line.startsWith(LAYER)) {
                layer = value;
            } else if (line.startsWith(APP_CTX)) {
                appCtx = value;
            } else if (line.startsWith(DESCRIPTION)) {
                description = value;
            }
           line = reader.readLine();
            if(line != null) {
                line = line.trim();
            }
        }
        return new RegistrationContextImpl(layer, appCtx, description, true);
    }

}
