/*
 * Scone - The Web Enhancement Framework
 * Copyright (C) 2009 Harald Weinreich, Volkert Buchmann, Frank Wollenweber, Torsten Haß
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
 package scone.netobjects;


import java.sql.Connection;
import java.util.Observer;


/**
 * caches all HtmlNode objects.
 * <br>
 * use the static methods provided by this class to obtain HtmlNode objects.
 *
 * @author Harald Weinreich
 * @author Volkert Buchmann
 */

public class HtmlNodeCache extends Cache implements TableRecordCacheInterface {

    // store an instance of this class statically (uh-oh)
    protected static HtmlNodeCache observable;
    protected static int observePeriod = 0;

    protected static CacheTable cache;

    protected static Object lock = new Object();

    public HtmlNodeCache() {
        super();
    }

    public static void init(int timeTillCleanUp, int gcType) {
        cache = new CacheTable("Html-Documents", 1, timeTillCleanUp, gcType);
        lock = new Object();
        observePeriod = 1000 * 4;   // every 4 secs
        observable = new HtmlNodeCache();
    }

    public static void setObservePeriod(int period) {
        observePeriod = period;
    }

    public static int getObservePeriod() {
        return observePeriod;
    }

    public static void putObserver(Observer o) {
        observable.addObserver(o);
    }

    public static void removeObserver(Observer o) {
        observable.deleteObserver(o);
    }

    /**
     * This method will return the required HtmlNode if it exists in the database,
     * and <code>null</code> otherwise.
     * @param node the NetNode
     * @return the HtmlNode corresponding to node or <code>null</null>
     */
    public static HtmlNode check(NetNode node) {
        if (node == null) {      // this can happen
            return null;
        } else {
            HtmlNode doc = null;
            String key = node.getNodeId();

            synchronized (lock) {
                // is the htmlnode already in the cache?
                doc = (HtmlNode) cache.get(0, key);
                if (doc == null) {
                    // try to read it from the database
                    doc = new HtmlNode(node);
                    if (!doc.hasRecordInDB) {
                        return null;
                    }
                    cache.put(doc);
                    observable.addItem(doc);
                }
            }
            return doc;
        }
    }

    /**
     * This method will return the required HtmlNode if it exists in the database,
     * and <code>null</code> otherwise.
     * @param netNode the NetNode 
     * @param persistent shall the NetNode be made persistent? <BR>
     * true: yes, now, <br>
     * false: no never.<BR>
     * For deferred DB persistency call get-method without boolean parameter.
     */
    public static HtmlNode check(NetNode node, boolean persistent) {
        HtmlNode doc = check(node);

        if (doc == null) {
            return null;
        }
        if (persistent) {
            doc.store();
        } else {
            doc.setPersistent(false);
        }
        return doc;
    }

    /**
     * This methid will return and potentially create the required HtmlNode.
     * <br>
     * If it exists in the database it will return the stored data.
     * If not, it will create a new set in the database
     * @param node the NetNode
     * @return the HtmlNode corresponding to node
     */
    public static HtmlNode get(NetNode node) {
        if (node == null) return null;

        HtmlNode doc = null;
        String key = node.getNodeId();
        
        synchronized (lock) {
            doc = (HtmlNode) cache.get(0, key);
            if (doc == null) {
                doc = new HtmlNode(node);
                cache.put(doc);
                observable.addItem(doc);
            }
        }
        return doc;
    }

    /**
     * This method will return and potentially create the required HtmlNode.
     * @param netNode the NetNode 
     * @param persistent shall the NetNode be made persistent? <BR>
     * true: yes, now, <br>
     * false: no never.<BR>
     * For deferred DB persistency call get-method without boolean parameter.
     */
    public static HtmlNode get(NetNode node, boolean persistent) {
        HtmlNode doc = get(node);

        if (doc == null) {
            return null;
        }
        if (persistent) {
            doc.store();
        } else {
            doc.setPersistent(false);
        }
        return doc;
    }

    /**
     * This method returns a number of HtmoNodes to a given query string.
     * @param sqlClause The where clause for the query string.
     * @return The number of HtmlNodes.
     */
    public static int getHtmlNodeCount(String sqlClause) {
        Connection con = HtmlNode.dbTable.getConnection();
        int count;

        synchronized (lock) {
            count = HtmlNode.dbTable.rowCountDb(con, HtmlNode.dbTable.getTableName(), sqlClause);
        }
        return count;
    }

    /**
     * Store objects to DB
     */
    public static void clean() {
        cache.shutdown();
    }
}
