package com.newrelic.metrics.publish;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;

import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import com.newrelic.metrics.publish.binding.Context;
import com.newrelic.metrics.publish.configuration.ConfigurationException;

/**
 * AgentFactory has two roles:
 * 1) Create new instances of an agent
 * 2) Map read in configuration tables to configured state of new agents
 */
public abstract class AgentFactory {
	private final String agentConfigurationFileName;
	private boolean configRequired = true;
	
//	TODO system property for config path
	private static final String CONFIG_PATH = "config";
	
	public AgentFactory(String agentConfigFileName) {
		super();
		this.agentConfigurationFileName = agentConfigFileName;
		this.configRequired = true;
	}

	public AgentFactory() {
		super();
		this.agentConfigurationFileName = null;
		this.configRequired = false;
	}
	
	/**
	 * Return a new instance of the appropriate Agent subclass, configured with information
	 * extracted from the @properties, a Map of configuration keys and values.
	 * 
	 * The keys and values are the result of processing the file referred to by
	 * getAgentConfigurationFileName().
	 * The specific keys and legal values are specific to the domain of the agent.
	 * Since the values come in as Object, casting and conversion may be required.
	*/
	
	public abstract Agent createConfiguredAgent(Map<String, Object> properties) throws ConfigurationException;
	
	/**
	 * Returns the name of the file which holds the agent configuration information,
	 * in JSON format.
	 * Subclasses can override
	 * @return String file name
	 */
	
	public String getAgentConfigurationFileName() {
		return agentConfigurationFileName;
	}
	
	/* protected */ void createConfiguredAgents(Runner runner) throws ConfigurationException {
        if(configRequired) {
    		File file = getConfigurationFile();
            Object parseResult = null;
            
    		try {
    	        FileReader reader = new FileReader(file);        
    	        JSONParser parser = new JSONParser();
    	        
    	        try {
    	        	parseResult = parser.parse(reader);
    			} catch (ParseException e) {
    				throw logAndThrow(Context.getLogger(), "Error parsing config file " + file.getAbsolutePath());
    			}
    		} catch(IOException ioEx) {
    			throw logAndThrow(Context.getLogger(), "Error reading config file " + file.getAbsolutePath());
    		}

    		JSONArray json = (JSONArray) parseResult;
        
	        for (int i = 0; i < json.size(); i++) {
	        	JSONObject obj = (JSONObject) json.get(i);
	        	@SuppressWarnings("unchecked")
	        	Map<String, Object> map = obj;
	        	createAndRegister(runner, map);
			}
        } else {
        	createAndRegister(runner, null);
        }
	}

	private void createAndRegister(Runner runner, Map<String, Object> map) throws ConfigurationException {
    	Agent agent = createConfiguredAgent(map);
    	Context.getLogger().fine("Created agent: " + agent);
    	runner.register(agent);
	}
	
    private File getConfigurationFile() throws ConfigurationException {
    	String configFileName = getAgentConfigurationFileName();
    	String path = CONFIG_PATH + File.separatorChar + configFileName;
        File file = new File(path);
        if (!file.exists()) {
        	throw logAndThrow(Context.getLogger(), "Cannot find config file " + path);
        }
        return file;
	}
    
    private ConfigurationException logAndThrow(Logger logger,String message) {
        logger.severe(message);
        return new ConfigurationException(message);
    }
}
@@ -2048,24 +2048,53 @@
     
-%09%09File file = 
+        JSONArray json = readJSONFile(getA
 ge
+n
 tCon
@@ -2107,17 +2107,22 @@
 tionFile
-(
+Name()
 );%0A     
@@ -2127,74 +2127,486 @@
     
+ 
-     Object parseResult = null;%0A            %0A    %09%09try %7B%0A    %09 
+%0A%09        for (int i = 0; i %3C json.size(); i++) %7B%0A%09        %09JSONObject obj = (JSONObject) json.get(i);%0A%09        %09@SuppressWarnings(%22unchecked%22)%0A%09        %09Map%3CString, Object%3E map = obj;%0A%09        %09createAndRegister(runner, map);%0A%09%09%09%7D%0A        %7D else %7B%0A        %09createAndRegister(runner, null);%0A        %7D%0A%09%7D%0A%0A%09public JSONArray readJSONFile(String filename) throws ConfigurationException %7B%0A%09%09Object parseResult = null;%0A%09%09%0A%09%09File file = getConfigurationFile(filename);%0A%0A%09%09try %7B%0A%09
    
+%09
     
@@ -2651,33 +2651,26 @@
 e);        %0A
-    %09    
+%09%09
     JSONPars
@@ -2703,31 +2703,17 @@
 ();%0A
-    %09        %0A    %09    
+%09%09    %0A%09%09
     
@@ -2722,17 +2722,10 @@
 y %7B%0A
-    %09    
+%09%09
     
@@ -2761,20 +2761,16 @@
 eader);%0A
-    
 %09%09%09%7D cat
@@ -2793,20 +2793,16 @@
 on e) %7B%0A
-    
 %09%09%09%09thro
@@ -2896,21 +2896,13 @@
 ));%0A
-    
 %09%09%09%7D%0A
-    
 %09%09%7D 
@@ -2927,20 +2927,16 @@
 ioEx) %7B%0A
-    
 %09%09%09throw
@@ -3029,21 +3029,13 @@
 ));%0A
-    
 %09%09%7D%0A%0A
-    
 %09%09JS
@@ -3078,316 +3078,22 @@
 lt;%0A
-        %0A%09        for (int i = 0; i %3C json.size(); i++) %7B%0A%09        %09JSONObject obj = (JSONObject) json.get(i);%0A%09        %09@SuppressWarnings(%22unchecked%22)%0A%09        %09Map%3CString, Object%3E map = obj;%0A%09        %09createAndRegister(runner, map);%0A%09%09%09%7D%0A        %7D else %7B%0A        %09createAndRegister(runner, null);%0A        %7D
+%09%09return json;
 %0A%09%7D%0A
@@ -3374,16 +3374,37 @@
 ionFile(
+String configFileName
 ) throws
@@ -3433,70 +3433,8 @@
 n %7B%0A
-    %09String configFileName = getAgentConfigurationFileName();%0A
     
@@ -3856,10 +3856,14 @@
 );%0A    %7D
+    
 %0A%7D

Support reading additional JSON properties files