/*
 * Created on 2004-08-19
 *
 * Part of the Symbian development plug-in for Eclipse
 * Copyright (C) Mikołaj Zalewski, 2004
 */
package pl.zalewski.mikolaj.symbdev.templates;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.Map;

/**
 * @author mikolaj
 *
 * A stream that recieves and input stream and a substitutions map
 * and outputs the stream with the substitutions done  
 */
public class SubstitutionStreamReader extends Reader {
    Map substMap;
    Reader input;
    Reader stringReader;
    
    public SubstitutionStreamReader(Map substMap, Reader input) {
        super();
        this.substMap=substMap;
        this.input=input;
    }

    /* (non-Javadoc)
     * @see java.io.InputStream#read()
     */
    public int read() throws IOException {
        if (stringReader!=null)
        {
            int ch=stringReader.read();
            if (ch!=-1) return ch;
            stringReader=null;
        }
        
        int ch=input.read();
        if (ch==-1) return -1;
        
        if (ch!='$') return ch;
        
        ch=input.read();
        if (ch=='$') return '$';
        if (ch!='{')
            throw new IOException("Error parsing variable");
        
        String[] name=readVariable();
        String value=(String)substMap.get(name[0]);
        if (value==null) throw new IOException("Unknown variable");
        if (name.length>1)
        {
            if (name[1].equals("lowercase"))
                value=value.toLowerCase();
            else if (name[1].equals("uppercase"))
                value=value.toUpperCase();
            else throw new IOException("Unkonwn variable option");
        }
        stringReader=new StringReader(value);
        return read();        // read the character from the string
    }
    
    protected String[] readVariable()
    	throws IOException
    {
        String[] tab=null;
        StringBuffer buf=new StringBuffer();
        int ch;
        while ((ch=input.read())!='}')
        {
            if (ch==-1)
                throw new IOException("Unexpected end of file while parsing variable name");
            if (ch==':')
            {
                if (tab==null)
                {
                    tab=new String[2];
                    tab[0]=buf.toString();
                    buf.setLength(0);
                    continue;
                } else throw new IOException("More than one ':' in variable name");
            }
            buf.append((char)ch);
        }
        if (tab!=null)
        {
            tab[1]=buf.toString();
            return tab;
        }
        
        tab=new String[1];
        tab[0]=buf.toString();
        return tab;
    }
    
    public int read(char[] cbuf, int off, int len)
    	throws IOException
    {
        int i;
        for (i=off; i<len; i++)
        {
            int ch=read();
            if (ch==-1) 
            {
                if (i==off) return -1;
                	else return i-off;
            }
            cbuf[i]=(char)ch;
        }
        return len-off;
    }
    
    public void close()
    	throws IOException
    {
        input.close();
        if (stringReader!=null)
        {
            stringReader.close();
            stringReader=null;
        }
    }

    /**
     * @return The content of the stream as a String
     */
    public String readString()
    	throws IOException
    {
        StringBuffer buf=new StringBuffer();
        int ch;
        while ((ch=read())!=-1)
            buf.append((char)ch);
        return buf.toString();
    }

}
