/*
 * Created on Nov 2, 2004
 * Copyright (C) Andrea Schweer, 2004
 *
 * 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.*;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.*;
import java.util.Set;
import java.util.TreeSet;

import org.greenstone.gsdlas.Constants;
import org.greenstone.gsdlas.database.DatabaseException;
import org.greenstone.gsdlas.database.DatabaseManager;
import org.greenstone.gsdlas.util.ArrayHelper;

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

    protected Set subscriptions = new TreeSet();
    protected String field;
    protected String value;
    protected int id;
    

    public static final String[] singleValueFields = new String[] {
            Constants.DOCUMENT_TITLE_FIELD,
            Constants.DOCUMENT_CONTENT_FIELD,
            "metadata_has_field",
            Constants.HOST_QUERY_FIELD,
            Constants.COLLECTION_QUERY_FIELD };
    public static final String[] multiValueFields = new String[] {
            Constants.TYPE_FIELD,
            Constants.HOST_ID_FIELD,
            Constants.COLLECTION_ID_FIELD,
            Constants.HOST_COLLECTION_ID_FIELD,
            Constants.DOCUMENT_ID_FIELD };
    
    public void addSubscription(int subscriptionID) {
        subscriptions.add(new Integer(subscriptionID));
    }

    /* (non-Javadoc)
     * @see org.greenstone.gsdlas.profiles.Predicate#getSubscriptions()
     */
    public Set getSubscriptionIDs() {
        return Collections.unmodifiableSet(subscriptions);
    }

    public int getID() {
        return id;
    }
    
    public void setID(int i) {
        this.id = i;
    }

    /* (non-Javadoc)
     * @see org.greenstone.gsdlas.profiles.Predicate#getKey()
     */
    public String getField() {
        return field;
    }

    /* (non-Javadoc)
     * @see org.greenstone.gsdlas.profiles.Predicate#getValue()
     */
    public String getValue() {
        return value;
    }

    public String toString() {
        return field + "=" + value;
    }
    
    public boolean equals(Object other) {
        if (other == null || !(other instanceof Predicate)) return false;
        return id == ((Predicate)other).getID();
    }
    
    public int compareTo(Object other) {
        Predicate otherPredicate = (Predicate) other;
        return new Integer(id).compareTo(new Integer(otherPredicate.getID()));
    }
    
    public abstract boolean isSatisfied(Map event);

    /**
     * @param key
     * @return
     */
    public static boolean isSingleValued(String key) {
        return ArrayHelper.contains(singleValueFields, key);
    }

    /**
     * @param key
     * @return
     */
    public static boolean isMultiValued(String key) {
        return ArrayHelper.contains(multiValueFields, key);
    }

    /**
     * @return
     * @throws DatabaseException
     * @throws SQLException
     */
    int saveToDatabase() throws SQLException, DatabaseException {
        String query = "SELECT id FROM predicates " +
        		"WHERE field = '" + field + 
        		"' AND value = '" + value + 
        		"' AND type = '" + this.getClass().getName() + "';";
        Statement statement = DatabaseManager.getInstance().getDatabaseConnection().createStatement();
        System.out.println(query);
        ResultSet result = statement.executeQuery(query);
        if (result.next()) { // predicate already exists in database
            int id = result.getInt("id"); 
            System.out.println("predicate already exists with id " + id);
            return id;
        }
        // predicate has been newly created
        String insert = "INSERT INTO predicates (field, type, value) " +
        "VALUES ('" + field + "', '" + this.getClass().getName() + "', '" + value + "');";
        System.out.println(insert);
        statement.execute(insert);
        result = statement.executeQuery(query);
        if (result.next()) {
            return result.getInt("id");
        } else {
            throw new DatabaseException("could not save predicate");
        }
    }

    /**
     * @param key
     * @return
     */
    public static boolean isFieldName(String key) {
        return ArrayHelper.contains(singleValueFields, key) || ArrayHelper.contains(multiValueFields, key);
    }

    /**
     * @param subID
     * @throws DatabaseException
     * @throws SQLException
     */
    public void removeSubscription(Integer subID) throws SQLException, DatabaseException {
        subscriptions.remove(subID);

        Statement statement = DatabaseManager.getInstance().getDatabaseConnection().createStatement();
        String sqlString = "DELETE FROM subs_to_predicates " +
        	"WHERE subscription = " + subID + 
        	" AND predicate = " + id;
        statement.executeUpdate(sqlString);
        
        if (subscriptions.isEmpty()) {
            PredicateFactory.deletePredicate(this);
            sqlString = "DELETE FROM predicates WHERE id = " + id;
            statement.executeUpdate(sqlString);
        }
    }
    
}
