package com.k_int.discover.lookup.identifier;

import com.k_int.discover.lookup.datamodel.LookupResultDTOComparator;
import com.k_int.discover.datamodel.CultureGrid_BaseHDO;
import com.k_int.discover.datamodel.CultureGrid_CollectionHDO;
import com.k_int.discover.datamodel.CultureGrid_InstitutionHDO;
import com.k_int.discover.datamodel.CultureGrid_ItemHDO;
import com.k_int.discover.lookup.datamodel.LookupResultDTO;
import com.opensymphony.xwork2.ActionSupport;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeSet;
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 given a specific identifier looks it up in the CultureGrid
 * datamodel in all possible identifier fields and returns all of the information
 * we hold about the given record
 *
 * @author rpb rich@k-int.com
 * @version 1.0 31.08.10
 * 
 */
public class LookupIdentifier extends ActionSupport implements ServletRequestAware, ApplicationContextAware {
	private static final long serialVersionUID = -5874876412934058656L;

	private static Log log = LogFactory.getLog(LookupIdentifier.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 recordsInfo;

    public String getRecordsInfo() {
        return this.recordsInfo;
    }
    
    @Override
    public String execute() {
        log.debug("LookupIdentifier::execute method called");
        
        String returnValue = SUCCESS;

        Session sess = null;

        try {
            sess = factory.openSession();

            String identifier = request.getParameter("id");
            String recordType = request.getParameter("recordType");
            if ( recordType == null || "".equals(recordType.trim()) )
                recordType = "all";
            String sourceId = request.getParameter("sourceId");
            if ( sourceId == null || "".equals(sourceId.trim()) )
                sourceId = "ALL";
            else
                sourceId = sourceId.trim();
            
            log.debug("identifier = " + identifier + " and recordType = " + recordType + " and sourceId = " + sourceId);

            // Get the base URL of the system from the properties file - used when creating
            // the various links to each of the instances, etc.
            ResourceBundle bundle = null;
	    try {
	      bundle = ResourceBundle.getBundle("identifierLookup", Locale.getDefault());
	    } catch (MissingResourceException mre) {
	      //leave null and use defaults.
	    }
            String baseURL = null;
            if ( bundle.containsKey("com.k_int.discover.lookup.serverName") ) {
                baseURL = bundle.getString("com.k_int.discover.lookup.serverName");
                if ( baseURL == null || "".equals(baseURL.trim()) )
                    baseURL = "http://localhost:8080";

            }

            log.debug("LookupIdentifier::execute - baseURL is set to " + baseURL);

            // Find all records with identifier as the primary identifier
            Set<CultureGrid_BaseHDO> allMatchingRecords = new HashSet<CultureGrid_BaseHDO>();
            Map<Long,String> matchMethod = new HashMap<Long,String>();

            // Add the record that uses the identifier as the aggregator internal id (if it's a number)
            try {
                Long potentialInternalId = Long.parseLong(identifier);
                if ( potentialInternalId > 0l ) {
                    // We have a possible ID - look for it..
                    CultureGrid_BaseHDO directMatch = CultureGrid_BaseHDO.lookupByResourceId(sess, potentialInternalId);
                    if ( directMatch != null ) {
                        // Check that the matching record is of the requested type and from the given source
                        if ( shouldAddRecord(directMatch, recordType, sourceId) ) {
                            allMatchingRecords.add(directMatch);
                            matchMethod.put(directMatch.getId(), "Internal CultureGrid identifier match");
                        }
                    }
                }
            } catch (NumberFormatException nfe) {
                // Not a number - don't worry..
            }

            // Add all records that use identifier as the primary identifier
            List<CultureGrid_BaseHDO> tempSet = CultureGrid_BaseHDO.lookupByIdentifier(sess, identifier);
            Iterator<CultureGrid_BaseHDO> tempIter = tempSet.iterator();
            while(tempIter.hasNext()) {
                CultureGrid_BaseHDO nextHDO = tempIter.next();
                if ( shouldAddRecord(nextHDO, recordType, sourceId) ) {
                    allMatchingRecords.add(nextHDO);
                    matchMethod.put(nextHDO.getId(), "Primary identifier match");
                }
            }
            
            // Add all records that use identifier as an alternative DC identifier
            tempSet = CultureGrid_BaseHDO.lookupByOtherDCIdentifier(sess, identifier);
            tempIter = tempSet.iterator();
            while(tempIter.hasNext()) {
                CultureGrid_BaseHDO nextHDO = tempIter.next();
                if ( shouldAddRecord(nextHDO, recordType, sourceId) ) {
                    allMatchingRecords.add(nextHDO);
                    matchMethod.put(nextHDO.getId(), "Additional dc:identifier match");
                }
            }

            // Add all collection records that use identifier as an 'other identifier'
            List<CultureGrid_CollectionHDO> tempCollSet = CultureGrid_CollectionHDO.lookupByOtherIdentifier(sess, identifier);
            Iterator<CultureGrid_CollectionHDO> tempCollIter = tempCollSet.iterator();
            while(tempCollIter.hasNext()) {
                CultureGrid_BaseHDO nextHDO = tempCollIter.next();
                if ( shouldAddRecord(nextHDO, recordType, sourceId) ) {
                    allMatchingRecords.add(nextHDO);
                    matchMethod.put(nextHDO.getId(), "Collection other identifier match");
                }
            }

            // Add all institution records that use identifier as an 'other identifier'
            List<CultureGrid_InstitutionHDO> tempInstSet = CultureGrid_InstitutionHDO.lookupByOtherIdentifier(sess, identifier);

            Iterator<CultureGrid_InstitutionHDO> tempInstIter = tempInstSet.iterator();
            while(tempInstIter.hasNext()) {
                CultureGrid_BaseHDO nextHDO = tempInstIter.next();
                if ( shouldAddRecord(nextHDO, recordType, sourceId) ) {
                    allMatchingRecords.add(nextHDO);
                    log.debug("About to log something..");
                    log.debug("About to add nextHDO: " + nextHDO.toString());
                    matchMethod.put(nextHDO.getId(), "Institution other identifier match");
                }
            }

            log.debug("After doing all the lookups allMatchingRecords.size = " + allMatchingRecords.size());
            
            // Loop through the matching records and create the relevant DTOs ready to create the XML we need
            Iterator<CultureGrid_BaseHDO> hdoIter = allMatchingRecords.iterator();
            Set<LookupResultDTO> recordDtos = new TreeSet<LookupResultDTO>(new LookupResultDTOComparator());
            while( hdoIter.hasNext() ) {
                CultureGrid_BaseHDO nextRecord = hdoIter.next();

                if ( nextRecord != null) {
                    String thisMatchMethod = matchMethod.get(nextRecord.getId());
                    LookupResultDTO tempRecDTO = LookupResultDTO.CreateLookupResultDTO(nextRecord, baseURL, thisMatchMethod);

                    if ( tempRecDTO != null ) {
                        recordDtos.add(tempRecDTO);
                    }
                }

                
            }

            // Loop through each record creating the relevant XML
            StringBuilder recordsBuilder = new StringBuilder();
            recordsBuilder.append("<records searchIdentifier=\"" + identifier + "\" numFound=\"" + recordDtos.size() + "\" recordType=\"" + recordType + "\">\n");

            Iterator<LookupResultDTO> recordIter = recordDtos.iterator();
            while(recordIter.hasNext()) {
                LookupResultDTO nextRec = recordIter.next();
                if ( nextRec != null ) {
                    String tempXML = nextRec.toXML();
                    if ( tempXML != null && !"".equals(tempXML.trim()))
                        recordsBuilder.append(tempXML);
                }
            }

            recordsBuilder.append("</records>\n");

            this.recordsInfo = recordsBuilder.toString();

            request.setAttribute("recordsInfo", this.recordsInfo);

            
        } 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!
                }
            }
        }
        
        return returnValue;
    }


    private boolean shouldAddRecord(CultureGrid_BaseHDO record, String requestedRecordType, String sourceId) {

        boolean retVal = false;
        
        if ( "all".equalsIgnoreCase(requestedRecordType) ) {
            retVal = true;
        } else {
            String actualRecordType = null;
            if ( record instanceof CultureGrid_ItemHDO )
                actualRecordType = "item";
            else if ( record instanceof CultureGrid_CollectionHDO )
                actualRecordType = "collection";
            else if ( record instanceof CultureGrid_InstitutionHDO )
                actualRecordType = "institution";
            else {
                // Unknown record type - don't add it in just in case..
                retVal = false;
            }

            if ( actualRecordType != null ) {
                if ( actualRecordType.equalsIgnoreCase(requestedRecordType) )
                    retVal = true;
            }
        }

        if ( retVal  && !"ALL".equals(sourceId)) {
            // Other tests have passed - check against the source ID
            String actualSourceId = record.getResource().getSource().getIdentifier();

            if ( !actualSourceId.equalsIgnoreCase(sourceId) ) {
                retVal = false;
            }
        }

        return retVal;
    }
}
