/*
 *  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: IO.java,v 1.19 2008/02/19 16:21:00 mikhail Exp $
 */

package kryshen.tema.functions;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import kryshen.tema.Function;
import kryshen.tema.FunctionDataParser;
import kryshen.tema.Tema;
import kryshen.tema.TemplateException;
import kryshen.tema.io.TemplateReader;

/**
 * I/O functions.
 */
public class IO {
    /**
     * Copy files.
     */
    public static final Function COPY = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String arg0 = fdp.getNextArg();
            String arg1 = fdp.getNextArg();
            
            File source = fdp.createFile(arg0);
            File dest = fdp.createFile(arg1);
            
            try {
                copyFile(source, dest);
            } catch (IOException e) {
                System.err.println(e);
                return 0;
            }
            out.write(arg1);
            return 1;
        }
    };
    
    /**
     * Write data to file.
     */
    public static final Function WRITE = new Function() {
        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(fdp.createFile(arg0));
            } catch (IOException e) {
                System.err.println(e);
                //throw new TemplateException(e.getMessage(), e, in);
                return 0;
            }
            
            try {
                fdp.parseData(fw);
            } finally {
                fw.close();
            }
            
            out.write(arg0);
            
            return 1;
        }
    };
    
    /**
     * Read from file.
     */
    public static final Function READ = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String filename = fdp.getData();
            String file;
            
            try {
                readFile(fdp.createFile(filename), out);
            } catch (IOException e) {
                System.err.println(e);
                //throw new TemplateException(e.getMessage(), e, in);
                return 0;
            }
            
            return 1;
        }
    };
    
    /**
     * Evaluate the code read from file.
     */
    public static final Function INCLUDE = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String filename = fdp.getData();
            
            TemplateReader fin;
            
            try {
                fin = Tema.createTemplateReader(fdp.createFile(filename));
            } catch (IOException e) {
                throw new TemplateException(e.getMessage(), e,
                        fdp.getTemplateReader());
            }
            
            int r = fdp.getTemplateParser().parse(fin, out);
            
            fin.close();
            return r;
        }
    };
    
    /**
     * Create path from base path and file name.
     */
    public static final Function FILE = new Function() {
        public int invoke(FunctionDataParser fdp, Writer out)
        throws IOException, TemplateException {
            
            String base = fdp.getNextArg();
            String name = fdp.getNextArg();                        
            
            if (fdp.getLastReturnCode() == 0)
                return 0;                        
                       
            out.write((new File(fdp.createFile(base), name)).getPath());
            
            return fdp.getLastReturnCode();
        }
    };
    
    /**
     * Update file (copy if newer).
     *
     * @param src source file.
     * @param dest destination file.
     *
     * @trows IOException on copying error.
     */
    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);
        
        copy(in, out);
        
        in.close();
        out.close();
    }
    
    private static void copy(InputStream in, OutputStream out)
    throws IOException {
        
        byte[] buffer = new byte[1024];
        int len;
        
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }
    
    private static void copy(Reader in, Writer out)
    throws IOException {
        
        char[] buffer = new char[1024];
        int len;
        
        while ((len = in.read(buffer)) > 0) {
            out.write(buffer, 0, len);
        }
    }
    
    private static void readFile(File src, Writer out)
    throws IOException {
        
        Reader in = Tema.createFileReader(src);
        copy(in, out);
    }
}