package com.k_int.discover.lookup.schema;

import com.k_int.discover.datamodel.schema.dto.SchemaDTO;
import com.k_int.discover.datamodel.schema.dto.SchemaElementDTO;
import com.k_int.discover.datamodel.schema.dto.SchemaSectionDTO;
import com.k_int.generic.schema.hdo.SchemaHDO;
import com.opensymphony.xwork2.ActionSupport;
import java.util.List;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * An action that details a schema as used by CG
 * 
 * @author rpb rich@k-int.com
 * @version 1.0 02.02.12
 * 
 */
public class ShowSchema extends ActionSupport implements ServletRequestAware, ApplicationContextAware {
	private static final long serialVersionUID = 163168287793201234L;

	private static Log log = LogFactory.getLog(ShowSchema.class);
    
    protected HttpServletRequest request;
    protected ApplicationContext ctx;
    protected SessionFactory factory;

    public void setServletRequest(HttpServletRequest request) { this.request = request; }
    public void setApplicationContext(ApplicationContext ctx) {	this.ctx = ctx; }
    public void setSessionFactory(SessionFactory factory) { this.factory = factory; }

    private String schemaInfo = "";

    public String getSchemaInfo() {
        return this.schemaInfo;
    }
    
    @Override
    public String execute() {
        log.debug("ShowSchema::execute method called");
        
        String returnValue = SUCCESS;

        Session sess = null;

        String identifierStr = request.getParameter("id");
        Long identifier = 0l;
        String schemaName = request.getParameter("name");
        
        log.debug("identifierStr = " + identifierStr + " and schemaName = " + schemaName);

        String lookupType = null;

        if ( identifierStr != null && !"".equals(identifierStr.trim()) ) {
            identifier = new Long(identifierStr);
            lookupType = "identifier";
        } else if ( schemaName != null && !"".equals(schemaName.trim()) ) {
            lookupType = "name";
        }


        if ( lookupType == null ) {
            // Nothing to lookup - return an error
            this.schemaInfo = setupErrorResponse("No id or name specified to lookup the schema");
        } else {

            ResourceBundle bundle = this.getSolrMappingsBundle();
                
            if ( bundle != null ) {

                try {
                    sess = factory.openSession();


                    SchemaHDO schema = null;

                    // Get the schema using the appropriate method
                    if ( "identifier".equals(lookupType) ) {
                        // Get the schema by identifier
                        schema = SchemaHDO.lookupById(sess, identifier);
                    } else {
                        // Get the schema by name
                        List<SchemaHDO> tempSchemas = SchemaHDO.lookupByName(sess, schemaName);
                        if ( tempSchemas != null && !tempSchemas.isEmpty() ) {
                            schema = tempSchemas.iterator().next();
                        }
                    }

                    // Should have the schema by now - process
                    if ( schema != null ) {
                        // We have a schema
                        
                        // Convert to a DTO for convenience methods..
                        SchemaDTO schemaDto = new SchemaDTO(schema);
                        

                        StringBuilder retvalBuilder = new StringBuilder();
                        retvalBuilder.append("{");
                        retvalBuilder.append("\"success\":\"true\",");
                        retvalBuilder.append("\"message\":\"\",");
                        retvalBuilder.append("\"id\":").append(schemaDto.getId()).append(",");
                        retvalBuilder.append("\"name\":\"").append(getValue(schemaDto.getName())).append("\",");
                        retvalBuilder.append("\"description\":\"").append(getValue(schemaDto.getDescription())).append("\",");
                        retvalBuilder.append("\"type\":\"").append(schemaDto.getSchemaType()).append("\",");
                        retvalBuilder.append("\"structure\":[");

                        boolean sectionOutput = false;

                        for(SchemaSectionDTO section: schemaDto.getOrderedSections()) {
                            if ( sectionOutput )
                                retvalBuilder.append(",");

                            // Output the section
                            retvalBuilder.append("{\"sectionName\":\"").append(getValue(section.getName())).append("\",");
                            retvalBuilder.append("\"position\":").append(section.getPosition()).append(",");
                            retvalBuilder.append("\"fields\":[");

                            // Output the elements in this section
                            boolean elementOutput = false;
                            for(SchemaElementDTO element: section.getOrderedFields()) {
                                if ( elementOutput )
                                    retvalBuilder.append(",");

                                // Work out the relevant solr field for this element
                                String mappingKey = element.getProperty().getMappingKey();
                                String solrField = "NO_MAPPING_SPECIFIED";
                                String mappingPrefix = schemaDto.getSchemaType().toString() + ".";
                                
                                if ( mappingKey != null && !"".equals(mappingKey.trim()) ) {
                                    mappingKey = mappingPrefix + mappingKey;
                                    log.debug("Looking for mappingKey: " + mappingKey);
                                    
                                    if ( bundle.containsKey(mappingKey) ) {
                                        String solrMap = (String)bundle.getObject(mappingKey);
                                        if ( solrMap != null && !"".equals(solrMap.trim()) )
                                            solrField = solrMap.trim();
                                    }
                                }

                                // Output the element
                                retvalBuilder.append("{");
                                retvalBuilder.append("\"label\":\"").append(getValue(element.getLabel())).append("\",");
                                retvalBuilder.append("\"mappingKey\":\"").append(getValue(element.getProperty().getMappingKey())).append("\",");
                                retvalBuilder.append("\"solrField\":\"").append(getValue(solrField)).append("\",");
                                retvalBuilder.append("\"description\":\"").append(getValue(element.getProperty().getDescription())).append("\",");
                                retvalBuilder.append("\"tooltip\":\"").append(getValue(element.getTooltip())).append("\",");
                                retvalBuilder.append("\"position\":").append(element.getPosition()).append(",");
                                
                                retvalBuilder.append("\"value\":{");
                                    retvalBuilder.append("\"min\":").append(element.getLowerBound()).append(",");
                                    retvalBuilder.append("\"max\":").append(element.getUpperBound()).append(",");                        
                                    retvalBuilder.append("\"defaultValue\":\"").append(getValue(element.getDefaultValue())).append("\",");
                                    if ( element.getOverrideType() != null ) {
                                        retvalBuilder.append("\"type\":\"").append(element.getOverrideType()).append("\",");
                                    } else {
                                        retvalBuilder.append("\"type\":\"").append(element.getProperty().getPropertyType()).append("\",");
                                    }
                                    retvalBuilder.append("\"vocabulary\":{");
//                                    if ( element.getBankURL() != null ) {
                                        retvalBuilder.append("\"url\":\"").append(getValue(element.getBankURL())).append("\",");
                                        retvalBuilder.append("\"vocab\":\"").append(getValue(element.getVocabulary())).append("\",");
                                        retvalBuilder.append("\"authority\":\"").append(getValue(element.getAuthority())).append("\"");
//                                    }
                                    retvalBuilder.append("},");
                                    retvalBuilder.append("\"editable\":").append(element.getInitialiseOnly());
                                retvalBuilder.append("},");
                                
                                retvalBuilder.append("\"minOccurs\":").append(element.getMinOccurs()).append(",");
                                retvalBuilder.append("\"maxOccurs\":").append(element.getMaxOccurs());
                                retvalBuilder.append("}");

                                elementOutput = true;
                            }

                            retvalBuilder.append("]}");

                            sectionOutput = true;
                        }

                        retvalBuilder.append("]");

                        retvalBuilder.append("}");


                        this.schemaInfo = retvalBuilder.toString();

                    } else {
                        // No schema found - return an error
                        this.schemaInfo = setupErrorResponse("No schema found using the id or name specified");
                    }


                } catch (HibernateException he) {
                    log.error("HibernateException thrown: " + he.getMessage());
                    he.printStackTrace();
                } finally {
                    if ( sess != null ) {
                        try {
                            sess.close();
                        } catch (HibernateException he) {
                            // Can't do anything!
                        }
                    }
                }
            } else {
                // No mappings - return error
                this.schemaInfo = setupErrorResponse("No mappings document found to specify which solr fields are used by the schema");
            }
        }
        
        request.setAttribute("schemaInfo", this.schemaInfo);
        
        return returnValue;
    }


    /**
     * Read the properties file and build up the mappings from object fields to solr fields
     * @return The mappings from object field names to solr fields
     */
    private ResourceBundle getSolrMappingsBundle() {
    
        ResourceBundle bundle = null;
        try {
          bundle = ResourceBundle.getBundle("solrMappings", Locale.getDefault());
        } catch (MissingResourceException mre) {
            log.error("Unable to find the solr mappings properties");
        }
        
        return bundle;
    }
    
    private String getValue(String possibleValue) {
        String retval = "";
        
        if ( possibleValue != null ) {
            retval = possibleValue.trim();
        }
        
        return retval;
    }
    
    private String setupErrorResponse(String message) {
        
        StringBuilder retvalBuilder = new StringBuilder();
        
        retvalBuilder.append("{");
        retvalBuilder.append("\"success\":\"false\",");
        retvalBuilder.append("\"message\":\"").append(message).append("\",");
        retvalBuilder.append("\"id\":-1,");
        retvalBuilder.append("\"name\":\"\",");
        retvalBuilder.append("\"description\":\"\",");
        retvalBuilder.append("\"type\":\"\",");
        retvalBuilder.append("\"structure\":[]");
        retvalBuilder.append("}");
        
        return retvalBuilder.toString();

    }
}
