/**
 * JLibs: Common Utilities for Java
 * Copyright (C) 2009  Santhosh Kumar T <santhosh.tekuri@gmail.com>
 *
 * This library 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 2.1 of the License, or (at your option) any later version.
 *
 * This library 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.
 */

package jlibs.core.annotation.processing;

import jlibs.core.lang.model.ModelUtil;

import javax.lang.model.element.TypeElement;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Santhosh Kumar T
 */
public class Printer{
    public static final String PLUS = "indent++";
    public static final String MINUS = "indent--";
    
    public TypeElement clazz;
    public String generatedQName;
    public String generatedPakage;
    public String generatedClazz;

    public int indent;
    PrintWriter ps;

    public Printer(PrintWriter ps){
        this.ps = ps;
    }

    private boolean doIndent = true;
    private void indent(){
        if(doIndent){
            if(emptyLine){
                println();
                emptyLine = false;
            }
            for(int i=0; i<indent; i++)
                ps.print("    ");
        }
    }
    public void println(String str){
        indent();
        ps.println(str);
        doIndent = true;
    }

    public void println(String... tokens){
        for(String token: tokens)
            print(token);
        println();
    }
    
    @SuppressWarnings({"StringEquality"})
    public void printlns(String... lines){
        for(String line: lines){
            if(line==PLUS)
                indent++;
            else if(line==MINUS)
                indent--;
            else
                println(line);
        }
    }

    public void printlns(InputStream is){
        BufferedReader reader = null;
        try{
            reader = new BufferedReader(new InputStreamReader(is));
            for(String line=reader.readLine(); line!=null; line=reader.readLine())
                println(line);
        }catch(IOException ex){
            throw new RuntimeException(ex);
        }finally{
            if(reader!=null)
                try{
                    reader.close();
                }catch(IOException ex){
                    ex.printStackTrace();
                }
        }
    }

    public void print(String str){
        indent();
        ps.print(str);
        doIndent = false;
    }

    private boolean emptyLine;
    public void emptyLine(boolean reqd){
        emptyLine = reqd;
    }

    public void println(){
        ps.println();
        doIndent = true;
    }

    public void close(){
        ps.close();
    }
    
    private static Map<TypeElement, Printer> registry = new HashMap<TypeElement, Printer>();
    public static Printer get(TypeElement clazz, Class annotation, String format) throws IOException{
        Printer printer = registry.get(clazz);
        if(printer==null){
            String str[] = ModelUtil.findClass(clazz, format);
            if(ModelUtil.exists(str[1], str[2]+".java"))
                throw new AnnotationError(clazz, ModelUtil.getAnnotationMirror(clazz, annotation), "Class "+str[0]+" already exists in source path");
            PrintWriter writer = new PrintWriter(Environment.get().getFiler().createSourceFile(str[0]).openWriter());
            printer=new Printer(writer);
            printer.clazz = clazz;
            printer.generatedQName = str[0];
            printer.generatedPakage = str[1];
            printer.generatedClazz = str[2];
            registry.put(clazz, printer);
        }
        return printer;
    }

    /*-------------------------------------------------[ Helpers ]---------------------------------------------------*/

    public void printPackage(){
        if(generatedPakage !=null && generatedPakage.length()>0){
            println("package "+generatedPakage +";");
            emptyLine(true);
        }
    }

    public void importClass(Class clazz){
        println("import "+ clazz.getName()+';');
    }

    public void importPackage(Class clazz){
        Package pakage = clazz.getPackage();
        if(pakage!=null)
            println("import "+ pakage.getName()+".*;");
    }

    public void printClassDoc(){
        println("/**");
        println(" * DON'T EDIT THIS FILE. THIS IS GENERATED BY JLIBS");
        println(" *");
        println(" * @author Santhosh Kumar T");
        println(" */");
    }
}

@@ -708,16 +708,62 @@
 delUtil;
+%0Aimport jlibs.core.util.regex.TemplateMatcher;
 %0A%0Aimport
@@ -2132,24 +2132,183 @@
 Stream is)%7B%0A
+        printlns(is, null, null);%0A    %7D%0A%0A    public void printlns(InputStream is, TemplateMatcher matcher, TemplateMatcher.VariableResolver variableResolver)%7B%0A
         Buff
@@ -2496,16 +2496,119 @@
 dLine())
+%7B%0A                if(matcher!=null)%0A                    line = matcher.replace(line, variableResolver);
 %0A       
@@ -2623,32 +2623,46 @@
  println(line);%0A
+            %7D%0A
         %7Dcatch(I

support for TemplateMatcher