package tableDefinition;

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

public class Configuration
{
	private String host = "";                 // = soft-banana.db.elephantsql.com
	private String port = "";                  // = 5432
	private String jdbcDriver = "";           // = org.postgresql.Driver
	private String connectionString = "";     // = jdbc:postgresql://
	private String userSpecifiedAs = "";      // = environment-variable      # literal, environment-variable or integrated-security
	private String user = "";                 // = DATABASE_USER
	private String passwordSpecifiedAs = "";  // = environment-variable      # literal, environment-variable or integrated-security
	private String password = "";             // = DATABASE_PASSWORD
	private String integratedSecurity = "";   // = false
	private String database = "";             // = dev
	private String schema = "";               // = public
	private String table = "";                // = 
	private String outputDirectory = "";      // = /Users/ronballard/Desktop/
	
	private boolean valid = true;
	private int lineNumber = 0;
	private int i;
	private String realUser = "";
	private String realPassword = "";
	

	
	public Configuration(String configurationFileName)
	{
		String line;
		String name;
		String value;
		
		FileReader configurationFile = null;
		BufferedReader configurationFileReader = null;
		try 
		{
			configurationFile = new FileReader(configurationFileName);
		} 
		catch (FileNotFoundException e) 
		{
			System.out.println("Could not open " + configurationFileName + " for reading");
			System.exit(1);
		}
		
		configurationFileReader = new BufferedReader(configurationFile);
		
		try 
		{
			while ((line = new String(configurationFileReader.readLine())) != null)
			{
				lineNumber++;
				for(i = 0; i < line.length(); i++)
				{
					if (line.charAt(i) == '#')
						break;
					else if (line.charAt(i) == ' ')
					{
						i++;
					}
					else if (line.charAt(i) == '[')
					{
						i++;
						getSectionName(line);
						break;
					}
					else
					{
						name = getParameterName(line);
						while 
						(
							(i < line.length()) && 
							((line.charAt(i) == ' ') || (line.charAt(i) == '='))
						)
						{
							i++;
						}
						value = getParameterValue(line);
						checkSetParameter(name, value);
						break;
					}
				}
			}
		}
		catch (NullPointerException n)
		{
			System.out.println("End of file " + configurationFileName);
		}
		catch (IOException e) 
		{
			e.printStackTrace();
		}
		print();
		
		if (userSpecifiedAs.equals("environment-variable"))
		{
			try 
			{
				realUser = new String(System.getenv(user));
			} 
			catch (NullPointerException npe) 
			{
				System.out.println
				(
					"Environment variable " + 
					user +
					" is not defined.  "
				);
			}
			catch (SecurityException se) 
			{
				System.out.println
				(
					"Permission to read environment variable " + 
					user +
					" was denied. "
				);
			}
		}
		else
		{
			realUser = new String(user);
		}

		if (passwordSpecifiedAs.equals("environment-variable"))
		{
			try 
			{
				realPassword = new String(System.getenv(password));
			} 
			catch (NullPointerException npe) 
			{
				System.out.println
				(
					"Environment variable " + 
					password +
					" is not defined.  "
				);
			}
			catch (SecurityException se) 
			{
				System.out.println
				(
					"Permission to read environment variable " + 
					password +
					" was denied."
				);
			}
		}
		else
		{
			realPassword = new String(password);
		}
	}
	
	private String getSectionName (String line)
	{
		StringBuffer name = null;
		boolean done;
		boolean sectionNameTerminated;
		char c;
		
		sectionNameTerminated = false;
		name = new StringBuffer();
		done = false;
		while (!done)
		{
			if (i >= line.length())
				done = true;
			else
			{
				c = line.charAt(i);
				if (c == ']')
				{
					sectionNameTerminated = true;
					done = true;
				}
				else if (c == '#')
					done = true;
				else if (Character.isLetterOrDigit(c)) 
				{
					if (Character.isLowerCase(c))
						name.append(c);
					else if (Character.isDigit(c))
						name.append(c);
					else if (c == '_')
						name.append(c);
					else
					{
						System.out.println 
						(
							lineNumber + ": " + line +
							": Section names can be lowercase letters, numeric digits (0-9) or underscrores, nothing else."
						);
						valid = false;
					}
				}
				else if (c == '_')
					name.append(c);
				else
				{
					System.out.println 
					(
						lineNumber + ": " + line +
						": Section names can be lowercase letters, numeric digits (0-9) or underscrores, nothing else."
					);
					valid = false;
				}
			i++;
			}
		}
		if (!sectionNameTerminated)
		{
			System.out.println 
			(
				lineNumber + ": " + line +
				": Section name must be terminated with \"]\"."
			);
			valid = false;
		}
			
		return name.toString();		
	}

	
	private String getParameterName (String line)
	{
		StringBuffer name = null;
		boolean done;
		char c;
		
		name = new StringBuffer();
		done = false;
		while (!done)
		{
			if (i >= line.length())
				done = true;
			else
			{
				c = line.charAt(i);
				if ((c == ' ') || (c == '=') || (c == '#'))
					done = true;
				else if (Character.isLetterOrDigit(c)) 
				{
					if (Character.isLowerCase(c))
						name.append(c);
					else if (Character.isDigit(c))
						name.append(c);
					else if (c == '_')
						name.append(c);
					else
					{
						System.out.println 
						(
							lineNumber + ": " + line +
							": Parameter names can be lowercase letters, numeric digits (0-9) or underscrores, nothing else."
						);
						valid = false;
					}
				}
				else if (c == '_')
					name.append(c);
				else
				{
					System.out.println 
					(
						lineNumber + ": " + line +
						": Parameter names can be lowercase letters, numeric digits (0-9) or underscrores, nothing else."
					);
					valid = false;
				}
				i++;
			}
		}
			
		return name.toString();		
	}

	
	private String getParameterValue (String line)
	{
		StringBuffer value = null;
		boolean done;
		char c;
		
		value = new StringBuffer();
		done = false;
		while (!done)
		{
			if (i >= line.length())
				done = true;
			else
			{
				c = line.charAt(i);
				if (c == '#')
					done = true;
				else
				{
					value.append(c);
					i++;
				}
			}
		}

		return value.toString().trim();
	}
	
	private void checkSetParameter(String name, String value)
	{
		
		if (name.equals("host"))
		{
			if (host.isEmpty())
				host = new String(value);
			else
			{
				System.out.println("'host' must not be specified more than once");
				valid = false;
			}
		}
		else if (name.equals("port"))
		{
			if (port.isEmpty())
				port = new String(value);
			else
			{
				System.out.println("'port' must not be specified more than once");
				valid = false;				
			}
		}		
		else if (name.equals("jdbc_driver"))
		{
			if (jdbcDriver.isEmpty())
				jdbcDriver = new String(value);
			else
			{
				System.out.println("'jdbc driver' must not be specified more than once");
				valid = false;				
			}
		}
		else if (name.equals("connection_string"))
		{
			if (connectionString.isEmpty())
				connectionString = new String(value);
			else
			{
				System.out.println("'connection string' must not be specified more than once");
				valid = false;				
			}
		}
		else if (name.equals("user_specified_as"))     // # literal, environment-variable or integrated-security
		{
			if (userSpecifiedAs.isEmpty())
			{
				if 
				(
					(value.equals("environment-variable")) || 
					(value.equals("literal")) ||
					(value.equals("integrated-security"))
				)
				{
					userSpecifiedAs = new String(value);
				}
				else
				{
					System.out.println("'user_specified_as' must be 'literal', 'environment-variable' or 'integrated-security'");
					valid = false;									
				}
			}
			else
			{
				System.out.println("'user_specified_as' must not be specified more than once");
				valid = false;				
			}
		}				
		else if (name.equals("user"))
		{
			if (user.isEmpty())
				user = new String(value);
			else
			{
				System.out.println("'user' must not be specified more than once");
				valid = false;				
			}				
		}
		else if (name.equals("password_specified_as")) //  # literal, environment-variable or integrated-security
		{
			if (passwordSpecifiedAs.isEmpty())
			{
				if 
				(
					(value.equals("environment-variable")) || 
					(value.equals("literal")) ||
					(value.equals("integrated-security"))
				)
				{
					passwordSpecifiedAs = new String(value);
				}
				else
				{
					System.out.println("'password_specified_as' must be 'literal', 'environment-variable' or 'integrated-security'");
					valid = false;									
				}
			}
			else
			{
				System.out.println("'password' must not be specified more than once");
				valid = false;				
			}
		}
		else if (name.equals("password"))
		{
			if (password.isEmpty())
				password = new String(value);
			else
			{
				System.out.println("'password' must not be specified more than once");
				valid = false;				
			}				
		}
		else if (name.equals("integrated_security"))   // true or false
		{
			if (integratedSecurity.isEmpty())
				integratedSecurity = new String(value);
			else
			{
				System.out.println("'integratedSecurity' must not be specified more than once");
				valid = false;				
			}				
		}
		else if (name.equals("database"))
		{
			if (database.isEmpty())
				database = new String(value);
			else
			{
				System.out.println("'database' must not be specified more than once");
				valid = false;				
			}				
		}
		else if (name.equals("schema"))
		{
			if (schema.isEmpty())
				schema = new String(value);
			else
			{
				System.out.println("'schema' must not be specified more than once");
				valid = false;				
			}				
		}
		else if (name.equals("table"))
		{
			if (table.isEmpty())
				table = new String(value);
			else
			{
				System.out.println("'table' must not be specified more than once");
				valid = false;				
			}				
		}
		else if (name.equals("output_directory"))
		{
			if (outputDirectory.isEmpty())
				outputDirectory = new String(value);
			else
			{
				System.out.println("'outputDirectory' must not be specified more than once");
				valid = false;				
			}				
		}
		else
		{
			System.out.println("parameter name '" + name + "' not recognised");
			valid = false;							
		}
	}

	private void print()
	{
		System.out.println("host:                  " + host);
		System.out.println("port:                  " + port);
		System.out.println("jdbc driver:           " + jdbcDriver);
		System.out.println("connection string:     " + connectionString);
		System.out.println("user specified as:     " + userSpecifiedAs);
		System.out.println("user:                  " + user);
		System.out.println("password specified as: " + passwordSpecifiedAs);
		System.out.println("password:              " + "********");
		System.out.println("integrated security:   " + integratedSecurity);
		System.out.println("database:              " + database);
		System.out.println("schema:                " + schema);
		System.out.println("table:                 " + table);
		System.out.println("output directory:      " + outputDirectory);
	}

	public String getHost()
	{
		return host;
	}

	public String getPort()
	{
		return port;
	}

	public String getJdbcDriver()
	{
		return jdbcDriver;
	}

	public String getConnectionString()
	{
		return connectionString;
	}

	public String getUserSpecifiedAs()
	{
		return userSpecifiedAs;
	}

	public String getUser()
	{
		return user;
	}

	public String getPasswordSpecifiedAs()
	{
		return passwordSpecifiedAs;
	}

	public String getPassword()
	{
		return password;
	}

	public String getIntegratedSecurity()
	{
		return integratedSecurity;
	}

	public String getDatabase()
	{
		return database;
	}

	public String getSchema()
	{
		return schema;
	}

	public String getTable()
	{
		return table;
	}

	public String getOutputDirectory()
	{
		return outputDirectory;
	}
	
	public String getRealUser()
	{
		return realUser;
	}

	public String getRealPassword()
	{
		return realPassword;
	}
}