/**
 * @(#)FileNameStudio.java
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 * RID-3 : File Name Studio
 * @author  Intelligent Technology Inc.
 * @version 1.00 2001/10/01-2001/12/28
 * @see 
 */
package	jp.co.nri.rid.analyzer;

import	java.net.*;
import	java.io.*;
import java.util.*;
import	jp.co.nri.rid.xml.*;
import	jp.co.nri.rid.table.editor.filter.*;
import	jp.co.iti.fagot.doc.DocManager;
import	jp.co.iti.fagot.util.*;
import jp.co.nri.rid.error.*;

/**
 * リンクURL文字列を解析するためのメソッドを集めたクラス
 */

public class FileNameStudio implements iExceptionCode{
	private static final String DELIM_FILE		= "/\\";
	private static final String DELIM_CONTENT	= ";";
	private static final String DELIM_CONTENTURL= "=";
//	private static final String DELIM_ANCHOR	= "#?";
	private static final String SEPARATOR		= "/";
	private static final String ZONEUNIT		= "ZoneUnit";
	private static final String NAME			= "Name";
	private static final String FILE			= "File";
	private static final String CREATOR			= "Creator";
	private static final String EXIST			= "Exist";
	private static final String FALSE			= "false";
//	private static final String	EXTENSIONS	= ".extensions";
	private static final String	HIT			= ".hit";
	private static final String	WITHOUT		= "without";
	private static final String	WILD		= "*";
	private static final String[] URLHEADERS = { "http://" ,"https://" ,"ftp://" ,"file://" ,"mail://" ,"news://" ,"mailto:" ,"telto:" ,"tel:" ," " };
	private static final String[] SKIPHEADERS = { "#" ,"?" ,"javascript:"};
	private static final char[]	URLCHARS = { ':' ,';' ,'*' ,'\"' ,'<' ,'>' ,'|' ,'#' };
	private static final String[] ACTIVEHEADERS = { "<%" ,"<?" ,"<cfoutput>" };
	
	static private ExtensionFilter filterStatic		= null;
	static private ExtensionFilter filterDynamic	= null;
	static private ExtensionFilter filterResource	= null;
	
	/**
	 * URL系文字列かどうかを判定する。(http:// https:// ftp:// mail:// news:// mailto: telto:のいずれかで始まっていればURLとする)
	 * @param	url	URL
	 * @return	URLならtrue
	 * @since	1.00
	 */
	public static boolean isURL(String url){
		String lowerurl = url.toLowerCase();
		int mx = URLHEADERS.length;
		for(int i=0;i<mx;i++){
			if(lowerurl.startsWith(URLHEADERS[i]))	return true;
		}
		
		mx = URLCHARS.length;
		for(int i=0;i<mx;i++){
			if(0<=lowerurl.indexOf(URLCHARS[i]))	return true;
		}
		
		StringTokenizer tokenizer = new StringTokenizer(url ,DELIM_FILE);
		for(int i=tokenizer.countTokens()-1;0<=i;i--){
			String str = tokenizer.nextToken();
			if(str.startsWith(" "))	return true;
			if(str.startsWith(".")){
				if(str.equals(".."))	continue;
				if(str.equals("."))		continue;
				return true;
			}
		}
		
		return false;
	}
	
	public static boolean checkForSWF(String url) throws RidException {
		String lowerurl = url.toLowerCase();
		if(lowerurl.startsWith("fscommand:"))	return false;
		
		if(url.endsWith("/"))	return true;
		if(isStaticPage(url))	return true;
		if(isDynamicPage(url))	return true;
		if(isResource(url))		return true;
		
		int mx = URLHEADERS.length;
		for(int i=0;i<mx;i++){
			if(lowerurl.startsWith(URLHEADERS[i]))	return true;
		}
		
		return false;
	}
	
	/**
	 * StaticPage系拡張子かどうかを判定する。(拡張子はelement.propertiesのimport.page.extensions.staticを参照)
	 * @param	name	ファイル名
	 * @return	Page系拡張子ならtrue
	 * @since	1.00
	 */
	public static boolean isStaticPage(String name) throws RidException {
//		ExtensionFilter filter = filter("import.page.extensions.static");
//		return filter.hit(name);
		try{ return filterStatic.hit(name); }
		catch(NullPointerException e){
			filterStatic = filter("import.page.extensions.static");
			return filterStatic.hit(name);
		}
	}
	
	/**
	 * DynamicPage系拡張子かどうかを判定する。(拡張子はelement.propertiesのimport.page.extensions.dynamicを参照)
	 * @param	name	ファイル名
	 * @return	Page系拡張子ならtrue
	 * @since	1.00
	 */
	public static boolean isDynamicPage(String name) throws RidException {
//		ExtensionFilter filter = filter("import.page.extensions.dynamic");
//		return filter.hit(name);
		try{ return filterDynamic.hit(name); }
		catch(NullPointerException e){
			filterDynamic = filter("import.page.extensions.dynamic");
			return filterDynamic.hit(name);
		}
	}
	
	/**
	 * Zone系文字列かどうかを判定する。(拡張子がなければZone系とする)
	 * @param	name	ファイル名
	 * @return	Zone系ならtrue
	 * @since	1.00
	 */
	public static boolean isZone(String name){
		if(0>name.indexOf("."))	return true;
		return false;
	}
	
	/**
	 * Resource系拡張子かどうかを判定する。(拡張子はelement.propertiesのimport.resource.extensionsを参照)
	 * @param	name	ファイル名
	 * @return	Resource系拡張子ならtrue
	 * @since	1.00
	 */
	public static boolean isResource(String name) throws RidException {
//		ExtensionFilter filter = filter("import.resource.extensions");
//		return filter.hit(name);
		try{ return filterResource.hit(name); }
		catch(NullPointerException e){
			filterResource = filter("import.resource.extensions");
			return filterResource.hit(name);
		}
	}
	
	/**
	 * skipするURLかどうかを判定する。(# ,? ,JavaScript:のいずれかで始まっていればskipする)
	 * @param	url	URL
	 * @return	skipするURLならtrue
	 * @since	1.00
	 */
	public static boolean skip(String url){
		String lowerurl = url.toLowerCase();
		int mx = SKIPHEADERS.length;
		for(int i=0;i<mx;i++){
			if(lowerurl.startsWith(SKIPHEADERS[i]))	return true;
		}
		
		return false;
	}
	
	/**
	 * <meta content="0;URL=XXX">のリンクを抽出する。
	 * @param	content	content属性をわたす。
	 * @return	抽出されたリンク部分。抽出できなければnull。
	 */
	public static String getMetaContentLink(String content){
		StringTokenizer ctoken = new StringTokenizer(content ,DELIM_CONTENT);
		for(int i=ctoken.countTokens()-1;0<=i;i--){
			StringTokenizer utoken = new StringTokenizer(ctoken.nextToken() ,DELIM_CONTENTURL);
			
			int j=utoken.countTokens();
			if(2 != j)	continue;
			if(!"url".equalsIgnoreCase(utoken.nextToken()))	continue;
			return utoken.nextToken();
		}
		
		return null;
	}
	
	private static int indexOfEx(String text ,String[] strs){
		int ix = -1;
		for(int i=strs.length-1;0<=i;i--){
			int wix	= text.indexOf(strs[i]);
			ix = ix(ix ,wix);
		}
		
		return ix;
	}
	
	private static int indexOfEx(String text ,char[] chars){
		int ix = -1;
		for(int i=chars.length-1;0<=i;i--){
			int wix	= text.indexOf(chars[i]);
			ix = ix(ix ,wix);
		}
		
		return ix;
	}
	
	private static int ix(int ix1 ,int ix2){
		if((0<=ix1)&&(0<=ix2))	return (ix1<ix2) ? ix1 : ix2 ;
		return (ix1>ix2) ? ix1 : ix2 ;
	}
	
	private static String cutParam(String text){
		int active = indexOfEx(text ,ACTIVEHEADERS);
		
		int anchor = -1;
		int spoint = text.indexOf('#');	// #の位置
		if(0 <= spoint){	// #あり(アンカーorCF変数)
			int s2point = text.indexOf('#' ,spoint+1);	// 2個目の#の位置
			if(0 > s2point)	anchor = spoint;	// アンカー
		}
		
		int delim = text.indexOf('?');	// ?の位置
		if(0>anchor){	// アンカーなし
			if(0<=spoint){	// #あり(=CF変数)
				if(0>active)	active = spoint;
				else{
					if(spoint < active)	active = spoint;
				}
			}
		}
		else{	// アンカーあり(=CF変数なし)
			if(0>delim)	delim = anchor;
			else{
				if(anchor < delim)	delim = anchor;
			}
		}
		
		if(0>delim){
			if(0>active)	return text;
			return null;
		}
		
		if(0<=active){
			if(active<delim) return null;
		}
		
		return text.substring(0 ,delim);
	}
	
	private static int indexOfCgiSp(String text){
		char[] chars = text.toCharArray();
		
		char before = (char)-1;
		int mx=chars.length;
		for(int i=0;i<mx;i++){
			char c = chars[i];
			
			if(('?'==c)&&('<'!=before)){
				try{
					if('>'!=chars[i+1])	return i;
				}catch(ArrayIndexOutOfBoundsException e){ return i; }
			}
			before = c;
		}
		
		return -1;
	}
	
	public static String cutParamForUrlUnit(String text){
		int anchor = -1;
		
		int spoint = text.indexOf('#');	// #の位置
		if(0 <= spoint){	// #あり(アンカーorCF変数)
			int s2point = text.indexOf('#' ,spoint+1);	// 2個目の#の位置
			if(0 > s2point)	anchor = spoint;	// アンカー
		}
		
		int cgi	= indexOfCgiSp(text);
		
		int ix = ix(anchor ,cgi);
		
		if(0>ix)	return text;
		
		return text.substring(0 ,ix);
	}
	
	public static String filename(String url){
		try{
			String[] tokens		= token(url ,DELIM_FILE);
//			String[] filetokens	= token(tokens[tokens.length-1] ,DELIM_ANCHOR);
//			filename = filetokens[0];
/*
			StringTokenizer tokenizer = new StringTokenizer(tokens[tokens.length-1] ,DELIM_ANCHOR);
			if(0>=tokenizer.countTokens())	return null;
			String name = tokenizer.nextToken();
			if(0<=name.indexOf("<%"))	return null;
			if(0<=name.indexOf("<?"))	return null;
			return name;
*/
			return cutParam(tokens[tokens.length-1]);
		}
		catch(NullPointerException e){ return null; }
	}
	
	public static String pureURL(String url){
		return cutParam(url);
/*
		StringTokenizer tokenizer = new StringTokenizer(url ,DELIM_ANCHOR);
		if(0>=tokenizer.countTokens())	return null;
		String name = tokenizer.nextToken();
		if(0<=name.indexOf("<%"))	return null;
		if(0<=name.indexOf("<?"))	return null;
		return name;
*/

/*		
		try{
			String[] urltokens	= token(url ,DELIM_ANCHOR);
			return urltokens[0];
		}
		catch(NullPointerException e){ return null; }
*/
	}
/*
	public static String pureURLForUrlUnit(String url){
		return cutParamForUrlUnit(url);
	}
*/
	
	public static String zonename(String file){
		StringTokenizer tokenizer = new StringTokenizer(file ,DELIM_FILE);
//		String[] tokens		= token(file ,DELIM_FILE);
		
		int mx = tokenizer.countTokens()-1;
//		int mx = tokens.length-1;
		if(0>=mx)	return null;
		StringBuffer strbuf = new StringBuffer(tokenizer.nextToken());
		for(int i=1;i<mx;i++){
			strbuf.append(SEPARATOR);
			strbuf.append(tokenizer.nextToken());
		}
		return strbuf.toString();
	}
	
	public static String zonename(String basezone ,String zone){
		String[]	basetokens	= null;
//		String[]	zonetokens	= null;
		Vector		base		= null;
		
		try {
			basetokens	= token(basezone ,DELIM_FILE);
			base		= new Vector(Arrays.asList(basetokens));
		}catch(NullPointerException e){
			base		= new Vector();
		}
		
		StringTokenizer tokenizer = null;
		try {
			tokenizer = new StringTokenizer(zone ,DELIM_FILE);
//			zonetokens	= token(zone ,DELIM_FILE);
		}catch(NullPointerException e){
			if(0<base.size())	return basezone;
			return null;
		}
		
		int mx = tokenizer.countTokens();
		for(int i=0;i<mx;i++){
			String token = tokenizer.nextToken();
			if("..".equals(token)){
				int ix = base.size();
				if(0>=ix)	return null;
				base.removeElementAt(ix-1);
			}
			else if(".".equals(token))	continue;
			else	base.add(token);
		}
		
		return zonename((String[])base.toArray(new String[0]));
	}
	
	public static String zonename(String[] tokens){
		int mx = tokens.length;
		if(0>=mx)	return null;
		StringBuffer zonename = new StringBuffer(tokens[0]);
		
		for(int i=1;i<mx;i++){
			zonename.append(SEPARATOR);
			zonename.append(tokens[i]);
		}
		
		return zonename.toString();
	}
	
	public static String page(String url){
		if(null==url)				return null;
		if(url.endsWith(SEPARATOR))	return null;
		
		StringTokenizer tokenizer = new StringTokenizer(url ,DELIM_FILE);
		int mx=tokenizer.countTokens()-1;
		for(int i=0;i<mx;i++)	tokenizer.nextToken();
		
		return tokenizer.nextToken();
	}
	
	public static String fusion(String url1 ,String url2)
		throws java.lang.ArrayIndexOutOfBoundsException
	{
		Vector tokens	= null;
		
/*
		StringTokenizer tokenizer = new StringTokenizer(url2 ,DELIM_ANCHOR);
		String newurl2	= tokenizer.nextToken();
		if(0<=newurl2.indexOf("<%"))	return null;
		if(0<=newurl2.indexOf("<?"))	return null;
*/		
		
		String newurl2	= cutParam(url2);
		if(null==newurl2) return null;
		
		StringTokenizer tokenizer = new StringTokenizer(url1 ,DELIM_FILE);
		int mx=tokenizer.countTokens()-1;
		if(0<mx){
			tokens = new Vector(mx);
			for(int i=0;i<mx;i++)	tokens.add(tokenizer.nextToken());
		}
		else	tokens = new Vector();
		
		tokenizer = new StringTokenizer(newurl2 ,DELIM_FILE);
		mx=tokenizer.countTokens();
		for(int i=0;i<mx;i++){
			String token = tokenizer.nextToken();
			if("..".equals(token)){
				int ix = tokens.size();
//				if(0>=ix)	return null;
				tokens.removeElementAt(ix-1);
			}
			else if(".".equals(token))	continue;
			else	tokens.add(token);
		}
		
		String[] array = (String[])tokens.toArray(new String[0]);
		mx = array.length;
		if(mx<=0)	return null;
		
		StringBuffer url = new StringBuffer(array[0]);
		for(int i=1;i<mx;i++){
			url.append(SEPARATOR);
			url.append(array[i]);
		}
		
		if(newurl2.endsWith(SEPARATOR))	url.append(SEPARATOR);
		
		return url.toString();
	}
	
	public static String simplefusion(String url1 ,String url2){
		Vector tokens	= null;
		
/*
		StringTokenizer tokenizer = new StringTokenizer(url2 ,DELIM_ANCHOR);
		String newurl2	= tokenizer.nextToken();
		if(0<=newurl2.indexOf("<%"))	return null;
		if(0<=newurl2.indexOf("<?"))	return null;
*/
		String newurl2	= cutParam(url2);
		if(null==newurl2)	return null;
		
		StringTokenizer tokenizer = new StringTokenizer(url1 ,DELIM_FILE);
		int mx=tokenizer.countTokens()-1;
		if(0<mx){
			tokens = new Vector(mx);
			for(int i=0;i<mx;i++)	tokens.add(tokenizer.nextToken());
		}
		else	tokens = new Vector();
		
		tokenizer = new StringTokenizer(newurl2 ,DELIM_FILE);
		mx=tokenizer.countTokens();
		for(int i=0;i<mx;i++){
			String token = tokenizer.nextToken();
			tokens.add(token);
		}
		
		String[] array = (String[])tokens.toArray(new String[0]);
		mx = array.length;
		if(mx<=0)	return null;
		
		StringBuffer url = new StringBuffer(array[0]);
		for(int i=1;i<mx;i++){
			url.append(SEPARATOR);
			url.append(array[i]);
		}
		
		return url.toString();
	}
	
/*
	public static String simplefusionForUrlUnit(String url1 ,String url2){
		Vector tokens	= null;
		
		String newurl2	= cutParamForUrlUnit(url2);
		if(null==newurl2)	return null;
		
		StringTokenizer tokenizer = new StringTokenizer(url1 ,DELIM_FILE);
		int mx=tokenizer.countTokens()-1;
		if(0<mx){
			tokens = new Vector(mx);
			for(int i=0;i<mx;i++)	tokens.add(tokenizer.nextToken());
		}
		else	tokens = new Vector();
		
		tokenizer = new StringTokenizer(newurl2 ,DELIM_FILE);
		mx=tokenizer.countTokens();
		for(int i=0;i<mx;i++){
			String token = tokenizer.nextToken();
			tokens.add(token);
		}
		
		String[] array = (String[])tokens.toArray(new String[0]);
		mx = array.length;
		if(mx<=0)	return null;
		
		StringBuffer url = new StringBuffer(array[0]);
		for(int i=1;i<mx;i++){
			url.append(SEPARATOR);
			url.append(array[i]);
		}
		
		return url.toString();
	}
*/	
	
	public static String[] token(String text ,String delim){
		StringTokenizer tokenizer = new StringTokenizer(text ,delim);
		
		int mx=tokenizer.countTokens();
		if(0>=mx)	return null;
		String[] token = new String[mx];
		for(int i=0;i<mx;i++)	token[i] = tokenizer.nextToken();
		return token;
	}
	
	/**
	 * @return file で指定された ZoneUnit。
	 *  存在しなければ、新規に作成した ZoneUnit を返すが、
	 *  作成に 失敗した場合は null を返す。
	 */
	public static elementBooster zone(elementBooster topzone ,String file ,String creator){
		elementBooster element = topzone;
		
//		String[] tokens	= token(file ,DELIM_FILE);
		StringTokenizer tokenizer = new StringTokenizer(file ,DELIM_FILE);
		int mx=tokenizer.countTokens()-1;
		if(0>=mx)	return element;
		String token = tokenizer.nextToken();
		StringBuffer key = new StringBuffer(token);
		element = zoneunit(element ,key.toString() ,token ,creator);
		if (element == null) {
			return null;
		}
		for(int i=1;i<mx;i++){
			token = tokenizer.nextToken();
			key.append(SEPARATOR);
			key.append(token);
			element = zoneunit(element ,key.toString() ,token ,creator);
			if (element == null) {
				return null;
			}
		}
		return element;
	}
	public static elementBooster zoneunit(elementBooster parent ,String key ,String name ,String creator){
		elementBooster[] children = parent.children();
		
		int mx = 0;
		if(null!=children)	mx = children.length;
		
		for(int i=0;i<mx;i++){
			String file = children[i].attribute(FILE);
			if(key.equalsIgnoreCase(file)) {
				if (children[i].tagname().equals(ZONEUNIT)) {
					/* key に一致する ZoneUnit があった場合 */
					return children[i];
				} else {
					/* ZoneUnit 以外で、key に一致するユニットがすでにあった場合 */
					return null;
				}
			}
		}
		
		elementBooster child = parent.add(ZONEUNIT);
//		child.attribute(FILE	,key);
		child.attribute(NAME	,name);
		child.attribute(CREATOR	,creator);
		child.attribute(EXIST	,FALSE);
		return child;
	}
	
	public static elementBooster unit(elementBooster parent ,String name ,String keyname ,String key){
		elementBooster[] children = parent.offspring(name);
		if(null==children)	return null;
		
		int mx=children.length;
		for(int i=0;i<mx;i++){
			String value = children[i].attribute(keyname);
			if(key.equalsIgnoreCase(value))	return children[i];
		}
		
		return null;
	}
	
	private static ExtensionFilter filter(String key) throws RidException {
		ZProperties	properties	= DocManager.loadProperty(DocManager.ELEMENT);
		String		extensions	= properties.getProperty(key);
		
		if(null==extensions) throw new RidException(new RidMessage().Error(ERR_NotFoundElementPropertiesKey,key));
		
		ExtensionFilter filter = null;
		if(WILD.equals(extensions))	filter	= new ExtensionFilter();
		else						filter	= new ExtensionFilter(ZString.tokenize(extensions));
		
		String hit = properties.getProperty(key+HIT);
		if(WITHOUT.equals(hit))	filter.hit = false;
		
		return filter;
	}
}
