package com.duell.configoverride;

import java.io.FileNotFoundException;
import java.io.IOException;

import com.duell.configoverride.configReader.ConfigReader;
import com.duell.configoverride.configReader.PropertyFileConfigReader;

import android.content.Context;
import android.util.Log;

public class OverrideConfigManager
{
	private static final String TAG = "EnvironmentConfigReader";

	// Used for actually accessing the property information
	private ConfigReader mainConfigReader = null;
	private ConfigReader overrideConfigReader = null;

	private Context ctx = null;

	private boolean strictOverride = false;

	// Used for creating ConfigReaders on our own
	private boolean mustInitOwnReaders = false;
	private String configFileName = null;
	private int configFileId = -1;
	private String overrideFileName = null;
	private StorageLocation mOverrideLocation = null;

	/**
	 * 
	 * @param ctx
	 * @param mainConfigFileid
	 *            - Resource ID of the config file whose which will be overrode.
	 *            Assumes it will be in /res/raw
	 * @param overrideConfigFileName
	 *            - File NAME of the config file whose values will be used in
	 *            the case of an override
	 * @param overrideLocation
	 *            - EXTERNAL or INTERNAL storage location
	 * @param strictOverride
	 *            - true => the property MUST exist in the mainConfigFile to be
	 *            overridden. false => the property specified does not have to
	 *            exist in the main config to be pulled from the override
	 * 
	 */
	public OverrideConfigManager(Context ctx, int mainConfigFileid, String overrideConfigFileName,
			StorageLocation overrideLocation, boolean strictOverride)
	{
		configFileId = mainConfigFileid;
		overrideFileName = overrideConfigFileName;
		mOverrideLocation = overrideLocation;
		this.strictOverride = strictOverride;
		this.mustInitOwnReaders = true;
		this.ctx=ctx;

	}

	/**
	 * 
	 * @param ctx
	 * @param mainConfigFileName
	 *            - Filename of the config file whose values will be overrode.
	 *            Assumes it will be in /assets.
	 * @param overrideConfigFileName
	 *            - File NAME of the config file whose values will be used in
	 *            the case of an override
	 * @param overrideLocation
	 *            - EXTERNAL or INTERNAL storage location
	 * @param strictOverride
	 *            - true => the property MUST exist in the mainConfigFile to be
	 *            overridden. false => the property specified does not have to
	 *            exist in the main config to be pulled from the override
	 */
	public OverrideConfigManager(Context ctx, String mainConfigFileName, String overrideConfigFileName,
			StorageLocation overrideLocation, boolean strictOverride)
	{
		configFileName = mainConfigFileName;
		overrideFileName = overrideConfigFileName;
		mOverrideLocation = overrideLocation;
		this.strictOverride = strictOverride;
		this.mustInitOwnReaders = true;
		this.ctx=ctx;

	}

	public OverrideConfigManager(Context ctx, ConfigReader mainConfig, ConfigReader overrideConfig,
			boolean strictOverride)
	{
		this.mainConfigReader = mainConfig;
		this.overrideConfigReader = overrideConfig;
		this.strictOverride = strictOverride;
		this.mustInitOwnReaders = false;
		this.ctx=ctx;
	}

	public OverrideConfigManager(Context ctx, ConfigReader mainConfig, ConfigReader overrideConfig)
	{
		this(ctx, mainConfig, overrideConfig, false);
	}

	public OverrideConfigManager init() throws IOException
	{
		if (mustInitOwnReaders)
		{
			if (configFileName != null) // load the main config via file name
										// from /assets
			{
				Log.i(TAG, "Loading main config file from /assets directory");

				mainConfigReader = new PropertyFileConfigReader();
				mainConfigReader.setConfig(StorageLocation.ASSETS, configFileName);
				try
				{
					mainConfigReader.loadConfig(ctx);
				}
				catch (IOException ioe)
				{
					throw new IOException("OverrideConfigManager: Main Config File could not be opened", ioe);
				}

			}
			else if (configFileId != -1)// Load the main config via resource id
										// from /res/raw
			{
				Log.i(TAG, "Loading main config file from /res/raw directory");

				mainConfigReader = new PropertyFileConfigReader();
				mainConfigReader.setConfig(configFileId);

				try
				{
					mainConfigReader.loadConfig(ctx);
				}
				catch (IOException ioe)
				{
					throw new IOException("OverrideConfigManager: Main Config File could not be opened", ioe);
				}
			}

			/*
			 * Load the override file, if it exists
			 */
			if (overrideFileName != null)
			{
				overrideConfigReader = new PropertyFileConfigReader();
				overrideConfigReader.setConfig(mOverrideLocation, overrideFileName);

				try
				{
					boolean success = overrideConfigReader.loadConfig(ctx);
					if(!success)
					{
						Log.w(TAG, "Override File not found when attempting to load from file system");
						overrideConfigReader=null;
					}
				}
				catch (IOException ioe)
				{
					if (ioe.getCause() != null)
					{
						if (ioe.getCause() instanceof FileNotFoundException)
						{
							// Swallow exception, log warning. The Override
							// should always be optional.
							Log.w(TAG, "Override File not found when attempting to load from file system", ioe);
							overrideConfigReader=null;
						}
						else
						{
							throw ioe;
						}
					}
				}
			}
		}
		else
		// Readers are already provided
		{

		}
		return this;
	}

	/**
	 * Returns the property, or null if no property exists
	 * 
	 * @param propertyName
	 * @return
	 */
	public Object getProperty(Object qualifier, String propertyName)
	{

		if (mainConfigReader.hasProperty(qualifier, propertyName)
				&& !mainConfigReader.isOverrideable(qualifier, propertyName))
		{
			return mainConfigReader.getProperty(qualifier, propertyName);
		}

		if (overrideConfigReader != null)
		{
			if (strictOverride)
			{
				if (mainConfigReader.hasProperty(qualifier, propertyName)
						&& overrideConfigReader.hasProperty(qualifier, propertyName))
				{
					return overrideConfigReader.getProperty(qualifier, propertyName);
				}
			}
			else
			{
				if (overrideConfigReader.hasProperty(qualifier, propertyName))
				{
					return overrideConfigReader.getProperty(qualifier, propertyName);
				}
			}
		}

		if (mainConfigReader.hasProperty(qualifier, propertyName))
		{
			return mainConfigReader.getProperty(qualifier, propertyName);
		}
		return null; // no property in main or override
	}
}
