/**
 * @(#)SSIString.java
 * SSI文字列を表す。
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 * SSI String
 * @author  Intelligent Technology Inc.
 * @version 1.00 2002/05/01
 */
package	jp.co.nri.rid.analyzer;

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

/**
 * SSI文字列をあつかうクラス。
 */

public class SSIString{
	public	static	final	int	UNKNOWN	=	-1;
	public	static	final	int	INCLUDE	=	 0;
	public	static	final	int	EXEC	=	 1;
	
	private	static	final	String[]	COMMANDS	=	{ "#include" ,"#exec" };
	private	static	final	char[]		BLANKS		=	{' ' ,'\t' ,'\n'};
	
	private int		myCommand;
	private HashMap myAttributes;
	private boolean myIsSSI;
	
	/**
	 * @param	string SSI文字列
	 * @since	1.00
	 */
	public SSIString(String string){
		analize(string);
	}
	
	/**
	 * コンストラクタで渡された文字列が正当なSSIコマンドとして認識できるならtrue。
	 * @return	正当なSSIコマンドならtrue。
	 * @since	1.00
	 */
    public boolean isSSI(){ return myIsSSI; }
	
	/**
	 * @return	SSIコマンドを返す。
	 * @since	1.00
	 */
	public int getCommand(){ return myCommand; }
	
	/**
	 * @return	属性を返す。
	 * @since	1.00
	 */
	public String getAttribute(String name){ return (String)myAttributes.get(name.toLowerCase()); }
	
	private void analize(String string){
		myIsSSI		= false;
		myCommand	= UNKNOWN;
		myAttributes= null;
		exString exstring = new exString(string);
		
		// 最初のブランク読み飛ばし
		try{ exstring.skipBlank(); }
		catch(EOFException e){ return; }
		
		// コマンド
		try{ myCommand = getCommand(exstring.getStringToBlank()); }
		catch(NullPointerException e){ }
		
		// コマンドが不当。
		if(UNKNOWN == myCommand)	return;
		
		// 属性
		try{ myAttributes = getAttributes(exstring); }
		catch(AttributeFormatException e){ return; }
		
		myIsSSI = true;
	}
	
	private int getCommand(String command){
		for(int i=COMMANDS.length-1;0<=i;i--){
			if(COMMANDS[i].equalsIgnoreCase(command))	return i;
		}
		
		return UNKNOWN;
	}
	
	private HashMap getAttributes(exString exstring) throws AttributeFormatException{
		HashMap map = new HashMap();
		
		while(true){
			try{ exstring.skipBlank(); }
			catch(EOFException e){ return map; }
			try{
				String name = exstring.getStringTo('=').trim();
				if(null==name)	throw new AttributeFormatException();
				exstring.ix++;	// '='スキップ
				exstring.skipBlank();
				if(!exstring.is('\"'))	throw new AttributeFormatException();
				exstring.ix++;	// '\"'スキップ
				String value = exstring.getStringTo('\"');
				exstring.ix++;	// '\"'スキップ
				
				map.put(name.toLowerCase() ,value);
				
				try{ if(!exstring.isBlank())	throw new AttributeFormatException(); }
				catch(EOFException e){ return map; }
			}
			catch(NullPointerException e){ throw new AttributeFormatException(); }
			catch(EOFException e){ throw new AttributeFormatException(); }
		}
	}
	
	private class AttributeFormatException extends Exception{
	}
	
	private class exString{
		private	char[]	myChars;
		public	int		ix;
		
		public exString(String string){
			myChars = string.toCharArray();
			ix = 0;
		}
		
		public	void skipBlank() throws EOFException{
			try{ while(isBlank())	ix++; }
			catch(ArrayIndexOutOfBoundsException e){ throw new EOFException(); }
		}
		
		public	boolean isBlank() throws EOFException{
			char c;
			try{ c = myChars[ix]; }
			catch(ArrayIndexOutOfBoundsException e){ throw new EOFException(); }
			
			for(int i=BLANKS.length-1;0<=i;i--){
				if(BLANKS[i]==c)	return true;
			}
			
			return false;
		}
		
		public	boolean is(char c) throws EOFException{
			try{ if(c == myChars[ix])	return true; }
			catch(ArrayIndexOutOfBoundsException e){ throw new EOFException(); }
			return false;
		}
		
		public String getStringToBlank(){
			StringBuffer buf = new StringBuffer();
			try{
				while(!isBlank()){
					buf.append(myChars[ix]);
					ix++;
				}
			}catch(EOFException e){ }
			
			return (0>=buf.length()) ? null : buf.toString();
		}
		
		public String getStringTo(char c) throws EOFException{
			StringBuffer buf = new StringBuffer();
			try{
				while(c != myChars[ix]){
					buf.append(myChars[ix]);
					ix++;
				}
			}catch(ArrayIndexOutOfBoundsException e){ throw new EOFException(); }
			
			return (0>=buf.length()) ? null : buf.toString();
		}
	}
}
