/*
 *  Copyright 2006-2008 Mikhail Kryshen
 *
 *  This file is part of Tema.
 *
 *  Tema is free software: you can redistribute it and/or modify it
 *  under the terms of the GNU Lesser General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  Tema 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the 
 *  GNU Lesser General Public License along with Tema.  
 *  If not, see <http://www.gnu.org/licenses/>.
 *
 *  $Id: Control.java,v 1.18 2008/02/19 16:21:00 mikhail Exp $
 */

package kryshen.tema.functions;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import kryshen.tema.Function;
import kryshen.tema.FunctionDataParser;
import kryshen.tema.TemplateException;
import kryshen.tema.TemplateParser;
import kryshen.tema.io.NullWriter;
import kryshen.tema.io.TemplateReader;

/**
 * Logical and conditional functions.
 *
 * @author Mikhail Kryshen
 */
public class Control {
    
    /**
     * Copy input to output and return zero value.
     */
    public static final Function FALSE =
            new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            if (fdp.hasMoreData())
                fdp.parseData(out);
            
            return 0;
        }
    };

    /**
     * Copy input to output and return non-zero value.
     */
    public static final Function TRUE =
            new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            if (fdp.hasMoreData())
                fdp.parseData(out);
            
            return 1;
        }
    };
    
    /**
     * Outputs it's data if it has non-zero value.
     */
    public static final Function OPTIONAL = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            StringWriter sw = new StringWriter();
            int s = fdp.parseData(sw);
            sw.close();
            String data = sw.toString();
            
            if (s != 0) {
                out.write(data);
                return 1;
            } else {
                return 0;
            }
        }
    };
    
    /**
     * Logical negation (applied to the return value).
     */
    public static final Function NOT = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            return (fdp.parseData(out) == 0) ? 1 : 0;
        }
    };
    
    public static final Function IF = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            int value = fdp.parseNextArg(NullWriter.INSTANCE);
            
            if (value != 0) {
                return fdp.parseData(out);
            }
            
            return 0;
        }
    };
    
    public static final Function IF_ELSE = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            int value = fdp.parseNextArg(NullWriter.INSTANCE);
            
            if (value != 0) {
                return fdp.parseNextArg(out);
            } else {
                fdp.skipNextArg();
                return fdp.parseData(out);
            }
        }
    };
    
    /**
     * Outputs it's evaluated data while the evaluation result is non-zero.
     */
    public static final Function WHILE = new Function() {
        public int invoke(FunctionDataParser fdp, final Writer out)
        throws IOException, TemplateException {
            
            String data = fdp.getData();
            StringReader dataReader = new StringReader(data);
            
            TemplateParser parser = fdp.getTemplateParser();
            
            int r = 0; // summarized return value
            int e = 0; // evaluation value
            
            while (true) {
                StringWriter sw = new StringWriter();
                
                e = parser.parse(new TemplateReader(dataReader), sw);
                
                if (e == 0)
                    break;
                
                r += Math.abs(e);
                out.write(sw.toString());
                dataReader.reset();
            }
            
            dataReader.close();
            return r;
        }
    };
}