/*****************************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one                *
 * or more contributor license agreements.  See the NOTICE file              *
 * distributed with this work for additional information                     *
 * regarding copyright ownership.  The ASF licenses this file                *
 * to you 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.                                                        *
 *                                                                           *
 *                                                                           *
 * This file is part of the BeanShell Java Scripting distribution.           *
 * Documentation and updates may be found at http://www.beanshell.org/       *
 * Patrick Niemeyer (pat@pat.net)                                            *
 * Author of Learning Java, O'Reilly & Associates                            *
 *                                                                           *
 *****************************************************************************/
package bsh.servlet;

/**

	This file is derived from Pat Niemeyer's free utilities package.  
	Now part of BeanShell.

	@see http://www.pat.net/javautil/
	@version 1.0
	@author Pat Niemeyer (pat@pat.net)
*/

import java.io.*;
import java.util.*;
import java.net.URL;

/**
	This is	a simple template engine.  An instance of SimpleTemplate wraps
	a StringBuffer and performs replace operations on one or more parameters
	embedded as HMTL style comments. The value can then be retrieved as a 
	String or written to a stream.

	Template values	in the text are	of the form:

		<!-- TEMPLATE-NAME -->

	Substitutions then take	the form of:

		template.replace( "NAME", value	);

	Two static util	methods	are provided to	help read the text of a	template
	from a stream (perhaps a URL or	resource).  e.g.

	@author	Pat Niemeyer
*/
public class SimpleTemplate 
{
	StringBuffer buff;
	static String NO_TEMPLATE = "NO_TEMPLATE";	// Flag	for non-existent
	static Map templateData	= new HashMap();
	static boolean cacheTemplates =	true;

	/**
		Get a template by name, with caching.
		Note: this should be updated to search the resource path first, etc.

		Create a new instance of a template from the specified file.

		The file text is cached	so lookup is fast.  Failure to find the
		file is	also cached so the read	will not happen	twice.

	*/
	public static SimpleTemplate getTemplate( String file )
	{
		String templateText = (String)templateData.get(	file );

		if ( templateText == null || !cacheTemplates ) {
			try {
				FileReader fr =	new FileReader(	file );
				templateText = SimpleTemplate.getStringFromStream( fr );
				templateData.put( file,	templateText );
			} catch	( IOException e	) {
				// Not found
				templateData.put( file,	NO_TEMPLATE );
			}
		} else
			// Quick check prevents	trying each time
			if ( templateText.equals( NO_TEMPLATE )	)
				return null;

		if ( templateText == null )
			return null;
		else
			return new SimpleTemplate( templateText	);
	}

	public static String getStringFromStream( InputStream ins )
		throws IOException
	{
		return getStringFromStream( new	InputStreamReader( ins ) );
	}

	public static String getStringFromStream( Reader reader	) throws IOException {
		StringBuffer sb	= new StringBuffer();
		BufferedReader br = new	BufferedReader(	reader );
		String line;
		while (	( line = br.readLine() ) != null )
			sb.append( line	+"\n");

		return sb.toString();
	}

	public SimpleTemplate( String template ) {
		init(template);
	}

	public SimpleTemplate( Reader reader ) throws IOException {
		String template	= getStringFromStream( reader );
		init(template);
	}

	public SimpleTemplate( URL url ) throws IOException 
	{
		String template	= getStringFromStream( url.openStream() );
		init(template);
	}

	private void init( String s ) {
		buff = new StringBuffer( s );
	}

	/**
		Substitute the specified text for the parameter
	*/
	public void replace( String param, String value	) {
		int [] range;
		while (	(range = findTemplate( param ))	!= null	)
			buff.replace( range[0],	range[1], value	);
	}

	/**
		Find the starting (inclusive) and ending (exclusive) index of the
		named template and return them as a two	element	int [].
		Or return null if the param is not found.
	*/
	int [] findTemplate( String name ) {
		String text = buff.toString();
		int len	= text.length();

		int start = 0;

		while (	start <	len ) {

			// Find	begin and end comment
			int cstart = text.indexOf( "<!--", start );
			if ( cstart == -1 )
				return null;  // no more comments
			int cend = text.indexOf( "-->",	cstart );
			if ( cend == -1	)
				return null;  // no more complete comments
			cend +=	"-->".length();

			// Find	template tag
			int tstart = text.indexOf( "TEMPLATE-",	cstart );
			if ( tstart == -1 ) {
				start =	cend; // try the next comment
				continue;
			}

			// Is the tag inside the comment we found?
			if ( tstart > cend ) {
				start =	cend; // try the next comment
				continue;
			}

			// find	begin and end of param name
			int pstart = tstart + "TEMPLATE-".length();

			int pend = len;
			for ( pend = pstart; pend < len; pend++) {
				char c = text.charAt( pend );
				if ( c == ' ' || c == '\t' || c	== '-' )
					break;
			}
			if ( pend >= len )
				return null;

			String param = text.substring( pstart, pend );

			// If it's the correct one, return the comment extent
			if ( param.equals( name	) )
				return new int [] { cstart, cend };

//System.out.println( "Found param: {"+param+"}	in comment: "+ text.substring(cstart, cend) +"}");
			// Else	try the	next one
			start =	cend;
		}

		// Not found
		return null;
	}

	public String toString() {
		return buff.toString();
	}

	public void write( PrintWriter out ) {
		out.println( toString()	);
	}

	public void write( PrintStream out ) {
		out.println( toString()	);
	}

	/**
		usage: filename	param value
	*/
	public static void main( String	[] args	) throws IOException
	{
		String filename	= args[0];
		String param = args[1];
		String value = args[2];

		FileReader fr =	new FileReader(	filename );
		String templateText = SimpleTemplate.getStringFromStream( fr );
		SimpleTemplate template	= new SimpleTemplate( templateText );

		template.replace( param, value );
		template.write(	System.out );
	}

	public static void setCacheTemplates( boolean b	) {
		cacheTemplates = b;
	}

}

