package seedu.address.commons.util;


import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

import seedu.todo.commons.core.Config;
import seedu.todo.commons.exceptions.DataConversionException;
import seedu.todo.commons.util.ConfigUtil;
import seedu.todo.commons.util.FileUtil;

import java.io.File;
import java.io.IOException;
import java.util.Optional;
import java.util.logging.Level;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;

public class ConfigUtilTest {

    private static String TEST_DATA_FOLDER = FileUtil.getPath("./src/test/data/ConfigUtilTest/");

    @Rule
    public ExpectedException thrown = ExpectedException.none();

    @Rule
    public TemporaryFolder testFolder = new TemporaryFolder();

    @Test
    public void read_null_assertionFailure() throws DataConversionException {
        thrown.expect(AssertionError.class);
        read(null);
    }

    @Test
    public void read_missingFile_emptyResult() throws DataConversionException {
        assertFalse(read("NonExistentFile.json").isPresent());
    }

    @Test
    public void read_notJasonFormat_exceptionThrown() throws DataConversionException {

        thrown.expect(DataConversionException.class);
        read("NotJasonFormatConfig.json");

        /* IMPORTANT: Any code below an exception-throwing line (like the one above) will be ignored.
         * That means you should not have more than one exception test in one method
         */
    }

    @Test
    public void read_fileInOrder_successfullyRead() throws DataConversionException {

        Config expected = getTypicalConfig();

        Config actual = read("TypicalConfig.json").get();
        assertEquals(expected, actual);
    }

    @Test
    public void read_valuesMissingFromFile_defaultValuesUsed() throws DataConversionException {
        Config actual = read("EmptyConfig.json").get();
        assertEquals(new Config(), actual);
    }

    @Test
    public void read_extraValuesInFile_extraValuesIgnored() throws DataConversionException {
        Config expected = getTypicalConfig();
        Config actual = read("ExtraValuesConfig.json").get();

        assertEquals(expected, actual);
    }

    private Config getTypicalConfig() {
        Config config = new Config();
        config.setAppTitle("Typical App Title");
        config.setLogLevel(Level.INFO);
        config.setDatabaseFilePath("database.json");
        return config;
    }

    private Optional<Config> read(String configFileInTestDataFolder) throws DataConversionException {
        String configFilePath = addToTestDataPathIfNotNull(configFileInTestDataFolder);
        return ConfigUtil.readConfig(configFilePath);
    }

    @Test
    public void save_nullConfig_assertionFailure() throws IOException {
        thrown.expect(AssertionError.class);
        save(null, "SomeFile.json");
    }

    @Test
    public void save_nullFile_assertionFailure() throws IOException {
        thrown.expect(AssertionError.class);
        save(new Config(), null);
    }

    @Test
    public void saveConfig_allInOrder_success() throws DataConversionException, IOException {
        Config original = getTypicalConfig();

        String configFilePath = testFolder.getRoot() + File.separator + "TempConfig.json";

        //Try writing when the file doesn't exist
        ConfigUtil.saveConfig(original, configFilePath);
        Config readBack = ConfigUtil.readConfig(configFilePath).get();
        assertEquals(original, readBack);

        //Try saving when the file exists
        original.setAppTitle("Updated Title");
        original.setLogLevel(Level.FINE);
        ConfigUtil.saveConfig(original, configFilePath);
        readBack = ConfigUtil.readConfig(configFilePath).get();
        assertEquals(original, readBack);
    }

    private void save(Config config, String configFileInTestDataFolder) throws IOException {
        String configFilePath = addToTestDataPathIfNotNull(configFileInTestDataFolder);
        new ConfigUtil();
        ConfigUtil.saveConfig(config, configFilePath);
    }

    private String addToTestDataPathIfNotNull(String configFileInTestDataFolder) {
        return configFileInTestDataFolder != null
                                  ? TEST_DATA_FOLDER + configFileInTestDataFolder
                                  : null;
    }


}

@@ -199,16 +199,65 @@
 Config;%0A
+import seedu.todo.commons.core.ConfigDefinition;%0A
 import s
@@ -306,24 +306,24 @@
 nException;%0A
-
 import seedu
@@ -440,24 +440,100 @@
 OException;%0A
+import java.util.ArrayList;%0Aimport java.util.Arrays;%0Aimport java.util.List;%0A
 import java.
@@ -2633,32 +2633,152 @@
  config;%0A    %7D%0A%0A
+    private List%3CString%3E getTypicalConfigNames() %7B%0A        return Arrays.asList(%22appTitle%22, %22databaseFilePath%22);%0A    %7D%0A%0A
     private Opti
@@ -4057,32 +4057,32 @@
 ilePath).get();%0A
-
         assertEq
@@ -4104,32 +4104,673 @@
 readBack);%0A    %7D
+%0A    %0A    @Test%0A    public void getDefinitions_configInOrder_configNamesCorrect() %7B%0A        List%3CString%3E expected = getTypicalConfigNames();%0A        List%3CConfigDefinition%3E actualDefinitions = new Config().getDefinitions();%0A        List%3CString%3E actual = new ArrayList%3C%3E();%0A        %0A        for (ConfigDefinition defn : actualDefinitions) %7B%0A            actual.add(defn.getConfigName());%0A        %7D%0A        %0A        assertEquals(expected.size(), actual.size());%0A        %0A        for (String configName : expected) %7B%0A            boolean isInExpected = actual.indexOf(configName) %3E= 0;%0A            assertEquals(isInExpected, true);%0A        %7D%0A    %7D
 %0A%0A    private vo

Update tests for getDefinitions