/*
 * Copyright 2015 Open Networking Laboratory
 *
 * 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.onosproject.persistence.impl;

import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Service;
import org.mapdb.DB;
import org.mapdb.DBMaker;
import org.onosproject.persistence.PersistenceService;
import org.onosproject.persistence.PersistentMapBuilder;
import org.onosproject.persistence.PersistentSetBuilder;
import org.slf4j.Logger;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;

import static org.slf4j.LoggerFactory.getLogger;

/**
 * Service that maintains local disk backed maps and sets.  This implementation automatically deletes empty structures
 * on shutdown.
 */
@Component(immediate = true)
@Service
public class PersistenceManager implements PersistenceService {

    private static final String DATABASE_PATH = System.getProperty("karaf.data", "./data/localDB");
    private static final String ENCLOSING_FOLDER = System.getProperty("karaf.data", "./data");

    static final String MAP_PREFIX = "map:";

    static final String SET_PREFIX = "set:";

    private final Logger log = getLogger(getClass());

    private DB localDB = null;

    private static final int FLUSH_FREQUENCY_MILLIS = 3000;

    private Timer timer;

    private final CommitTask commitTask = new CommitTask();

    @Activate
    public void activate() {
        timer = new Timer();
        Path dbPath = Paths.get(DATABASE_PATH);
        Path dbFolderPath = Paths.get(ENCLOSING_FOLDER);
        //Make sure the directory exists, if it does not, make it.
        if (!dbFolderPath.toFile().isDirectory()) {
            log.info("The specified folder location for the database did not exist and will be created.");
            try {
                Files.createDirectories(dbFolderPath);
            } catch (IOException e) {
                log.error("Could not create the required folder for the database.");
                throw new PersistenceException("Database folder could not be created.");
            }
        }
        //Notify if the database file does not exist.
        boolean dbFound = Files.exists(dbPath);
        if (!dbFound) {
            log.info("The database file could not be located, a new database will be constructed.");

        } else {
            log.info("A previous database file has been found.");
        }
        localDB = DBMaker.newFileDB(dbPath.toFile())
                .asyncWriteEnable()
                .closeOnJvmShutdown()
                .make();
        timer.schedule(commitTask, FLUSH_FREQUENCY_MILLIS, FLUSH_FREQUENCY_MILLIS);
        log.info("Started");
    }

    @Deactivate
    public void deactivate() {
        timer.cancel();
        for (Map.Entry<String, Object> entry : localDB.getAll().entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
                //This is a map implementation to be handled as such
            if (value instanceof Map) {
                Map asMap = (Map) value;
                if (asMap.isEmpty()) {
                    //the map is empty and may be deleted
                    localDB.delete(key);
                }
                //This is a set implementation and can be handled as such
            } else if (value instanceof Set) {
                Set asSet = (Set) value;
                if (asSet.isEmpty()) {
                    //the set is empty and may be deleted
                    localDB.delete(key);
                }
            }
        }
        localDB.commit();
        localDB.close();
        log.info("Stopped");
    }

    public <K, V> PersistentMapBuilder<K, V> persistentMapBuilder() {
        return new DefaultPersistentMapBuilder<>(localDB);
    }

    public <E> PersistentSetBuilder<E> persistentSetBuilder() {
        return new DefaultPersistentSetBuilder<>(localDB);
    }

    private class CommitTask extends TimerTask {

        @Override
        public void run() {
            localDB.commit();
        }
    }
}
@@ -1647,42 +1647,10 @@
 H = 
-System.getProperty(%22karaf.data%22, 
 %22
+.
 ./da
@@ -1660,17 +1660,16 @@
 localDB%22
-)
 ;%0A    pr
@@ -1717,50 +1717,17 @@
 R = 
-System.getProperty(%22karaf.data%22, 
 %22
+.
 ./data%22
-)
 ;%0A%0A 

Revert PersistenceManager change to use karaf data directory