###############################################################################
#
# InterWikiNameのパーサ
#
###############################################################################
package Wiki::InterWiki;
use strict;

#==============================================================================
# コンストラクタ
#==============================================================================
sub new {
	my $class = shift;
	my $wiki  = shift;
	my $self  = {};

	$self->{wiki} = $wiki;
	$self->{interwiki} = [];
	bless $self,$class;

	$self->_parse();
	$self->_add_children($wiki);

	return bless $self;
}

#==============================================================================
# 子WikiをInterWikiに追加
#==============================================================================
sub _add_children {
	my $self = shift;
	my $wiki = shift;

	eval {
		my @children = $wiki->get_wiki_list();
		$self->_add_child($wiki,"",@children);
	}
}
#==============================================================================
# 子WikiをInterWikiに追加(再帰的にcallされるメソッド)
#==============================================================================
sub _add_child {
	my $self   = shift;
	my $wiki   = shift;
	my $parent = shift;
	my @items  = @_;
	my $prev   = "";

	foreach my $item (@items){
		if(ref($item) eq "ARRAY"){
			if($parent eq ""){
				$self->_add_child($wiki,"$prev",@$item);
			} else {
				$self->_add_child($wiki,"$parent/$prev",@$item);
			}
		} else {
			if($parent eq ""){
				$self->add_inter_wiki($wiki->config('script_name')."/$item?page=","$item");
			} else {
				$self->add_inter_wiki($wiki->config('script_name')."/$parent/$item?page=","$parent/$item");
			}
			$prev = $item;
		}
	}
}

#==============================================================================
# パース(コンストラクタから呼ばれます)
#==============================================================================
sub _parse {
	my $self = shift;
	my $wiki = $self->{wiki};
	if($wiki->page_exists("InterWikiName")){
		my $source = $wiki->get_page("InterWikiName");
		$source =~ s/\r//g;
		my @lines = split(/\n/,$source);
		foreach my $line (@lines){
			if(index($line,"*")==0){
				$self->_parse_line($line);
			}
		}
	}
}

#==============================================================================
# 1行をパース
#==============================================================================
sub _parse_line {
	my $self   = shift;
	my $source = shift;
	# 別名リンク
	if ($source =~ /\[([^\[]+?)\|((http|https|ftp|mailto):[\w\.,%~^+\-%\/\?\(\)!\$&=:;\*#\@']*)\]\s*([\w\-]+)/
	 || $source =~ /\[([^\[]+?)\|((file:[^\[\]]*))\]\s*([\w\-]+)/
	 || $source =~ /\[([^\[]+?)\|((\/|\.\/|\.\.\/)+[\w\.,%~^+\-%\/\?\(\)!\$&=:;\*#\@']*)\]\s*([\w\-]+)/) {
		my $label = $1;
		my $url   = $2;
		my $enc   = $4;
		$self->add_inter_wiki($url,$label,$enc);
	}
	# 文字コードの指定なし
	elsif ($source =~ /\[([^\[]+?)\|((http|https|ftp|mailto):[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!\$&=:;\*#\@']*)\]/
	    || $source =~ /\[([^\[]+?)\|(file:[^\[\]]*)\]/
	    || $source =~ /\[([^\[]+?)\|((\/|\.\/|\.\.\/)+[a-zA-Z0-9\.,%~^_+\-%\/\?\(\)!\$&=:;\*#\@']*)\]/) {
		my $label = $1;
		my $url   = $2;
		my $enc   = "";
		$self->add_inter_wiki($url,$label,$enc);
	}
	# 任意のURLリンク
	elsif ($source =~ /\[([^\[]+?)\|(.+?)\]\s*([\w\-]+)/) {
		my $label = $1;
		my $url   = $2;
		my $enc   = $3;
		$self->add_inter_wiki($url,$label,$enc);
	}
	# 任意のURLリンク(文字コードの指定なし)
	elsif ($source =~ /\[([^\[]+?)\|(.+?)\]/) {
		my $label = $1;
		my $url   = $2;
		my $enc   = "";
		$self->add_inter_wiki($url,$label,$enc);

	}
}

#==============================================================================
# InterWikiNameを追加
#==============================================================================
sub add_inter_wiki {
	my $self  = shift;
	my $url   = shift;
	my $label = shift;
	my $enc   = shift;

	push(@{$self->{interwiki}},{label=>$label,quote=>quotemeta($label),url=>$url,enc=>$enc});
}

#==============================================================================
# InterWikiNameが含まれるかどうかチェック
#==============================================================================
sub exists_interwiki {
	my $self = shift;
	my $str  = shift;

	return 0 if (not defined $str);

	# $str の先頭に InterWikiName になりうる書式がなければ、偽を返して終了
	return 0 if (not $str =~ /^\[\[/);

	my @keywords = @{ $self->{interwiki} };

	# 定義された全ての InterWikiName について繰り返す。
	foreach my $keyword (@keywords) {
		my $label = $keyword->{quote};

		# 別名なしの InterWikiName
		if ($str =~ /^\[\[$label:(.+?)\]\]/) {
			$self->{g_post} = $';
			my $enc   = $keyword->{enc};
			my $param = $1;
			$self->{g_label} = $keyword->{label}.':'.$param;
			if ($enc ne q{}) {
				&Jcode::convert(\$param, $enc);
			}
			$self->{g_url} = $keyword->{url}.Util::url_encode($param);
			return 1;
		}

		# 別名ありの InterWikiName
		elsif ($str =~ /^\[\[([^\[]+?)\|$label:(.+?)\]\]/) {
			$self->{g_post} = $';
			$self->{g_label} = $1;
			my $enc   = $keyword->{enc};
			my $param = $2;
			if ($enc ne q{}) {
				&Jcode::convert(\$param, $enc);
			}
			$self->{g_url} = $keyword->{url}.Util::url_encode($param);
			return 1;
		}
	}
	return 0;
}

1;