package net.yacy.data.ymark;

import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;
import java.nio.CharBuffer;

import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

/**
 * This class monitors the read progress
 *
 */
public class MonitoredReader extends FilterReader {
   private volatile long mark = 0;
   private volatile long location = 0;
   private final int threshold;
   private final long maxProgress;
   private long lastTriggeredLocation = 0;
   private ChangeListener listener = null;
   
   public MonitoredReader(Reader in, int threshold, long maxProgress) {
      super(in);
      this.threshold = threshold;
      this.maxProgress = maxProgress;
   }
   
   public void addChangeListener(ChangeListener l) {
	   this.listener = l;
   }
   
   protected void triggerChanged(final long location) {
	   if ( threshold > 0 && Math.abs( location-lastTriggeredLocation ) < threshold ) 
		   return;
	   lastTriggeredLocation = location;
	   if (listener == null)
		   return;
	   listener.stateChanged(new ChangeEvent(this));
   }
   
   public long getProgress() { 
	   return this.location; 
   }
   
   public long maxProgress() {
	   return this.maxProgress;
   }

   @Override 
   public int read() throws IOException {
      final int i = super.read();
      if ( i != -1 ) 
    	  triggerChanged(location++);
      return i;
   }
   
   @Override
   public int read(char[] cbuf, int off, int len) throws IOException {
		final int i = super.read(cbuf, off, len);
		if ( i != -1 ) 
			triggerChanged(location+=i);
	    return i;
   }
   
   @Override
   public int read(char[] cbuf) throws IOException {
		final int i = super.read(cbuf);
		if ( i != -1 ) 
			triggerChanged(location+=i);
	    return i;
   }
   
   @Override
   public int read(CharBuffer target) throws IOException {
		final int i = super.read(target);
		if ( i != -1 ) 
			triggerChanged(location+=i);
	    return i;
   }

   @Override 
   public long skip(long n) throws IOException {
      final long i = super.skip(n);
      if ( i != -1 ) 
    	  triggerChanged(location+=i);
      return i;
   }

   @Override 
   public synchronized void mark(int readlimit) throws IOException {
      super.mark(readlimit);
      mark = location;
   }

   @Override 
   public synchronized void reset() throws IOException {
      super.reset();
      if ( location != mark ) 
    	  triggerChanged(location = mark);
   }   
}