/*
 *  PHEX - The pure-java Gnutella-servent.
 *  Copyright (C) 2001 - 2006 Phex Development Group
 *
 *  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
 * 
 *  --- CVS Information ---
 *  $Id: QueryHistoryMonitor.java 3859 2007-07-01 20:15:19Z gregork $
 */
package phex.query;

import java.io.*;

import phex.event.QueryHistoryChangeListener;
import phex.msg.QueryMsg;
import phex.prefs.core.StatisticPrefs;
import phex.utils.CircularQueue;
import phex.utils.NLogger;

public class QueryHistoryMonitor
{
    private boolean isHistoryMonitored;
    private CircularQueue historyQueue;
    private BufferedWriter fileWriter;

    /**
     * Right now we have only one single listener. If more are needed apply
     * the same design that can be found in NetworkHostContainer
     */
    private QueryHistoryChangeListener changeListener;

    public QueryHistoryMonitor()
    {
        isHistoryMonitored = false;
        historyQueue = new CircularQueue( StatisticPrefs.QueryHistoryEntries.get().intValue(),
            StatisticPrefs.QueryHistoryEntries.get().intValue() );
        updateFileMonitoring();
    }

    public void shutdown()
    {
        if ( fileWriter != null )
        {
            try
            {

                fileWriter.close();
                NLogger.debug( QueryHistoryMonitor.class,
                    "End QueryMonitoring to file." );
            }
            catch ( IOException exp )
            {
                NLogger.error( QueryHistoryMonitor.class, exp, exp );
            }
            fileWriter = null;
        }
    }

    private void updateFileMonitoring()
    {
        // START this is a special implementation for Raster...
        if ( isHistoryMonitored
            && StatisticPrefs.QueryHistoryLogFile.get().length() > 0 )
        {
            try
            {
                File file = new File( StatisticPrefs.QueryHistoryLogFile.get() );
                File parent = file.getParentFile();
                if ( parent != null )
                {
                    parent.mkdirs();
                }
                file.createNewFile();
                fileWriter = new BufferedWriter( new FileWriter(
                    file.getAbsolutePath(), true ) );
                NLogger.debug( QueryHistoryMonitor.class,
                    "Start QueryMonitoring to " + file.getAbsolutePath() );
            }
            catch ( IOException exp )
            {
                NLogger.error( QueryHistoryMonitor.class, exp, exp );
            }
        }
        else
        {
            shutdown();
        }
        // END this is a special implementation for Raster...
    }

    public void setHistoryMonitored( boolean state )
    {
        isHistoryMonitored = state;
        updateFileMonitoring();
    }

    public boolean isHistoryMonitored( )
    {
        return isHistoryMonitored;
    }

    public synchronized void setMaxHistroySize( int size )
    {
        if ( size == historyQueue.getCapacity() )
        {
            return;
        }
        historyQueue = new CircularQueue( size, size );
        StatisticPrefs.QueryHistoryEntries.set( new Integer( size ) );
    }

    public synchronized int getMaxHistorySize()
    {
        return historyQueue.getCapacity();
    }

    public synchronized int getHistorySize()
    {
        return historyQueue.getSize();
    }

    public synchronized QueryMsg getSearchQueryAt( int index )
    {
        return (QueryMsg) historyQueue.get( index );
    }

    public synchronized void addSearchQuery( QueryMsg query )
    {
        if ( isHistoryMonitored )
        {
            String searchString = query.getSearchString();
            if ( searchString.length() > 0 && !searchString.equals( "\\" ) 
                 && !searchString.startsWith( "urn:sha1:" ) )
            {
                historyQueue.addToHead( query );
                fireQueryHistoryChanged( );
            }

            // START this is a special implementation for Raster...
            if ( fileWriter != null )
            {
                try
                {
                    fileWriter.write( query.getSearchString() );
                    /*fileWriter.write( query.getSearchString() + "\t" +
                        query.getHeader().getHopsTaken() + "\t" +
                        query.getHeader().getTTL() + "\t");
                    URN[] urns = query.getQueryURNs();
                    for ( int i = 0; i < urns.length; i++ )
                    {
                        if ( urns[i].isSha1Nid() )
                        {
                            fileWriter.write( urns[i].getAsString() );
                            break;
                        }
                    }*/
                    fileWriter.newLine();
                }
                catch ( IOException exp )
                {
                    NLogger.warn(QueryHistoryMonitor.class, exp, exp );
                }
            }
            // END this is a special implementation for Raster...
        }
    }

    ///////////////////// START event handling methods ////////////////////////
    public void setQueryHistoryChangeListener( QueryHistoryChangeListener listener )
    {
        if ( changeListener != null )
        {
            throw new RuntimeException( "CaughtHostChangedListener already used!!" );
        }
        changeListener = listener;
    }

    private void fireQueryHistoryChanged( )
    {
        changeListener.queryHistoryChanged( );
    }
    ///////////////////// END event handling methods ////////////////////////
}