package flow;

import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;

import org.codehaus.jackson.map.ObjectMapper;

import com.avaya.ingensg.ce.wa.imrest.common.model.MetricsRequest;
import com.avaya.ingensg.ce.wa.imrest.common.model.Service;
import com.avaya.ingensg.ce.wa.imrest.common.model.ServiceMetrics;
import com.avaya.sce.runtime.tracking.ReportInfo;
import com.avaya.sce.runtimecommon.IReportInfo;

import flow.constants.SSAConstants;
import flow.pojo.Attribute;
import flow.utils.Utils;

/**
 * A basic servlet which allows a user to define their code, generate
 * any output, and to select where to transition to next.
 * Last generated by Orchestration Designer at: 2013-JUN-04  11:07:56 AM
 */
public class BuildServiceMap extends com.avaya.sce.runtime.BasicServlet {

	//{{START:CLASS:FIELDS
	//}}END:CLASS:FIELDS

	/**
	 * Default constructor
	 * Last generated by Orchestration Designer at: 2013-JUN-04  11:07:56 AM
	 */
	public BuildServiceMap() {
		//{{START:CLASS:CONSTRUCTOR
		super();
		//}}END:CLASS:CONSTRUCTOR
	}

	/**
	 * This method allows for custom integration with other Java components.
	 * You may use Java for sophisticated logic or to integrate with custom
	 * connectors (i.e. JMS, custom web services, sockets, XML, JAXB, etc.)
	 *
	 * Any custom code added here should work as efficiently as possible to prevent delays.
	 * It's important to design your callflow so that the voice browser (Voice Portal/IR)
	 * is not waiting too long for a response as this can lead to a poor caller experience.
	 * Additionally, if the response to the client voice browser exceeds the configured
	 * timeout, the platform may throw an "error.badfetch". 
	 *
	 * Using this method, you have access to all session variables through the 
	 * SCESession object.
	 *
	 * The code generator will *** NOT *** overwrite this method in the future.
	 * Last generated by Orchestration Designer at: 2013-JUN-04  11:07:56 AM
	 */
	public void servletImplementation(com.avaya.sce.runtimecommon.SCESession mySession) {

		//Start building the WA Service Map
        Map<Integer, Service> serviceMap = new LinkedHashMap<Integer, Service>();		
        
        Integer requiredResource = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.REQUEST_TYPE, IProjectVariables.REQUEST_TYPE_FIELD_REQUIRED_RESOURCE, mySession));       
        Integer requestTypeSelection = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.SELECT_SPECIFIED_RESOURCE, IProjectVariables.SELECT_SPECIFIED_RESOURCE_FIELD_VALUE, mySession));
        Integer priority = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.PROPERTIES, IProjectVariables.PROPERTIES_FIELD_PRIORITY, mySession));       

		try {	    
			//Get the list of high-priority customers (taken from properties file in this sample)
			String customerId = (String)Utils.getVariableField(IProjectVariables.COLLECT_CUSTOMER_ID, IProjectVariables.COLLECT_CUSTOMER_ID_FIELD_VALUE, mySession);
			String priorityCustomerData = (String)Utils.getVariableField(IProjectVariables.PROPERTIES, IProjectVariables.PROPERTIES_FIELD_PRIORITY_CUSTOMER, mySession);

			if (!Utils.isStringBlank(priorityCustomerData)) {
				String priorityCustomers[] = priorityCustomerData.split(SSAConstants.DELIMITER_COMMA + "\\s*");			
				for (String priorityCustomer : priorityCustomers){
					if (priorityCustomer.compareToIgnoreCase(customerId) == 0){                		
						//Top priority caller has dialled in
						priority = 1;
						Utils.logInfo("Setting top priority customer " + customerId, mySession);
	                    break;
					}
				}
			}				
			
			if (requestTypeSelection != requiredResource) {
				//Get available attributes and the customer priority (taken from properties file in this sample)
				Map<String, Attribute> attributesMap = (Map<String, Attribute>)Utils.getVariableField(IProjectVariables.ATTRIBUTES, mySession);
				
				//Selections (example - 'Service' & 'Language')
				//Set the 'selected index' value on each Category
				String menu1Category = (String)Utils.getVariableField(IProjectVariables.MENU_CATEGORIES, IProjectVariables.MENU_CATEGORIES_FIELD_MENU_1CATEGORY, mySession);
				String menu2Category = (String)Utils.getVariableField(IProjectVariables.MENU_CATEGORIES, IProjectVariables.MENU_CATEGORIES_FIELD_MENU_2CATEGORY, mySession);
				int selectedMenu1Value = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.FIRST_MENU_SELECTION, IProjectVariables.FIRST_MENU_SELECTION_FIELD_INDEX, mySession));
				int selectedMenu2Value = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.SECOND_MENU_SELECTION, IProjectVariables.SECOND_MENU_SELECTION_FIELD_INDEX, mySession));			
				attributesMap.get(menu1Category).setSelectedIndex(selectedMenu1Value - 1);
				attributesMap.get(menu2Category).setSelectedIndex(selectedMenu2Value - 1);
		
				//Then retrieve the value selected in each case
				String menu1Value = attributesMap.get(menu1Category).getValues().get(selectedMenu1Value - 1).getKey();			
				String menu2Value = attributesMap.get(menu2Category).getValues().get(selectedMenu2Value - 1).getKey();
				Utils.logInfo("Selected " + menu1Category + " value: " + menu1Value, mySession);
				Utils.logInfo("Selected " + menu2Category + " value: " + menu2Value, mySession);
				//Save the selected values for later
				Utils.setVariableField(IProjectVariables.MENU_CATEGORIES, IProjectVariables.MENU_CATEGORIES_FIELD_MENU_1SELECTION, menu1Value, mySession);
				Utils.setVariableField(IProjectVariables.MENU_CATEGORIES, IProjectVariables.MENU_CATEGORIES_FIELD_MENU_2SELECTION, menu2Value, mySession);								
	
				//Add the first element in the 'third' Category as an example
				String serviceMapCategory = (String)Utils.getVariableField(IProjectVariables.SAMPLE_CATEGORY, mySession);
				attributesMap.get(serviceMapCategory).setSelectedIndex(0);			
				String serviceMapValue = attributesMap.get(serviceMapCategory).getValues().get(0).getKey();			

		        Service service = new Service.Builder()
				        .priority(priority)
				        .addAttributeCategory(menu1Category).withValues(menu1Value)
				        .addAttributeCategory(menu2Category).withValues(menu2Value)
				        .addAttributeCategory(serviceMapCategory).withValues(serviceMapValue)
				        .addAttributeCategory(SSAConstants.CATEGORY_CHANNEL).withValues(SSAConstants.ATTRIBUTE_CHANNEL)
				        .build();

		        // Read optional fields from config and set if available
		        setOptionalFields(service, mySession);
		        
		        // Add complete service object to serviceMap 
		        serviceMap.put(1, service);          
		        
		        //Check if any additional Q2M attributes have been specified in config file	        
		        String q2Multiple = (String)Utils.getVariableField(IProjectVariables.Q_2MULTIPLE_SERVICES, mySession);
		        if (!Utils.isStringBlank(q2Multiple)){
		        	Map<Integer, Service> q2MultipleMap = Utils.convertStringToServiceMap(q2Multiple, mySession);	        	        	
		        	
		        	//Merge the two maps
		        	Map<Integer, Service> mergedMap = new LinkedHashMap<Integer, Service>();
		        	mergedMap.putAll(serviceMap);
		        	mergedMap.putAll(q2MultipleMap);
		        	serviceMap = mergedMap;
		        }
		        
				//Convert map to JSON string using Jackson	        
		        ObjectMapper mapper = new ObjectMapper();
				String jsonServiceMap = mapper.writeValueAsString(serviceMap);			       
		        
		        Utils.logInfo("Service Map Built: " + jsonServiceMap, mySession);        				
	            Utils.setVariableField(IProjectVariables.CONTEXT, IProjectVariables.CONTEXT_FIELD_SERVICE_MAP, jsonServiceMap, mySession);
	
				//Start building the WA Service Metrics Map
	            //Copy the attributes and priority from the Service Map
		        Map<Integer, ServiceMetrics> serviceMapMetrics = new LinkedHashMap<Integer, ServiceMetrics>();		
				
		        ServiceMetrics serviceMetric = new ServiceMetrics();
		        serviceMetric.setAttributes(service.getAttributes());
		        serviceMetric.setPriority(service.getPriority());	        
	        
		        serviceMapMetrics.put(1, serviceMetric); 
	          
	            MetricsRequest metrics = new MetricsRequest();            
	            metrics.setServiceMap(serviceMapMetrics);            
	            metrics.setId((String)Utils.getVariableField(IProjectVariables.PROPERTIES, IProjectVariables.PROPERTIES_FIELD_CALL_ID, mySession));
	            	       	        
				//Convert map to JSON string using Jackson	        
				String jsonMetricsRequest = mapper.writeValueAsString(metrics);			
				Utils.setVariableField(IProjectVariables.SERVICE_METRICS, jsonMetricsRequest, mySession);
		        
		        Utils.logInfo("Metrics Request: " + (String)Utils.getVariableField(IProjectVariables.SERVICE_METRICS, mySession), mySession);      
			} else {
				//Convert map to JSON string using Jackson	        
		        ObjectMapper mapper = new ObjectMapper();
				String jsonServiceMap = mapper.writeValueAsString(serviceMap);		
		        Utils.logInfo("Created empty ServiceMap for RequiredResource request", mySession);        				
	            Utils.setVariableField(IProjectVariables.CONTEXT, IProjectVariables.CONTEXT_FIELD_SERVICE_MAP, jsonServiceMap, mySession);				
			}
			

		} catch (IOException e) {							
			Utils.logError("Exception caught processing Service Map: " + e, mySession);
	        ReportInfo report =  new com.avaya.sce.runtime.tracking.ReportInfo(
	                IReportInfo.REPORT_TYPE_PROGRESS, 
	                IReportInfo.ALARM_LEVEL_MAJOR, 
	                SSAConstants.REPORTING_TAG, 
	                "Error Building Service Map",
	                e.getMessage());	        
	        report.trackItems(mySession);
		} catch ( NullPointerException e) {							
			Utils.logError("Exception caught processing Service Map: " + e, mySession);
	        ReportInfo report =  new com.avaya.sce.runtime.tracking.ReportInfo(
	                IReportInfo.REPORT_TYPE_PROGRESS, 
	                IReportInfo.ALARM_LEVEL_MAJOR, 
	                SSAConstants.REPORTING_TAG, 
	                "Error Building Service Map",
	                e.getMessage());	        
	        report.trackItems(mySession);
		} 
	}	
	
	private void setOptionalFields(Service service, com.avaya.sce.runtimecommon.SCESession mySession) {
        // Rank is optional, only set on service if Rank is set in config	        
        Integer rank;
        try {
			 rank = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.PROPERTIES, IProjectVariables.PROPERTIES_FIELD_RANK, mySession));
			 service.setRank(rank);
        } catch (NumberFormatException e) {
			//Utils.logInfo("Rank not available in config, not setting rank on service", mySession);		        	
        }
        
        // ProficiencyMin is optional, only set on service if ProficiencyMin is set in config	        
        Integer proficiencyMin;
        try {
        	proficiencyMin = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.PROPERTIES, IProjectVariables.PROPERTIES_FIELD_MIN_PROFICIENCY, mySession));
			 service.setMinProficiency(proficiencyMin);
        } catch (NumberFormatException e) {
			//Utils.logInfo("MinProficiency not set in config, not setting minProficiency on service", mySession);		        	
        }
        
        // ProficiencyMax is optional, only set on service if ProficiencyMax is set in config	        
        Integer proficiencyMax;
        try {
        	proficiencyMax = Integer.valueOf((String)Utils.getVariableField(IProjectVariables.PROPERTIES, IProjectVariables.PROPERTIES_FIELD_MAX_PROFICIENCY, mySession));
			 service.setMaxProficiency(proficiencyMax);
        } catch (NumberFormatException e) {
			//Utils.logInfo("MaxProficiency not set in config, not setting maxProficiency on service", mySession);		        	
        }        		     
	}
	
	/**
	 * Builds the list of branches that are defined for this servlet object.
	 * This list is built automatically by defining Goto nodes in the call flow editor.
	 * It is the programmer's responsibilty to provide at least one enabled Goto.<BR>
	 *
	 * The user should override updateBranches() to determine which Goto that the
	 * framework will activate.  If there is not at least one enabled Goto item, 
	 * the framework will throw a runtime exception.<BR>
	 *
	 * This method is generated automatically and changes to it may
	 * be overwritten next time code is generated.  To modify the list
	 * of branches for the flow item, override:
	 *     <code>updateBranches(Collection branches, SCESession mySession)</code>
	 *
	 * @return a Collection of <code>com.avaya.sce.runtime.Goto</code>
	 * objects that will be evaluated at runtime.  If there are no gotos
	 * defined in the Servlet node, then this returns null.
	 * Last generated by Orchestration Designer at: (timestamp generation disabled)
	 */
	public java.util.Collection getBranches(com.avaya.sce.runtimecommon.SCESession mySession) {
		java.util.List list = null;
		com.avaya.sce.runtime.Goto aGoto = null;
		list = new java.util.ArrayList(1);

		aGoto = new com.avaya.sce.runtime.Goto("GetServiceMetrics", 0, true, "Default");
		list.add(aGoto);

		return list;
	}
}
