/*
 * Copyright (C) 2006 Mikhail A. Kryshen
 *
 * $Id: FunctionDataParser.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $
 */

package kryshen.tema;

import java.io.*;
import java.util.*;

import static kryshen.tema.TemplateParser.Result;
import static kryshen.tema.TemplateParser.FunctionData;
import static kryshen.tema.TemplateParser.Terminator;

/**
 * Parser for a function data.
 *
 * @author Mikhail A. Kryshen
 */
public class FunctionDataParser {
    static final char[] ARG_SEPARATORS = TemplateParser.LIST_SEPARATORS;

    private TemplateParser tp;
    private FunctionData fd;
    private Reader in;

    private boolean available = true;
    private boolean first = true;

    FunctionDataParser(TemplateParser tp, FunctionData fd,
                       Reader in) {
        this.tp = tp;
        this.fd = fd;
        this.in = in;
    }

    private TemplateParser.Result parseData(Writer out, boolean argument)
	throws IOException, TemplateException {
        
        if (!available)
            throw new TemplateException
		("Unexpected end of instruction data.");

        TemplateParser.Result r;

        if (fd == FunctionData.RECURSIVE) {
            r = tp.parse(in, out, true, 
                         argument ? ARG_SEPARATORS : null,
                         (argument || !first) ? ARG_SEPARATORS : null);
        } else if (fd == FunctionData.NONRECURSIVE) {
            r = tp.parse(in, out, false, 
                         argument ? ARG_SEPARATORS : null,
                         (argument || !first) ? ARG_SEPARATORS : null);
        } else if (fd == FunctionData.SUBFUNCTION && argument) {
            /* Subfunction can pass a list of arguments */
            StringWriter sw = new StringWriter();
            tp.parseFunction(in, sw);
            sw.close();
            in = new StringReader(sw.toString());
            fd = FunctionData.NONRECURSIVE;
            r = parseData(out, true);
        } else if (fd == FunctionData.SUBFUNCTION) {
            r = new Result(null, tp.parseFunction(in, out), false);
        } else {
            throw new IllegalArgumentException("Invalid FunctiodData: " + fd);
        }

        if (r.terminator != TemplateParser.Terminator.SEPARATOR)
            available = false; // No more function data available.

        first = false;
        return r;
    }

    public int parseData(Writer out) throws IOException, TemplateException {
        return parseData(out, false).substitutions; 
    }

    public String getData() throws IOException, TemplateException {        
        StringWriter sw = new StringWriter();
        parseData(sw);
        sw.close();
        return sw.toString();
    }

    public int parseNextArg(Writer out) throws IOException, TemplateException {
        TemplateParser.Result r = parseData(out, true);

        // Ignore empty arguments.
        while (r.empty && available) {
            r = parseData(out, true);
        }

        return r.substitutions;
    }

    public String getNextArg() throws IOException, TemplateException {        
        StringWriter sw = new StringWriter();
        parseNextArg(sw);
        sw.close();
        return sw.toString();
    }

    public List<String> getArgs() throws IOException, TemplateException {
	List<String> l = new ArrayList<String>();

	while (available) {
	    l.add(getNextArg());
	}
	
	return l;
    }

    public boolean hasMoreData() {
        return available;
    }

    public TemplateParser getTemplateParser() {
        return tp;
    }
}