/**
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 *
 * Copyright (C)
 * <a href="http://www.inab.org">Spanish National Institute of Bioinformatics (INB)</a>
 * <a href="http://www.bsc.es">Barcelona Supercomputing Center (BSC)</a>
 * <a href="http://inb.bsc.es">Computational Node 6</a>
 */

package org.inb.util;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.util.Map;

/**
 * @author Dmitry Repchevsky
 */

public class TemplateInputStream extends FilterInputStream
{    
    private Map paramz;
    private StringReader param_value;
    
    public TemplateInputStream(InputStream in, Map paramz)
    {
        super(in);
        this.paramz = paramz;
    }
    
    @Override
    public int read() throws IOException
    {
      int ch;
      
      if (param_value != null)
      {
          ch = param_value.read();
          
          if (ch >= 0)
              return ch; // get the next char of param
          
          param_value = null; // we successfully injected te param
      }
      
      ch = in.read();
      
      if (ch == '$')
      {
        StringBuffer sb = new StringBuffer(); // looking for a template parameter name
        while((ch = in.read()) > 0 && ch != '$')
        {
            sb.append((char)ch);
        }
        
        String key = sb.toString();
        Object value = paramz.get(key);
        
        if (value == null)
            throw new IOException("Can't find a parameter $" + key + "$");
        
        param_value = new StringReader((String)value);
        
        return this.read(); // read the first char of param value. 
      }
      
      return ch;
    }
    
    @Override
    public int read(byte b[]) throws IOException
    {
      return read(b, 0, b.length);
    }
    
    @Override
    public int read(byte b[], int off, int len) throws IOException
    {
      	if (b == null)
        {
	    throw new NullPointerException();
	}
        else if ((off < 0) || (off > b.length) || (len < 0) ||
		   ((off + len) > b.length) || ((off + len) < 0))
        {
	    throw new IndexOutOfBoundsException();
	}

        int i = off;
        for (int c; len > 0 && (c = read()) >= 0; i++, len--)
        {
          b[i] = (byte)c;
        }
        
        return i == off ? -1 : i - off;
    }   
}