/*
 * 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 scone.util.ErrorLog;

import java.sql.Connection;
import java.sql.ResultSet;
import java.util.Vector;

import adc.parser.HtmlTag;


/**
 * caches the links table from the database and provides means to update the database
 *
 * @author Harald Weinreich
 * @author Volkert Buchmann
 */

public class LinkCache implements TableRecordCacheInterface {

    // key1=linkId  key2=linkstring
    protected static CacheTable cache;

    public static Object lock = new Object();

    public static void init(int timeTillCleanUp, int gcType) {
        cache = new CacheTable("Links", 1, timeTillCleanUp, gcType, 20000);  // Many needed, as pages have many links...
        lock = new Object();
    }

    /**
     * returns the links defined in <code>from</code>
     * @param from the NetNode
     * @return the links
     */
    public static LinkVector getLinksFrom(NetNode from) {
        return (LinkVector) getLinks("where fromNodeId='" + from.getNodeId() + "'");
    }

    /**
     * returns the links pointing to <code>to</code>
     * @param to the NetNode
     * @return the links
     */
    public static LinkVector getLinksTo(NetNode to) {
        return (LinkVector) getLinks("where toNodeId='" + to.getNodeId() + "'");
    }

    /**
     * This method returns a Vector of Links to a given query.
     * @param sqlClause The where clause for the query string.
     */
    public static Vector getLinks(String sqlClause) {
        clean(); // first store new data to DB!
        Vector links = new LinkVector();

        if (Link.dbTable.useDb()) {
            Connection con = Link.dbTable.getConnection();
            int i = 0;

            synchronized (lock) {
            	// System.out.println(sqlClause);
                ResultSet results = Link.dbTable.queryDb(con, Link.dbTable.getTableName(), sqlClause);

                // eval all records returned...
                while (results != null) {
                    Link link = new Link(results);  // Create new use object
                    String id = link.getLinkId();

                    // if (id.length()>0 && !id.equals("-1")) // another set read from DB
                    if (link.hasRecordInDB) {
                        // System.out.println(results.getString("userId") + "  " +results.getString("userName"));
                        if (cache.get(0, id) == null) {   //
                            cache.put(link);
                        }
                        links.add(link);
                    } else {  // End of results reached!
                        return links;
                    }
                }
            }
	        try {
	            con.close();
	        } catch (Exception e) {
	            ErrorLog.log(Link.dbTable.getTableName(), "LinkCache.getLinks()", "Could not close database connection", e);
	        }
	        return null;
        } else {
            System.out.println("|-------------------------------------------------------------|");
            System.out.println("| A method that requires the database was used, but           |");
            System.out.println("| Database access has been disabled. Result may be corrupted. |");
            System.out.println("|-------------------------------------------------------------|");
        }
        return links;
    }

    /**
     * This method returns a number of Links to a given query string.
     * @param sqlClause The where clause for the query string.
     * @return The number of links in the Database.
     */
    public static int getLinkCount(String sqlClause) {
        int count = 0;

        if (Link.dbTable.useDb()) {
            Connection con = Link.dbTable.getConnection();

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

    /**
     * returns the link defined in <code>from</code>, ponting to <code>to</code>
     * @param from the defining node
     * @param to the linked node
     * @param fragment the fragment
     * @param tag the defining tag, used to fill new link objects with infos.
     * @return the link
     */
    public static Link get(NetNode from, NetNode to, String fragment, HtmlTag tag) {
        String key = createKey(from.getNodeId(), to.getNodeId(), fragment);
        Link link = null;

        synchronized (lock) {
            link = (Link) cache.get(0, key);
            if (link == null) {
                link = new Link(from, to, fragment);
                link.fill(tag);   // fill link with data from tag...
                cache.put(link);
            }
        }
        return link;
    }

    /**
     * returns the link defined in <code>from</code>, ponting to <code>to</code>
     * @param from the defining node
     * @param to the linked node
     * @param fragment the fragment
     * @return the link
     */
    public static Link get(NetNode from, NetNode to, String fragment) {
        String key = createKey(from.getNodeId(), to.getNodeId(), fragment);
        Link link = null;

        synchronized (lock) {
            link = (Link) cache.get(0, key);
            if (link == null) {
                link = new Link(from, to, fragment);
                cache.put(link);
            }
        }
        return link;
    }

    /**
     * returns the link defined in <code>from</code>, ponting to <code>to</code>
     * @param from the defining node
     * @param to the linked node
     * @param fragment the fragment
     * @param tag the defining tag
     * @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.
     * @return the link
     */
    public static Link get(NetNode from, NetNode to, String fragment, HtmlTag tag, boolean persistent) {
        Link link = get(from, to, fragment, tag);

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

    /**
     * returns the link specified by the id
     * @param id the id
     * @return the link
     */
    public static Link getById(String id) {
        Link link = null;

        synchronized (lock) {
            link = (Link) cache.get(0, id);
            if (link == null) {
                // System.out.println("Link with "+id+" not found in cache!");  // May happen with db off and Garbage collection...
                link = new Link(id);   // Read from DB, as not in cache.
                cache.put(link);
            }
        }
        return link;
    }

    /**
     * Create a unique key for links
     */
    public static String createKey(String fromId, String toId, String fragment) {
        return SimpleUri.getHexHashCode("Link:" + fromId + toId + fragment);
    }

    public static void clean() {
        cache.clean();
    }
}
