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

package kryshen.tema;

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

import java.sql.SQLException;
import java.sql.PreparedStatement;

import kryshen.tema.functions.*;

public class Functions {
    public static final Function GET =
        new Function("get") {
            public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

		String name = fdp.getData();
                return fdp.getTemplateParser().parseVariable(name, out);
            }
        };

    public static final Function SET =
        new Function("set") {
            public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

                String arg0 = fdp.getNextArg();
                String arg1 = fdp.getData();
                
                fdp.getTemplateParser().setValue(arg0, arg1);
                
		out.write(arg0);
                return 1;
            }
        };

    /* prepare:qury_name sql_statement */
    public static final Function PREPARE =
        new Function("prepare") {
            public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

                String arg0 = fdp.getNextArg();
                String data = fdp.getData();

		PreparedStatement statement;

		try {
		    statement = Tema.connection.prepareStatement(data);
		} catch (SQLException e) {
		    throw new TemplateException(e.getMessage(), e);
		}
                
                fdp.getTemplateParser().setValue(arg0, statement);   
             
		out.write(arg0);
                return 1;
            }
        };

    public static final Function OPTIONAL =
        new Function("optional") {
            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;
                }
            }
        };

    public static final Function IMAGE =
        new Function("image") {
            public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

                String arg0 = fdp.getNextArg();
                String arg1 = fdp.getNextArg();
                String arg2 = fdp.getNextArg();
                int arg3 = fdp.hasMoreData() ? 
		    Integer.parseInt(fdp.getNextArg()) : -1;
                int arg4 = fdp.hasMoreData() ? 
		    Integer.parseInt(fdp.getNextArg()) : -1;

                File source = new File
                    (Tema.getProperty("resource_base"), arg0);

                try {
                    ImageConverter.convert
                        (source,                  /* source file */
                         new File(arg1),          /* dest file */
                         arg2,                    /* format */
                         arg3,                    /* max width */
                         arg4);                   /* max height */
                } catch (Exception e) {
                    System.err.println(e);
                    return 0;
                }

                out.write(arg1);
                return 1;
            }
        };

    public static final Function COPY =
        new Function("copy") {
           public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

                String arg0 = fdp.getNextArg();
                String arg1 = fdp.getNextArg();

                File source = new File
                    (Tema.getProperty("resource_base"), arg0);
                File dest = new File(arg1);
                
                try {
                    copyFile(source, dest);
                } catch (IOException e) {
                    System.err.println(e);
                    return 0;
                }
                out.write(arg1);
                return 1;
            }
        };

    /* query:sql_query template arg1 arg2 ... argN */
    public static final Function QUERY =
        new Function("query") {
           public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {
                
                String arg0 = fdp.getNextArg();
                String arg1 = fdp.getNextArg();
		List<String> args = fdp.getArgs();				

		TemplateParser tp = fdp.getTemplateParser();

		try {
		    return Tema.query
			(arg1, (PreparedStatement)tp.getValue(arg0),
			 args, tp, out);
		} catch (SQLException e) {
		    throw new TemplateException(e.getMessage(), e);
		}
            }
        };

    public static final Function WRITE =
        new Function("write") {
           public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

                String arg0 = fdp.getNextArg();

		System.err.println("Writing " + arg0 + "...");

                Writer fw;

                try {
		    fw = Tema.createFileWriter(arg0);
                } catch (IOException e) {
                    System.err.println(e);
                    return 0;
                }
                
                try {
		    fdp.parseData(fw);
                } finally {
                    fw.close();
                }

                out.write(arg0);
		
		System.err.println("Saved " + arg0 + ".");
                return 1;
            }
        };

    public static final Function READ =
        new Function("read") {
           public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {

	       String filename = fdp.getData();
	       String file;
	       
                try {
                    file = Tema.readFile(new File(filename));
                } catch (IOException e) {
                    System.err.println(e);
                    return 0;
                }
		
                out.write(file);
                return 1;
            }
        };

    public static final Function INCLUDE =
        new Function("include") {
           public int invoke(FunctionDataParser fdp, Writer out)
                throws IOException, TemplateException {
                
                String filename = fdp.getData();
                
                Reader fin = new BufferedReader
		    (Tema.createCachedFileReader(new File(filename)));
                
                int r = fdp.getTemplateParser().parse(fin, out);

                fin.close();
                return r;
            }
        };

    public static final Function NULL_OUTPUT =
        new Function("!") {
	    public int invoke(FunctionDataParser fdp, Writer out)
		throws IOException, TemplateException {		

		/* Write nothing. */
		return fdp.parseData(new Writer() {
                    public void close() {}
                    public void flush() {}
                    public void write(char[] cbuf, int off, int len) {}
                });
            }
        };

    public static final Function REPLACE =
        new Function("replace") {
	    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("xml_escape") {
	    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("xml_cdata") {
	    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 DEFINE = new Define();

    private static void copyFile(File src, File dest) throws IOException {
	System.err.print("Copying " + src + "... ");
	
	if (src.lastModified() < dest.lastModified()) {
	    System.err.println(dest + " is up to date.");
	    return;
	}

	File parent = dest.getParentFile();
	if (parent != null) parent.mkdirs();

        InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dest);
        
        byte[] buffer = new byte[1024];
        int len;
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
        in.close();
        out.close();

	System.err.println("saved " + dest + ".");
    }

    static void registerAllFunctions(TemplateParser p) {
        p.registerFunction(GET);
        p.registerFunction(SET);
        p.registerFunction(OPTIONAL);
        p.registerFunction(IMAGE);
        p.registerFunction(COPY);
        p.registerFunction(QUERY);
        p.registerFunction(PREPARE);
        p.registerFunction(WRITE);
        p.registerFunction(READ);
        p.registerFunction(INCLUDE);
        p.registerFunction(NULL_OUTPUT);
        p.registerFunction(REPLACE);
        p.registerFunction(XML_ESCAPE);
        p.registerFunction(XML_CDATA);
        p.registerFunction(DEFINE);
    }
}