/*
 * Created on Nov 1, 2004
 * Copyright (C) 2004, 2005 Andrea Schweer
 *
 * This file is part of the Greenstone Alerting Service.
 * Refer to the COPYING file in the base directory of this package
 * for licensing information.
 */
package org.greenstone.gsdlas.profiles;

import java.sql.SQLException;
import java.util.*;
import java.util.Map;
import java.util.TreeMap;

import org.greenstone.gsdlas.Constants;
import org.greenstone.gsdlas.database.DatabaseException;


/**
 * @author schweer
 * 
 * TODO To change the template for this generated type comment go to Window -
 * Preferences - Java - Code Style - Code Templates
 */
public abstract class PredicateFactory {

    private static int id = 0; 
    
    private static Map equalsPredicates = new TreeMap();
    
    // substring for collection_name -> SubstringMatchPredicates referring to it
    private static Map collectionNameMatchPredicates = new TreeMap();
    private static Map hostNameMatchPredicates = new TreeMap();
    
    // query -> QueryPredicates referring to it
    private static Map documentTitleQueryPredicates = new TreeMap();
    private static Map documentContentQueryPredicates = new TreeMap();
    
    
    /**
     * @param key
     * @param value
     * @return
     * @throws ParseException
     * @throws DatabaseException
     * @throws SQLException
     */
    public static Predicate createPredicate(String key, String value)
            throws SQLException, DatabaseException {
        System.out.println("creating predicate for key " + key + " and value " + value);
        if (!Predicate.isSingleValued(key)) {
            return null;
        }
        Predicate result = null;
        if (value == null || value.length() == 0) {
            return null;
        }
        
        if (Predicate.isMultiValued(key)) {
            List list = new ArrayList();
            list.add(value);
            return (Predicate) createPredicates(key, list).get(0);
        } else if (key.startsWith("document")) {
            result = createQueryPredicate(key, value);
        } else if (key.endsWith("_query")) {
            result = createSubstringMatchPredicate(key, value);
        } else {
        	return null;
        }
        result.setID(result.saveToDatabase());
        return result;
    }
    
    public static List createPredicates(String key, List values) throws SQLException, DatabaseException {
        if (!Predicate.isMultiValued(key)) {
            return null;
        }
        List results = createEqualsPredicates(key, values);
        for (Iterator iter = results.iterator(); iter.hasNext();) {
            EqualsPredicate pred = (EqualsPredicate) iter.next();

            pred.setID(pred.saveToDatabase());
        }
        return results;
    }

    /**
     * @param key
     * @param value
     * @return
     */
    private static SubstringMatchPredicate createSubstringMatchPredicate(String key, String value) {
        SubstringMatchPredicate predicate = null;
        if (key.equals(Constants.COLLECTION_QUERY_FIELD)) {
            if (collectionNameMatchPredicates.containsKey(value)) {
                predicate = (SubstringMatchPredicate) collectionNameMatchPredicates.get(value);
            } else {
                predicate = new SubstringMatchPredicate(Constants.COLLECTION_ID_FIELD, value);
                collectionNameMatchPredicates.put(value, predicate);
            }
        } else if (key.equals(Constants.HOST_QUERY_FIELD)) {
            if (hostNameMatchPredicates.containsKey(value)) {
                predicate = (SubstringMatchPredicate) hostNameMatchPredicates.get(value);
            } else {
                predicate = new SubstringMatchPredicate(Constants.HOST_ID_FIELD, value);
                hostNameMatchPredicates.put(value, predicate);
            }
        }
        // TODO other fields?
        return predicate;
    }

    /**
     * @param key
     * @param values
     * @return
     */
    private static List createEqualsPredicates(String key, List values) {
        List result = new Vector();
        
        Map keyToPredicates;
        if (!equalsPredicates.containsKey(key)) {
            keyToPredicates = new HashMap();
            equalsPredicates.put(key, keyToPredicates);
        }
        keyToPredicates = (Map) equalsPredicates.get(key);
        
        for (Iterator iter = values.iterator(); iter.hasNext();) {
            String value = (String) iter.next();
            if (value == null || value.length() == 0) {
                continue;
            }

            if (key.equals(Constants.HOST_ID_FIELD) && !(value.startsWith("http://"))) {
                value = "http://" + value + ":8080/soap/servlet/rpcrouter";
            }
            
            EqualsPredicate predicate = null;
            if (keyToPredicates.containsKey(value)) {
                predicate = (EqualsPredicate) keyToPredicates.get(value);
            } else {
                predicate = new EqualsPredicate(key, value);
                keyToPredicates.put(value, predicate);
            }
            result.add(predicate);
        }
        return result;
    }
    
    /**
     * @param field
     * @param query
     * @return
     */
    private static QueryPredicate createQueryPredicate(String field,
            String query) {
        QueryPredicate predicate = null;
        if (field.equals(Constants.DOCUMENT_CONTENT_FIELD)) {
            if (!documentContentQueryPredicates.containsKey(query)) {
                predicate = new QueryPredicate(field, query);
                documentContentQueryPredicates.put(query, predicate);
            }
            return (QueryPredicate) documentContentQueryPredicates.get(query);
        } else if (field.equals(Constants.DOCUMENT_TITLE_FIELD)) {
            if (!documentTitleQueryPredicates.containsKey(query)) {
                predicate = new QueryPredicate(field, query);
                documentTitleQueryPredicates.put(query, predicate);
            }
            return (QueryPredicate) documentTitleQueryPredicates.get(query);
        }
        return predicate;
    }

    public static Collection getAllQueryPredicates() {
        Set result = new TreeSet();
        result.addAll(documentTitleQueryPredicates.values());
        result.addAll(documentContentQueryPredicates.values());
        return Collections.unmodifiableSet(result);
    }
    
    public static Collection getQueryPredicates(String field) {
        Set result = new TreeSet();
        if (field.equals(Constants.DOCUMENT_TITLE_FIELD)) {
            result.addAll(documentTitleQueryPredicates.values());
        } else if (field.equals(Constants.DOCUMENT_CONTENT_FIELD)) {
            result.addAll(documentContentQueryPredicates.values());
        }
        return Collections.unmodifiableSet(result);
    }
    
    public static Collection getAllSubstringMatchPredicates() {
        Collection result = new Vector();
        result.addAll(hostNameMatchPredicates.values());
        result.addAll(collectionNameMatchPredicates.values());
        return Collections.unmodifiableCollection(result);
    }

    /**
     * @param string
     * @param string2
     * @return
     */
    public static EqualsPredicate getEqualsPredicate(String key, String value) {
        EqualsPredicate result = null; 
        if (equalsPredicates.containsKey(key)) {
            result = (EqualsPredicate) ((Map)equalsPredicates.get(key)).get(value);
        }
        return result;
    }

    /**
     * @param predicate
     */
    public static void deletePredicate(Predicate predicate) {
        String field = predicate.getField();
        String value = predicate.getValue();
        
        if (predicate instanceof EqualsPredicate) {
            Map map = (Map) equalsPredicates.get(field);
            if (map.containsKey(value)) {
                map.remove(value);
            }
        } else if (predicate instanceof QueryPredicate) {
            if (field.equals(Constants.DOCUMENT_TITLE_FIELD)) {
                documentTitleQueryPredicates.remove(value);
            } else if (field.equals(Constants.DOCUMENT_CONTENT_FIELD)) {
                documentContentQueryPredicates.remove(value);
            } else {
                System.err.println("problem while removing: unknown field " + field);
            }
        } else if (predicate instanceof SubstringMatchPredicate) {
            if (field.equals(Constants.HOST_ID_FIELD)) {
                hostNameMatchPredicates.remove(value);
            } else if (field.equals(Constants.COLLECTION_ID_FIELD)) {
                collectionNameMatchPredicates.remove(value);
            } else {
                System.err.println("problem while removing: unknown field " + field);
            }
        } else {
            System.err.println("problem while removing: unknown class " + predicate.getClass().getName());
        }
    }
    
}