/*_############################################################################
  _## 
  _##  SNMP4J-Agent 3 - DefaultMOPersistenceProvider.java  
  _## 
  _##  Copyright (C) 2005-2025  Frank Fock (SNMP4J.org)
  _##  
  _##  Licensed 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.snmp4j.agent.io;

import java.io.*;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;

import org.snmp4j.agent.MOServer;
import org.snmp4j.agent.mo.MOPriorityProvider;

/**
 * The {@code DefaultMOPersistenceProvider} provides agent state
 * persistence using a file with {@link DefaultMOInput} and
 * {@link DefaultMOOutput} input/output.
 *
 * @author Frank Fock
 * @version 1.2
 */
public class DefaultMOPersistenceProvider implements MOPersistenceProvider {

    private final MOServer[] server;
    private final String defaultURI;

    /**
     * Creates a persistence provider for the supplied {@link MOServer} instances.
     * The content and state of the managed objects of those servers are subject
     * to {@link #store} and {@link #restore} operations.
     *
     * @param server
     *   an array of {@code MOServer} instances (possibly empty).
     * @param defaultURI
     *   the (optional) default URI (i.e., file path) to be used for this
     *   persistence provider.
     */
    public DefaultMOPersistenceProvider(MOServer[] server, String defaultURI) {
        this.server = server;
        this.defaultURI = defaultURI;
    }

    /**
     * Returns a unique ID of the persistence provider which should identify the
     * format and type of the persistence provider.
     *
     * @return "default".
     */
    public String getPersistenceProviderID() {
        return "default";
    }

    /**
     * Checks whether the supplied URI string is valid for this persistence
     * provider.
     *
     * @param uri a string identifying a persistent storage location for this
     *   storage provider.
     * @return {@code true} if the {@code uri} is valid,
     *   {@code false} otherwise.
     */
    public boolean isValidPersistenceURI(String uri) {
        try {
            File f = getFile(uri);
            return (f.isFile() && (f.canRead() || f.canWrite())) || !f.exists();
        }
        catch (Exception ex) {
            return false;
        }
    }

    /**
     * Converts the specified URI string to a {@link File} object. If the URI
     * string starts with "file:", it will be parsed as a {@link URI},
     * and then converted to a {@link File}. Otherwise, it will be interpreted
     * as a simple file path.
     *
     * @param uri the string representation of the file URI or file path.
     * @return a {@link File} object corresponding to the given URI or file path.
     */
    public static File getFile(String uri) {
        File f;
        if (uri.toUpperCase().startsWith("FILE:")) {
            URI u = URI.create(uri);
            f = new File(u);
        }
        else {
            f = new File(uri);
        }
        return f;
    }

    /**
     * Restore (load) agent state from the specified file URI or file name.
     *
     * @param uri a string pointing to the persistent storage file from which the
     *   agent state should be restored from. The format of the string is
     *   either a simple file name or an URI starting with "file:".
     * @param importMode specifies how the agent's current state should be
     *   update while restoring a previous state.
     * @throws IOException if the restore operation fails.
     */
    public void restore(String uri, int importMode) throws IOException {
        if (uri == null) {
            uri = getDefaultURI();
        }
        File outputFile = getFile(uri);
        Path outputPath = outputFile.toPath();
        try (ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(outputPath))) {
            DefaultMOInput is = new DefaultMOInput(ois);
            is.setOverwriteMode(importMode);
            MOServerPersistence p = new MOServerPersistence(server);
            p.loadData(is);
        }
    }



    /**
     * Stores the current agent state to persistent storage specified by the
     * supplied URI.
     *
     * @param uri a string pointing to the persistent storage file to use.
     *   The format of the string is either a simple file name or an URI
     *   starting with "file:".
     * @throws IOException if the store operation fails.
     */
    public void store(String uri) throws IOException {
        store(uri, null);
    }

    @Override
    public void store(String uri, MOPriorityProvider priorityProvider) throws IOException {
        if (uri == null) {
            uri = getDefaultURI();
        }
        try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(getFile(uri).toPath()))) {
            DefaultMOOutput os = new DefaultMOOutput(oos);
            MOServerPersistence p = new MOServerPersistence(server);
            p.saveData(os, priorityProvider);
            oos.flush();
        }
    }

    public String getDefaultURI() {
        return defaultURI;
    }

}
