/*
 *  Copyright 2006-2009 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/>.
 */

package kryshen.tema.functions;

import java.io.IOException;
import java.io.Writer;
import kryshen.tema.Function;
import kryshen.tema.FunctionDataParser;
import kryshen.tema.TemplateException;
import kryshen.tema.io.ReplaceWriter;

/**
 * Functions for string manipulation.
 */
public class Strings {
    public static final Function TO_UPPER = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String data = fdp.getData();
            out.write(data.toUpperCase());
            return fdp.getLastReturnCode();
        }
    };
    
    public static final Function TO_LOWER = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String data = fdp.getData();
            out.write(data.toLowerCase());
            return fdp.getLastReturnCode();
        }
    };
    
    public static final Function SUBSTRING = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String is = fdp.getNextArg();
            String js = fdp.getNextArg();
            
            String data = fdp.getData();
            
            try {
                if (js.equals("$")) {
                    out.write(data.substring(Integer.parseInt(is)));
                } else {
                    out.write(data.substring(
                            Integer.parseInt(is),
                            Integer.parseInt(js)));
                }
            } catch (NumberFormatException e) {
                throw new TemplateException(
                        e.toString(), e, fdp.getTemplateReader());
            } catch (IndexOutOfBoundsException e) {
                throw new TemplateException(
                        e.toString(), e, fdp.getTemplateReader());
            }
            
            return fdp.getLastReturnCode();
        }
    };
    
    public static final Function REPLACE = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String arg0 = fdp.getNextArg();
            String arg1 = fdp.getNextArg();
            
            ReplaceWriter rw = new ReplaceWriter(out, arg0, arg1);
            
            int ret = fdp.parseData(rw);
            rw.finish();
            return ret;
        }
    };
    
    public static final Function XML_ESCAPE = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            final String[] chars = {"&", "<", ">", "`", "\""};
            final String[] escape = {"&", "<", ">", "'", """};
            
            ReplaceWriter rw = new ReplaceWriter(out, chars, escape);
            
            int ret = fdp.parseData(rw);
            rw.finish();
            return ret;
        }
    };
    
    public static final Function XML_CDATA = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            ReplaceWriter rw = new ReplaceWriter
                    (out, "]]>", "]]]><![CDATA[]>", "<![CDATA[", "]]>");
            
            int ret = fdp.parseData(rw);
            rw.finish();
            return ret;
        }
    };
    
    public static final Function REGEX_MATCH = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String regex = fdp.getNextArg();            
            String data = fdp.getData(out);
            
            if (data.matches(regex)) {
                return 1;
            }
            
            return 0;
        }
    };
    
    public static final Function REGEX_REPLACE_FIRST = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String regex = fdp.getNextArg();
            String replacement = fdp.getNextArg();
            String data = fdp.getData();
            
            if (fdp.getLastReturnCode() == 0)
                return 0;
            
            out.write(data.replaceFirst(regex, replacement));
            
            return fdp.getLastReturnCode();
        }
    };
    
    public static final Function REGEX_REPLACE_ALL = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String regex = fdp.getNextArg();
            String replacement = fdp.getNextArg();
            String data = fdp.getData();
            
            if (fdp.getLastReturnCode() == 0)
                return 0;
            
            out.write(data.replaceAll(regex, replacement));
            
            return fdp.getLastReturnCode();
        }
    };
    
    public static final Function EQUAL = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String s1 = fdp.getNextArg();
            
            while (fdp.hasMoreData()) {
                String s2 = fdp.getNextArg();
                
                if (!s1.equals(s2)) {
                    return 0;
                }
                
                s1 = s2;
            }

            return 1;
        }
    };
    
    public static final Function CHAR = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {           

            if (!fdp.hasMoreData())
                return 0;
            
            do {
                String s = fdp.getNextArg();
                int code;

                try {
                    if (s.startsWith("0x")) {
                        code = Integer.parseInt(s.substring(2), 16);
                    } else {
                        code = Integer.parseInt(s);
                    }
                } catch (NumberFormatException e) {
                    throw new TemplateException(e.getMessage(), e,
                            fdp.getTemplateReader());
                }

                out.write(code);                
            } while (fdp.hasMoreData());
                
            return 1;
        }
    };
}