/**
 * Copyright (c) 2010-2012 EBM WebSourcing, 2012-2013 Linagora
 * 
 * This program/library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at your
 * option) any later version.
 * 
 * This program/library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
 * for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program/library; If not, see <http://www.gnu.org/licenses/>
 * for the GNU Lesser General Public License version 2.1.
 */
package org.ow2.petals.cli.connection;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;

import org.junit.Ignore;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.ow2.petals.cli.Constants;
import org.ow2.petals.cli.api.connection.AuthenticatedConnectionParameters;
import org.ow2.petals.cli.api.connection.ConnectionParameters;

public class PreferenceFileManagerTest {
    
    /**
     * Preferences filename defined as maven-surefire-plugin and set into the
     * environment variable {@value PreferenceFileManager#PREFERENCE_ENV_VAR}
     */
    public final static String PREFERENCES_FILE_FOR_TEST = System
            .getProperty("PREFERENCES_FILE_FOR_TEST");

    /**
     * <p>
     * Verify that the preferences file used when the environment variable
     * {@value PreferenceFileManager#PREFERENCE_ENV_VAR} is not set.
     * </p>
     * <p>
     * The expected preferences file is the default one.
     * </p>
     */
    @Test
    public final void testGetPreferenceFile_ByDefault() throws URISyntaxException {

        final URL expectedPrefFileUrl = Thread.currentThread().getContextClassLoader()
                .getResource(PreferenceFileManager.PREFERENCE_FILE_NAME);
        final File expectedPrefFile = new File(expectedPrefFileUrl.toURI());

        final File preferenceFile = PreferenceFileManager.getPreferenceFile();

        assertEquals("The preference file is not the expected one.", expectedPrefFile,
                preferenceFile);
    }

    /**
     * <p>
     * Verify that the preferences file used when the environment variable
     * {@value PreferenceFileManager#PREFERENCE_ENV_VAR} is set to an empty
     * value.
     * </p>
     * <p>
     * The expected preferences file is the default one.
     * </p>
     */
    @Test
    @Category(UnitTestsRequiringEmptyEnvVar.class)
    @Ignore("Waiting to be able to set empty env var through the maven-surefire-plugin: SUREFIRE-963")
    public final void testGetPreferenceFile_WithEmptyEnvVar() throws URISyntaxException {

        // The environment variable is set to "" at maven-surefire-plugin level

        final URL expectedPrefFileUrl = Thread.currentThread().getContextClassLoader()
                .getResource(PreferenceFileManager.PREFERENCE_FILE_NAME);
        final File expectedPrefFile = new File(expectedPrefFileUrl.toURI());

        final File preferenceFile = PreferenceFileManager.getPreferenceFile();

        assertEquals("The preference file is not the expected one.", expectedPrefFile,
                preferenceFile);
    }

    /**
     * <p>
     * Verify the preferences file used when the environment variable
     * {@value PreferenceFileManager#PREFERENCE_ENV_VAR} is to an unexisting
     * file.
     * </p>
     * <p>
     * The expected preferences file is the one defined in the environment
     * variable.
     * </p>
     */
    @Test
    @Category(UnitTestsRequiringInvalidEnvVar.class)
    public final void testGetPreferenceFile_WithInvalidEnvVar() throws URISyntaxException {

        // The environment variable is set to "${basedir}/unexisting.properties"
        // at maven-surefire-plugin level

        final File expectedPrefFile = new File(PREFERENCES_FILE_FOR_TEST);

        final File preferenceFile = PreferenceFileManager.getPreferenceFile();

        assertEquals("The preference file is not the expected one.", expectedPrefFile,
                preferenceFile);
    }

    /**
     * <p>
     * Verify preferences file used when the environment variable
     * {@value PreferenceFileManager#PREFERENCE_ENV_VAR} is to an existing file.
     * </p>
     * <p>
     * The expected preferences file is the one defined in the environment
     * variable.
     * </p>
     */
    @Test
    @Category(UnitTestsRequiringSetEnvVar.class)
    public final void testGetPreferenceFile_WithSetEnvVar() throws URISyntaxException {

        // The environment variable is set to
        // "${basedir}/target/petals-cli.default-by-env-var"
        // at maven-surefire-plugin level

        final File expectedPrefFile = new File(PREFERENCES_FILE_FOR_TEST);

        final File preferenceFile = PreferenceFileManager.getPreferenceFile();

        assertEquals("The preference file is not the expected one.", expectedPrefFile,
                preferenceFile);
    }

    /**
     * <p>
     * Verify the read of preferences file when the preference file does not exist.
     * </p>
     * <p>
     * Expected result: the error {@link PreferenceFileNotFoundException} occurs.
     * </p>
     */
    @Test(expected = PreferenceFileNotFoundException.class)
    @Category(UnitTestsRequiringInvalidEnvVar.class)
    public final void testGetPreferenceConnectionParameters_WithUnexistingPreferenceFile()
            throws URISyntaxException, PreferenceFileException {

        PreferenceFileManager.getPreferenceConnectionParameters();
    }
    
    @Test
    public final void testInitializeDefaultConnectionAliasWithoutErrors() throws Exception {
        List<String> errors = new ArrayList<String>();
        Properties preferenceProperties = new Properties();
        
        preferenceProperties.setProperty("server1.host", "test1");
        preferenceProperties.setProperty("server1.port", "7458");

        preferenceProperties.setProperty(PreferenceFileManager.DEFAULT_ALIAS_PROPERTY, "test1");
        
        String defaultConnectionAlias = PreferenceFileManager
                .initializeDefaultConnectionAlias(preferenceProperties, errors);
        
        assertEquals("test1", defaultConnectionAlias);
    }
    
    @Test
    public final void testInitializeDefaultConnectionAliasWithNoDefaultConnectionAlias()
            throws Exception {
        List<String> errors = new ArrayList<String>();
        Properties preferenceProperties = new Properties();

        preferenceProperties.setProperty("server1.host", "test1");
        preferenceProperties.setProperty("server1.port", "7458");

        String defaultConnectionAlias = PreferenceFileManager.initializeDefaultConnectionAlias(
                preferenceProperties, errors);

        assertEquals(null, defaultConnectionAlias);
        assertEquals(1, errors.size());
        assertTrue(errors.contains(String.format(
                Constants.PreferenceFileMessages.MISSING_PROPERTY,
                PreferenceFileManager.DEFAULT_ALIAS_PROPERTY)));
    }
    
    @Test
    public final void testInitializeDefaultConnectionAliasWithEmptyPreferenceFile()
            throws Exception {
        List<String> errors = new ArrayList<String>();
        Properties preferenceProperties = new Properties();

        String defaultConnectionAlias = PreferenceFileManager.initializeDefaultConnectionAlias(
                preferenceProperties, errors);
        assertNull(defaultConnectionAlias);
    }

    @Test
    public final void testIntializePreferenceConnectionParametersFromPropertiesWithoutErrors() throws Exception {
        List<String> errors = new ArrayList<String>();
        Properties preferenceProperties = new Properties();
        
        preferenceProperties.setProperty("server1.host", "test1");
        preferenceProperties.setProperty("server1.port", "7458");

        preferenceProperties.setProperty("server2.host", "test2");
        preferenceProperties.setProperty("server2.port", "7459");
        preferenceProperties.setProperty("server2.username", "userTest2");
        preferenceProperties.setProperty("server2.password", "pwdTest2");

        preferenceProperties.setProperty("server3.host", "test3");
        preferenceProperties.setProperty("server3.port", "7460");
        preferenceProperties.setProperty("server3.username", "userTest3");
        preferenceProperties.setProperty("server3.password", "pwdTest3");
        preferenceProperties.setProperty("server3.passphrase", "passPhrase3");
        
        HashMap<String, ConnectionParameters> preferenceConnectionParameters = PreferenceFileManager
                .initializePreferenceConnectionParametersFromProperties(preferenceProperties, errors);
        
        ConnectionParameters connectionParameter1 = preferenceConnectionParameters.get("server1");
        assertEquals(new ConnectionParameters("test1", 7458), connectionParameter1);

        ConnectionParameters connectionParameter2 = preferenceConnectionParameters.get("server2");
        assertTrue(connectionParameter2 instanceof AuthenticatedConnectionParameters);
        assertEquals(new AuthenticatedConnectionParameters("test2", 7459, "userTest2", "pwdTest2",
                null), connectionParameter2);

        ConnectionParameters connectionParameter3 = preferenceConnectionParameters.get("server3");
        assertTrue(connectionParameter3 instanceof AuthenticatedConnectionParameters);
        assertEquals(new AuthenticatedConnectionParameters("test3", 7460, "userTest3", "pwdTest3",
                "passPhrase3"), connectionParameter3);
    }
    
    @Test
    public final void testIntializePreferenceConnectionParametersFromPropertiesWithErrors() throws Exception {
        List<String> errors = new ArrayList<String>();
        Properties preferenceProperties = new Properties();
        
        preferenceProperties.setProperty("server1.host", "test1");
        preferenceProperties.setProperty("server1.port", "745ds");

        preferenceProperties.setProperty("server2.host", "test2");
        preferenceProperties.setProperty("server2.port", "7459");
        preferenceProperties.setProperty("server2.username", "userTest");

        preferenceProperties.setProperty("server3.host", "test3");
        preferenceProperties.setProperty("server3.port", "7457");
        preferenceProperties.setProperty("server3.password", "pwdTes2t");
        
        preferenceProperties.setProperty("server4.username", "userTest");
        
        preferenceProperties.setProperty("server5.usernme", "userIncorect");

        preferenceProperties.setProperty("servefd", "testIncorrect");
        
        PreferenceFileManager.initializePreferenceConnectionParametersFromProperties(preferenceProperties, errors);
        assertEquals(8, errors.size());
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.INCORRECT_PROPERTY_VALUE, "745ds", "server1.port")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.MISSING_PASSWORD_PROPERTY, "server2")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.MISSING_USER_PROPERTY, "server3")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.MISSING_PROPERTY, "server4.host")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.MISSING_PROPERTY, "server4.port")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.MISSING_PASSWORD_PROPERTY, "server4")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.INCORRECT_PROPERTY_NAME, "server5.usernme")));
        assertTrue(errors.contains(String.format(Constants.PreferenceFileMessages.INCORRECT_PROPERTY_NAME, "servefd")));
    }
    
    @Test
    public final void testIntializePreferenceConnectionParametersFromPropertiesWithEmptyPreferenceFile()
            throws Exception {
        List<String> errors = new ArrayList<String>();
        Properties preferenceProperties = new Properties();

        HashMap<String, ConnectionParameters> preferenceConnectionParameters = PreferenceFileManager.initializePreferenceConnectionParametersFromProperties(preferenceProperties, errors);
        assertNotNull(preferenceConnectionParameters);
        assertTrue(preferenceConnectionParameters.isEmpty());
    }
}
