/**
 *The Method set(name,value) sets a variable or calls a set method by reflection
 *The purpose of this is so that settings can be very easily coded in\removed and set via the cmd line\env var
 *
 *Variable and methods names are case insensitive
 *Method name must conform to; set_[name]
 */

import java.lang.reflect.*;

public class Settings
{
	private static final long m = 60 * 1000;	//Millis In Minutes
	private static final long h = 60 * m;		//Millis In Hours
	private static final long d = 24 * h;		//Millis In Days

	public int MAX_NUM_OF_ITEMS = 50;
	public int ARTICLE_MIN_LEN = 750;
	public int requestTimeout = 5000;
	public boolean debug = false;
	public String feedsDir = "feeds";
	public String baseURL = "";
	public String replaceFile = "Replace.txt";
	public long articleStaleTime = d;				//1 Day
	public String sqlUser = null;
	public String sqlPass = null;
	public String sqlDB = null;
	public String sqlHost = null;
	public int sqlPort = 3306;


	public long[] delay_NORM = new long[]{45*m,3*h,8*h,12*h,2*d};
	public long[] delay_UPDATE = new long[]{30*m,1*h,2*h,8*h,12*h,2*d};
	public long[] delay_ERROR = new long[]{15*m,30*m,1*h,3*h,6*h,8*h,14*h,1*d};

	private void set_articleStaleTime(Object obj)
	{
		articleStaleTime = ParseTime(obj.toString());
	}

	private void set_delay_NORM(Object obj)
	{
		delay_NORM = ParseTimeArray(obj.toString());
	}

	private void set_delay_UPDATE(Object obj)
	{
		delay_UPDATE = ParseTimeArray(obj.toString());
	}

	private void set_delay_ERROR(Object obj)
	{
		delay_ERROR = ParseTimeArray(obj.toString());
	}

	private static long[] ParseTimeArray(String str)
	{
		try
		{
			char fChar = str.charAt(0);
			char lChar = str.charAt(str.length()-1);

			if( (fChar == '[' && lChar == ']') || (fChar == '{' && lChar == '}') || (fChar == '(' && lChar == ')') )
			{
				String[] raw = str.substring(1,str.length() -1).split(",");

				long[] time = new  long[raw.length];

				for (int i = 0; i<time.length; i++)
					time[i] = ParseTime(raw[i]);

			 	return time;
			}
		}catch(Exception e)
		{
		}

		throw new RuntimeException("Not in correct format");
	}

	private static long ParseTime(String str)
	{
		long mul = -1;
		char iChar = str.charAt(str.length()-1);

	    if(iChar == 'm')
	    	mul = m;
	    else if(iChar == 'h')
	    	mul = h;
	    else if(iChar == 'd')
	    	mul = d;

    	if( mul < 0)
    		return Long.parseLong(str);
    	else
			return Long.parseLong(str.substring(0,str.length()-1)) * mul;
	}

	private void set_Proxy(Object proxy) throws Exception
	{
		String raw = proxy.toString();
		String[] parts = raw.split(":");

		boolean thrw = true;

		if(parts.length == 2)
		{
			try
			{
				System.getProperties().put( "proxyPort", String.valueOf(Integer.parseInt(parts[1].toString())) );
				System.getProperties().put( "proxyHost", parts[0] );
				System.getProperties().put( "proxySet", "True" );

				thrw = false;
			}catch(Exception e)
			{
				//Exception handled below
			};
		}

		if(thrw)
			throw new Exception("Invalid Proxy, must be of the form host:port");
	}

	private Field[] fields = null;
	private Method[] methods = null;
	public boolean set(String name,Object value) throws Exception
	{
		//Call Method
		{
			if(methods==null)
				methods = this.getClass().getDeclaredMethods();

			String mName = "set_" + name;

			for (int i = 0; i<methods.length; i++)
		    {
		    	if(methods[i].getName().equalsIgnoreCase(mName))
		    	{
		    		methods[i].invoke(this,value);
		    		return true;
		    	}
		    }
		}

		//Set Field Values
		{
			if(fields == null)
				fields = this.getClass().getFields();

			for (int i = 0; i<fields.length; i++)
			{
				if(fields[i].getName().equalsIgnoreCase(name))
				{
					Field f = fields[i];
					Class t = f.getType();

					if(t.isPrimitive())
					{
						String str = value.toString();

						if(t.equals(Integer.TYPE))
						{
							f.setInt(this,Integer.parseInt(str));
						}
						else if(t.equals(Double.TYPE))
						{
							f.setDouble(this,Double.parseDouble(str));
						}else if(t.equals(Byte.TYPE))
						{
							f.setByte(this,Byte.parseByte(str));
						}else if(t.equals(Character.TYPE))
						{
							if(str.length()>0)
							{
								f.setChar(this,str.charAt(0));
							}else throw new Exception("Value is not of correct type");
						}else if(t.equals(Long.TYPE))
						{
							f.setLong(this,Long.parseLong(str));
						}else if (t.equals(Boolean.TYPE))
						{
							f.setBoolean(this,Boolean.parseBoolean(str));
						}
						else
							throw new RuntimeException("Not Supported: " + f.getName());
					}else
					{
						f.set(this,value);
					}

					return true;
				}
			}
		}

		return false;
	}
}
