/**
 * @(#)RImporter.java
 *
 * Copyright 2001 Nomura Research Institute, LTD. All rights reserved.
 *
 * RID-X : Rid Importer
 *
 * @author  Intelligent Technology Inc.
 * @version 1.00 2002/02/21
 */
package jp.co.nri.rid.importer;

import java.io.*;
import java.util.*;
import java.text.*;
import javax.swing.*;
//import java.io.IOException;

// W3C DOM
//import	org.w3c.dom.*;

// RID
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.ZApp;
import	jp.co.iti.fagot.util.*;
import	jp.co.nri.rid.error.*;
import	jp.co.nri.rid.analyzer.*;

/**
 * インポータの基本機能を実装したすべてのインポータのスーパークラス
 */

abstract public class RImporter implements iExceptionCode{
	protected static final String	WILD		= "*";
	protected static final String	SEPARATOR		= "/";
	protected static final String	NAMESEPARATOR	= ".";
	protected static final String	ZONEUNIT	= "ZoneUnit";
//	protected static final String	FILE		= "File";
	protected static final String	KEY			= "Key";
	protected static final String	NAME		= "Name";
	protected static final String	EXIST		= "Exist";
	protected static final String	SIZE		= "Size";
//	protected static final String	FILETYPE	= "FileType";
//	protected static final String	TYPE		= "Type";
	protected static final String	DATE		= "Date";
	protected static final String	WIDTH		= "Width";
	protected static final String	HEIGHT		= "Height";
	protected static final String	UNIT		= ".unit";
	protected static final String	ATTRIBUTES	= ".attributes";
	protected static final String	EXTENSIONS	= ".extensions";
	protected static final String	HIT			= ".hit";
	protected static final String	WITHOUT		= "without";
	protected static final String	TRUE		= "true";
	protected static final String	FALSE		= "false";
	protected static final String	CREATOR		= "Creator";
	protected static final String	IMPORTER	= "importer";
	protected static final String	KEY_DIR		= "import.dir";
	protected static final String	KEY_COMMENT	= "import.comment";
	protected static final String	COMMENT		= "Comment";
	
	protected static final String	PAGETYPE	= "PageType";
	protected static final String	STATIC		= "static";
	protected static final String	DYNAMIC		= "dynamic";
	protected static final String	SERVER		= "server";
	
	protected elementBooster	myElement;
	protected String			myUnitName;
	protected FilenameFilter	myFilter;
	protected FilenameFilter	myDirFilter;
	protected String[]			myAttributes;
	protected RWarningException	myWarnings;
	
	abstract	protected	elementBooster	topelement();
	abstract	protected	String			getExtensionKey();
	abstract	protected	elementBooster	extensionNewUnit(elementBooster unit) throws RidException;
	abstract	protected	String			getPageType();
	
	/**
	 * @param	key	Page/Resource/Documentを表すキー文字列を指定する
	 * @since	1.00
	 */
	public RImporter(String key) throws RidException{
		myElement	= topelement();
		
		ZProperties	properties	= DocManager.loadProperty(DocManager.ELEMENT);
		myUnitName		= properties.getProperty(key+UNIT);
		if(null==myUnitName)	throw new RidException(new RidMessage().Error(ERR_NotFoundElementPropertiesKeyI,key+UNIT));
		myAttributes	= ZString.tokenize(properties.getProperty(key+ATTRIBUTES));
		if(null==myAttributes)	throw new RidException(new RidMessage().Error(ERR_NotFoundElementPropertiesKeyI,key+ATTRIBUTES));
		
/*		
		String extensions	= properties.getProperty(key+EXTENSIONS);
		if(null==extensions)	throw new RidException(new RidMessage().Error(ERR_NotFoundElementPropertiesKeyI,key+EXTENSIONS));
		if(WILD.equals(extensions))	myFilter	= new ExtensionFilter();
		else	myFilter	= new ExtensionFilter(ZString.tokenize(extensions));
		String hit = properties.getProperty(key+EXTENSIONS+HIT);
		if(WITHOUT.equals(hit))	((ExtensionFilter)myFilter).hit = false;
*/
		myFilter	= getExtensionFilter(properties);
		myDirFilter	= new DirFilter();
	}
	
	private ExtensionFilter getExtensionFilter(ZProperties properties) throws RidException{
		String exkey		= getExtensionKey();
		String extensions	= properties.getProperty(exkey);
		if(null==extensions)	throw new RidException(new RidMessage().Error(ERR_NotFoundElementPropertiesKeyI,exkey));
		
		ExtensionFilter filter;
		if(WILD.equals(extensions))	filter	= new ExtensionFilter();
		else	filter	= new ExtensionFilter(ZString.tokenize(extensions));
		String hit = properties.getProperty(exkey+HIT);
		if(WITHOUT.equals(hit))	filter.hit = false;
		
		return filter;
	}
	
	/**
	 * インポートをおこなう。
	 * @param	dirname	インポート元ディレクトリ名
	 * @since	1.00
	 */
	public	void	Import(String dirname) throws RidException{
		ZDebug.trace(dirname);
		
		myWarnings = new RWarningException();
		Zone			zone	= new Zone(dirname);
		elementBooster	zoneelem= zone.buildZone(myElement);
		if(null==zoneelem)	return;
		
		resetExist(ZONEUNIT		,zoneelem);
		resetExist(myUnitName	,zoneelem);
//		if(RIgnoreFiles.ignorename(zoneelem.attribute(NAME)))	return;
		Import(zone.ImportDir ,zoneelem);
		if(0<myWarnings.length())	throw  new RidException(myWarnings.getMessage());
/*
		File dir = new File(dirname);
		if(!dir.isDirectory())	return;
		resetExist(ZONEUNIT		,myElement);
		resetExist(myUnitName	,myElement);
		if(RIgnoreFiles.ignorename(myElement.attribute(NAME)))	return;
		Import(dir ,myElement);
*/
	}
	
	protected void Import(File dir ,elementBooster element) throws RidException{
		element.attribute(EXIST ,TRUE);
		
		// child file
		File[] files = dir.listFiles(myFilter);
		int mx = files.length;
		for(int i = 0;i < mx;i++)	add(files[i] ,element);
		
		// child folder
		files = dir.listFiles(myDirFilter);
		mx = files.length;
		for(int i = 0;i < mx;i++){
			String name			= files[i].getName();
			if(RIgnoreFiles.ignorename(name))	continue;
			Import(files[i] ,child(ZONEUNIT ,name ,element));
		}
	}
	
	protected elementBooster child(String unit ,String name ,elementBooster parent) throws RidException {
		elementBooster[] children = parent.children(unit);
		if(null==children)	return newchild(unit ,name ,parent);
		
		int mx = children.length;
		for(int i=0;i<mx;i++){
			if(name.equalsIgnoreCase(children[i].attribute(NAME)))	return children[i];
		}
		
		return newchild(unit ,name ,parent);
	}
	
	protected elementBooster newchild(String unit ,String name ,elementBooster parent) throws RidException {
		Attributes attributes = new Attributes();
//		attributes.add(FILE ,file);
		attributes.add(NAME ,name);
		attributes.add(CREATOR ,IMPORTER);
		attributes.add(COMMENT ,ZApp.getTheApp().getResource().getString(KEY_COMMENT));

		return extensionNewUnit(parent.add(unit ,attributes));
	}
	
	protected void add(File file ,elementBooster element) throws RidException{
		String name = file.getName();
		if(RIgnoreFiles.ignorename(name))	return;
		elementBooster child = child(myUnitName ,name ,element);
		child.attribute(EXIST ,TRUE);
		
		int mx = myAttributes.length;
		for(int i=0;i<mx;i++){
			String attribute = myAttributes[i];
			try{
				if(SIZE.equals(attribute))		child.attribute(SIZE ,String.valueOf(file.length()));
//				else if(TYPE.equals(attribute))	child.attribute(TYPE ,type(name));
				else if(DATE.equals(attribute))	child.attribute(DATE ,DateFormat.getDateTimeInstance().format(new Date(file.lastModified())));
//				else if(FILETYPE.equals(attribute))	child.attribute(FILETYPE	,type(name));
				else if(WIDTH.equals(attribute))	child.attribute(WIDTH		,width(file));
				else if(HEIGHT.equals(attribute))	child.attribute(HEIGHT		,height(file));
			}
			catch(RWarningException e){ myWarnings.add(e); }
		}
	}
/*
	protected String type(String name){
		String type = null;
		StringTokenizer st = new StringTokenizer(name ,NAMESEPARATOR);
		while(st.hasMoreTokens())	type = st.nextToken();
		return type;
	}
*/
	protected String width(File file) throws RWarningException{
		ImageIcon icon;
		
		try{ icon = new ImageIcon(file.getCanonicalPath()); }
		catch(IOException e){ throw new RWarningException(WAR_ReadErrorI ,file.getPath()); }
		int width = icon.getIconWidth();
		if(0<width)	return String.valueOf(width);
		return null;
	}
	protected String height(File file) throws RWarningException{
		ImageIcon icon;
		
		try{ icon = new ImageIcon(file.getCanonicalPath()); }
		catch(IOException e){ throw new RWarningException(WAR_ReadErrorI ,file.getPath()); }
		int height = icon.getIconHeight();
		if(0<height)	return String.valueOf(height);
		return null;
	}
	
	protected void resetExist(String unit ,elementBooster element) throws RidException{
		elementBooster[] elements = element.offspring(unit);
		if(null==elements)	return;
		
		String mytype = getPageType();
		
		int mx = elements.length;
		for(int i=0;i<mx;i++){
			elementBooster elem = elements[i];
			if(RIgnoreFiles.ignorefile(elem.attribute(KEY)))	continue;
			String type = elem.attribute(PAGETYPE);
			if(null!=mytype){
				if(!mytype.equals(type))	continue;
			}
			
			elem.attribute(EXIST ,FALSE);
		}
	}
	
	private	class Zone{
		private	File myBaseDir;
		public	File ImportDir;
		
		public Zone(String base){
			myBaseDir	= new File(base);
			String idir	= ZApp.getTheApp().getResource().getString(KEY_DIR);
			try{
				if(0<idir.length())	ImportDir	= new File(idir);
				else				ImportDir	= new File(base);
			}catch(NullPointerException e){ ImportDir	= new File(base); }
		}
		
		public elementBooster buildZone(elementBooster top) throws RidException {
			return buildZone(top ,zonename(ImportDir));
		}
		
		private elementBooster buildZone(elementBooster top ,String key) throws RidException {
			if(null==key)	return null;
			
			elementBooster	elem= top;
			StringTokenizer	st	= new StringTokenizer(key ,"/");
			while(st.hasMoreTokens()){
				String name = st.nextToken();
				elementBooster child = child(elem ,name);
				if(null==child){
					child = newchild(ZONEUNIT ,name ,elem);
				}
				elem = child;
			}
			
			return elem;
		}
		
		private String zonename(File dir){
			try{ if(!dir.isDirectory())		return null; }
			catch(NullPointerException e){	return null; }
			
			if(myBaseDir.equals(dir))	return "";
			String parent = zonename(dir.getParentFile());
			if(null==parent)	return null;
			return parent + "/" + dir.getName();
		}
		
		private elementBooster child(elementBooster parent ,String name){
			elementBooster[] children = parent.children(ZONEUNIT);
			if(null==children)	return null;
			int mx = children.length;
			for(int i=0;i<mx;i++){
				if(name.equalsIgnoreCase(children[i].attribute(NAME)))	return children[i];
			}
			
			return null;
		}
	}
}
