/*
 * $Id: AnchorCollectionCallback.java,v 1.4 2006/01/27 16:39:04 rampil Exp $
 * Copyright (c) 2004 LOGICAL-PARADOX.ORG
 */
package org.logical_paradox.rss.http;

import java.io.OutputStreamWriter;
import java.util.Enumeration;
import java.util.Vector;

import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import javax.swing.text.html.HTMLEditorKit;


/**
 * アンカータグを収集するためのコールバッククラス
 * (javax.swing.text.html.parser.HTMLEditorKit.Parserのコールバック)
 * @author satoshi akabane@logical-paradox.org
 * @version $Revision: 1.4 $
 */
public class AnchorCollectionCallback extends HTMLEditorKit.ParserCallback {
	private OutputStreamWriter out;
	private Vector<String> anchors = new Vector<String>();
	private boolean acceptIndex = true;						// 解析対象ページをINDEXしても良いか
	private boolean acceptFollow = true;						// 解析対象ページの先のリンクをINDEXしても良いか

	/**
	 * デフォルトコンストラクタ
	 */
	public AnchorCollectionCallback() {
		out = null;
	}

	/**
	 * コンストラクタ
	 */
	public AnchorCollectionCallback(OutputStreamWriter writer) {
		out = writer;
	}

	/**
	 * アンカーリストに何か格納されているかどうかを返す
	 */
	public int size() {
		return anchors.size();
	}

	/**
	 * アンカーリストを全て削除する
	 */
	public void clean() {
		anchors.removeAllElements();
		acceptIndex = acceptFollow = true;
	}

	/**
	 * アンカーリストを返す．
	 * @return アンカーのリスト
	 * @throws NoIndexException 解析に失敗
	 */
	public Vector<String> getAnchors() throws NoIndexException {
		// 不恰好だが..
		if(acceptIndex == false) {
			/*
			 * このブロックに突入した場合，ページの収集が禁止されているので，少なくとも
			 * NoIndexExceptionは発生する
			 */
			if(acceptFollow == true) {
				// このページ自体は無効だが，リンクはOKの場合
				throw new NoIndexException("case 1", anchors);
			} else {
				// このページもリンクも完全にダメな場合
				throw new NoIndexException("case 2");
			}
		} else {
			if(acceptFollow == false) {
				// このページはOKだが，リンクはダメな場合
				return null;
			} else {
				// このページもOKだし，リンクもOKの場合
				return anchors;
			}
		}
	}

	/**
	 * 開始タグがきた場合のハンドラ
	 */
	public void handleStartTag(HTML.Tag t, MutableAttributeSet a, int pos) {
		super.handleStartTag(t, a, pos);

		String tag = t.toString().trim().toLowerCase();
		if(tag.equals("meta")) {
			handleMetaTag(t, a, pos);
		} else if(tag.equals("a") || tag.equals("area")) {
			handleAnchorTag(t, a, pos);
		}
	}

	/**
	 * メタタグがきた場合のハンドラ
	 */
	public void handleMetaTag(HTML.Tag t, MutableAttributeSet a, int pos) {
		// METAタグを抽出
		Enumeration e = a.getAttributeNames();
		String content = null;

		while(e.hasMoreElements()) {
			Object key = e.nextElement();
			if(key != null && key.toString().trim().toLowerCase().equals("name")) {
				String prop = (String)a.getAttribute(key);
				if(prop.trim().toLowerCase().equals("robots") == false) {
					// <meta name=robots ..>でないのでなにもしないで返す
					return;
				}
			} else if(key != null && key.toString().trim().toLowerCase().equals("content")) {
				content = (String)a.getAttribute(key);
			}
		}

		if(content == null || content.trim().length() == 0) {
			return;
		}

		// <meta name=robots content=..>の場合はこれ以降の処理を実施する
		String[] param = content.split(",");
		if(param == null || param.length == 0) {
			return;
		}

		String p = null;
		for(int i = 0; i < param.length; i++) {
			p= param[i].trim().toLowerCase();

			if(p.equals("noindex")) {
				// ページの収集が禁止されている場合
				acceptIndex = false;
			} else if(p.equals("nofollow")) {
				// このページ以下のリンクのトレースを禁止している場合
				acceptFollow = false;
			}
		}
	}

	/**
	 * アンカータグがきた場合のハンドラ
	 */
	public void handleAnchorTag(HTML.Tag t, MutableAttributeSet a, int pos) {
		// アンカータグを抽出
		// <A>または<AREA>
		Enumeration e = a.getAttributeNames();
		String href = null;

		while(e.hasMoreElements()) {
			Object key = e.nextElement();
			if(key != null && key.toString().trim().toLowerCase().equals("href") == true) {
				href = (String)a.getAttribute(key);
				break;
			}
		}

		if(href != null) {
			anchors.addElement(href);

			if(out != null) {
				// デバッグ用のログライターオブジェクトが設定されている場合は
				// 収集したURLを出力する
				try {
					out.write(href);
					out.write("\n");
					out.flush();
				} catch(Exception ioe) {}
			}
		}
	}

	/**
	 * 閉じタグの必要ないタグのハンドラ
	 * このクラスでは閉じタグは無視するので，handleStartTag()を呼び出すだけ
	 */
	public void handleSimpleTag(HTML.Tag t, MutableAttributeSet a, int pos) {
		handleStartTag(t, a, pos);
	}
}

// end of AnchorCollectionCallback.java
