/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jdbi.v3.stringtemplate4;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.STGroupString;

import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * Locates SQL in <code>.sql.stg</code> StringTemplate group files on the classpath.
 */
public class StringTemplateSqlLocator {
    private static final Map<Class<?>, STGroup> CACHE = ExpiringMap.builder()
            .expiration(10, TimeUnit.MINUTES)
            .expirationPolicy(ExpirationPolicy.ACCESSED)
            .entryLoader(o -> readStringTemplateGroup((Class) o))
            .build();

    private static final String TEMPLATE_GROUP_EXTENSION = ".sql.stg";

    private StringTemplateSqlLocator() {
    }

    /**
     * Locates SQL for the given type and name. Example: Given a type <code>com.foo.Bar</code> and a name of
     * <code>baz</code>, loads a StringTemplate group file from the resource named <code>com/foo/Bar.sql.stg</code> on
     * the classpath, and returns the template with the given name from the group.
     *
     * @param type the type that "owns" the given StringTemplate group file. Dictates the filename of the
     *             StringTemplate group file on the classpath.
     * @param name the template name in the StringTemplate group.
     * @return the located SQL.
     */
    public static ST findStringTemplate(Class<?> type, String name) {
        STGroup group = findStringTemplateGroup(type);

        if (!group.isDefined(name)) {
            throw new IllegalStateException("No StringTemplate group " + name + " for class " + type);
        }

        return group.getInstanceOf(name);
    }

    /**
     * Loads the StringTemplateGroup for the given type. Example: Given a type <code>com.foo.Bar</code>, returns a
     * StringTemplateGroup loaded from the resource named <code>com/foo/Bar.sql.stg</code> on the classpath.
     *
     * @param type the type that "owns" the given StringTemplate group file. Dictates the filename of the
     *             StringTemplate group file on the classpath.
     * @return the loaded StringTemplateGroup.
     */
    public static STGroup findStringTemplateGroup(Class<?> type) {
        return CACHE.get(type);
    }

    private static STGroup readStringTemplateGroup(Class<?> type) {
        String path = resourcePathFor(type);

        try (InputStream is = openStream(type.getClassLoader(), path)) {
            return new STGroupString(toString(is));
        }
        catch (IOException e) {
            throw new RuntimeException("Unable to read StringTemplate group file at " + path + " on classpath", e);
        }
    }

    private static String toString(InputStream inputStream) throws IOException {
        final int bufferSize = 1024;
        final char[] buffer = new char[bufferSize];
        final StringBuilder out = new StringBuilder();
        Reader in = new InputStreamReader(inputStream, UTF_8);
        for (; ; ) {
            int rsz = in.read(buffer, 0, buffer.length);
            if (rsz < 0){
                break;
            }
            out.append(buffer, 0, rsz);
        }
        return out.toString();
    }

    private static InputStream openStream(ClassLoader classLoader, String path) {
        InputStream is = classLoader.getResourceAsStream(path);

        if (is == null) {
            throw new IllegalStateException("Unable to find StringTemplate group file at " + path + " on classpath");
        }

        return is;
    }

    private static String resourcePathFor(Class<?> clazz) {
        return clazz.getName().replace('.', '/') + TEMPLATE_GROUP_EXTENSION;
    }
}

@@ -3551,51 +3551,8 @@
     
-final int bufferSize = 1024;%0A        final 
 char
@@ -3576,18 +3576,12 @@
 har%5B
-bufferSize
+1024
 %5D;%0A 
@@ -3587,22 +3587,16 @@
         
-final 
 StringBu
@@ -3708,32 +3708,18 @@
 or (
-; ; ) %7B%0A            int 
+int rsz; (
 rsz 
@@ -3757,72 +3757,18 @@
 gth)
-;%0A            if (rsz %3C 0)%7B%0A                break;%0A            %7D
+) %3E= 0;) %7B
 %0A   

Simplify StringTemplateSqlLocator code.