# -*- mode: perl; coding: utf-8 -*-
# keitairc/lib/plugins/00location_receiver
# 位置情報送信、のコールバック
# $Id: 00location_receiver,v 1.12 2008-06-29 09:20:49 morimoto Exp $
# $Source: /home/ishikawa/work/keitairc/tmp/keitairc/lib/plugins/00location_receiver,v $

# The line number (1 incremented) and filename below must be
# actual. see perlsyn.
# line 10 "keitairc/lib/plugins/00location_receiver"

use Net::HTTP;
use XML::Simple;
use Encode;

# WGS84系を渡すこと
sub get_rgeocode_xml {
	my ($lat, $lon) = @_;
	my $s = Net::HTTP->new(Host => 'refits.cgk.affrc.go.jp') || return;
	$s->write_request(GET => "/tsrv/jp/rgeocode.php?lat=$lat&lon=$lon");
	$s->read_response_headers();
	my $xml;
	for(;;){
		my $buf;
		my $n = $s->read_entity_body($buf, 1024);
		return unless defined $n;
		last unless $n;
		$xml .= $buf;
	}
	$xml;
}

sub dms_to_degree{
	my $dms = shift;
	my ($degree, $min, $sec, $secc) = ($dms =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
	$degree + $min/60 + $sec/3600 + $secc/360000;
}

sub wgs84_to_tokyo{
	my ($lat, $lon) = @_;
	return ($lat + 0.00010696*$lat - 0.000017467*$lat - 0.0046020,
		$lon + 0.000046047*$lon + 0.000083049*$lon - 0.010041);
}

sub tokyo_to_wgs84{
	my ($lat, $lon) = @_;
	return ($lat - 0.00010695*$lat + 0.000017464*$lat + 0.0046017,
		$lon - 0.000046038*$lon - 0.000083043*$lon + 0.010040);
}

# see http://labs.anoncom.net/others/GoogleMap/NoAjaxInterface.html
sub google_map_image{
	my ($wx, $wy, $format) = @_;
	my $gwx = sprintf('%0.6f', $wx);
	my $gwy = sprintf('%0.6f', $wy);
	$gwx =~ s/\.//;
	$gwy =~ s/\.//;
	my %format = (
		gif => 1,
		png => 2,
		jpeg => 3,
	);
	my $iconid = 15;
	my $zoom = 2000;
	my $width = 160;
	my $height = 240;
	sprintf('http://maps.google.com/mapdata?cc=JP&min_priority=1&w=%d&h=%d&latitude_e6=%d&longitude_e6=%d&zm=%d&Point=b&Point.latitude_e6=%d&Point.longitude_e6=%d&Point.iconid=%d&Point=e&image_format=%d',
		$width, $height,
		$gwx, $gwy, $zoom, $gwx, $gwy, $iconid, $format{$format});
}

$plugin = {
	name => 'location_receiver',

	action_imprementation => sub {
		my ($request, $name, $session_id, $param_string) = @_;
		my ($cid) = ($param_string =~ /^(\d+)/);
		my $uri = $request->uri();;
		$uri =~ s/.*\?//;
		my %h;
		for my $pair (split(/&/, $uri)){
			my ($k, $v) = split(/=/, $pair);
			$h{$k} = $v;
		}

		my $ci = new Keitairc::ClientInfo($request);
		my $view = new Keitairc::View($::cf, $ci);
		my $p;
		$p->{session_id} = $session_id;
		$p->{cid} = $cid;
		$p->{channel_compact} = $::ib->simple_escape(encode($::cf->web_charset(), $::ib->compact_channel_name($cid)));

		# 測地系
		# 以下の2つの測地系の中から使用している測地系を示す。
		# wgs84 WGS84系: GPS測量で算出される座標系。数回の改定
		# により現在ではITRF座標系と実用上の差異はなくなってい
		# る。
		# tokyo 日本測地系: 測量法施行令第2条で定められた日本標
		# 準の測地系。
		# 備考: 引数内容としては"tokyo"という表示になるが、実際
		# の測地系はWGS84系のデータを使用。
		# from http://www.au.kddi.com/ezfactory/tec/spec/eznavi.html

		# NTT DoCoMo
		if($ci->is_docomo()){
			# iエリアはPOSTで来る
			# ACTN=OK&LAT=%2B35.44.27.996&LON=%2B139.35.37.932&GEO=wgs84&XACC=1&POSINFO=2
			my ($wx, $wy);
			my $posted = $request->content();
			my %posted;
			for my $pair (split(/&/, $posted)){
				my ($k, $v) = split(/=/, $pair);
				$posted{$k} = $v;
			}
			if(defined $posted{LAT}){
				$posted{LAT} =~ s/^%2b//i;
				$posted{LON} =~ s/^%2b//i;
				($wx, $wy) = (dms_to_degree($posted{LAT}), dms_to_degree($posted{LON}));
			}else{
				# iエリアじゃないからlcsかな
				# GET /loc.jsp?lat=%2B35.40.53.008&lon=%2B139.45.57.971&geo=WGS84&x-acc=3 
				# see http://www.utilz.jp/wiki/Gps
				unless(defined $h{lat}){
					$p->{error} = 1;
					$p->{error_lcs} = 1;
					return $view->render('location_receiver.html', $p);
				}
				$h{lat} =~ s/^%2b//i;
				$h{lon} =~ s/^%2b//i;
				($wx, $wy) = (dms_to_degree($h{lat}), dms_to_degree($h{lon}));
			}

			my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
			my $xml_code = get_rgeocode_xml($wx, $wy);
			unless($xml_code){
				$p->{error} = 1;
				$p->{rgeocode_noresponse} = 1;
				return $view->render('location_receiver.html', $p);
			}

			my $xml = XMLin($xml_code);
			if($xml->{status} ne 'true'){
				$p->{error} = 1;
				$p->{rgeocode_invalid} = 1;
				return $view->render('location_receiver.html', $p);
			}
			$p->{wx} = $wx;
			$p->{wy} = $wy;
			$p->{tx} = $tx;
			$p->{ty} = $ty;
			$p->{map_image_url} = google_map_image($wx, $wy, 'gif');
			$p->{address} = $xml->{prefecture}->{pname} .
					$xml->{municipality}->{mname} .
					$xml->{local}->{section};
			Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
			Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
			return $view->render('location_receiver.html', $p);
		}

		# Softbank
		# HTTPヘッダーのx-jphone-geocodeに位置情報が通知されます。
		# x-jphone-geocode: 354053%1A1394557%1A(住所がSJISでエ
		# ンコードされたもの) "%1A"(SUB)で区切られて lat, lon,
		# 住所(SJISでエンコード)の形式になります。住所はドキュ
		# メントを見る限りSJISでエスケープしたものとなっていま
		# すが、正しくデコードできない場合がありました。この情
		# 報は利用しない方が良いのかも知れません。
		# see http://www.utilz.jp/wiki/Gps
		if($ci->is_softbank()){
			my ($lat, $lon);
			if(defined $request->{_headers}->{'x-jphone-geocode'}){
				($lat, $lon) = split(/%1A/, $request->{_headers}->{'x-jphone-geocode'});
				# sigh
				$lat =~ s/^(\d\d)(\d\d)(\d\d)/$1.$2.$3.00/;
				$lon =~ s/^(\d\d\d)(\d\d)(\d\d)/$1.$2.$3.00/;
			}else{
				# GET /loc.jsp?pos=N35.40.53.00E139.45.57.97&geo=wgs84&x-acr=1 
				($lat, $lon) = ($h{pos} =~ /^N([\d.]+)E([\d.]+)$/);
			}
			my ($wx, $wy) = (dms_to_degree($lat), dms_to_degree($lon));
			my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
			my $xml_code = get_rgeocode_xml($wx, $wy);
			unless($xml_code){
				$p->{error} = 1;
				$p->{rgeocode_noresponse} = 1;
				return $view->render('location_receiver.html', $p);
			}

			my $xml = XMLin($xml_code);
			if($xml->{status} ne 'true'){
				$p->{error} = 1;
				$p->{rgeocode_invalid} = 1;
				return $view->render('location_receiver.html', $p);
			}
			$p->{wx} = $wx;
			$p->{wy} = $wy;
			$p->{tx} = $tx;
			$p->{ty} = $ty;
			$p->{map_image_url} = google_map_image($wx, $wy, 'png');
			$p->{address} = $xml->{prefecture}->{pname} .
					$xml->{municipality}->{mname} .
					$xml->{local}->{section};
			Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
			Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
			return $view->render('location_receiver.html', $p);
		}

		# see KDDI au: 技術情報 > 簡易位置情報
		# http://www.au.kddi.com/ezfactory/tec/spec/eznavi.html
		if($ci->is_ezweb()){
			# au W53S location の戻り例
			#   3/?datum=tokyo&unit=dms&lat=35.44.51.75&lon=139.35.15.0
			# au W53S gpsone の戻り例
			# /?ver=1&datum=0&unit=0&lat=%2b35.44.29.09&lon=%2b139.35.38.97&alt=71&time=20080114183222&smaj=116&smin=96&vert=46&majaa=24&fm=2
			$h{lat} =~ s/^%2b//i; # au GPSOneの場合
			$h{lon} =~ s/^%2b//i; # au GPSOneの場合
			my ($wx, $wy) = (dms_to_degree($h{lat}), dms_to_degree($h{lon}));
			my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
			my $xml_code = get_rgeocode_xml($wx, $wy);
			unless($xml_code){
				$p->{error} = 1;
				$p->{rgeocode_noresponse} = 1;
				return $view->render('location_receiver.html', $p);
			}

			my $xml = XMLin($xml_code);
			if($xml->{status} ne 'true'){
				$p->{error} = 1;
				$p->{rgeocode_invalid} = 1;
				return $view->render('location_receiver.html', $p);
			}
			$p->{wx} = $wx;
			$p->{wy} = $wy;
			$p->{tx} = $tx;
			$p->{ty} = $ty;
			$p->{map_image_url} = google_map_image($wx, $wy, 'png');
			$p->{address} = $xml->{prefecture}->{pname} .
					$xml->{municipality}->{mname} .
					$xml->{local}->{section};
			Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
			Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
			return $view->render('location_receiver.html', $p);
		}

		# http://developer.emnet.ne.jp/browser3-1.html
		# Example:
		# http://www.emobilemap.net/positioning.cgi?ver=MOPA-001-2001&pos=N35.44.33.156E135.22.33.124&geo=wgs84&x-acy=1
		if($ci->is_emobile()){
			unless(defined $h{pos}) {
				$p->{error} = 1;
				$p->{error_lcs} = 1;
				return $view->render('location_receiver.html', $p);
			}

			my ($wx, $wy);
			if($h{pos} =~ /N([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)E([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)/){
				($wx, $wy) = ($1, $2);
			}

			($wx, $wy) = (dms_to_degree($wx), dms_to_degree($wy));
			my ($tx, $ty) = wgs84_to_tokyo($wx, $wy);
			my $xml_code = get_rgeocode_xml($wx, $wy);
			unless($xml_code){
				$p->{error} = 1;
				$p->{rgeocode_noresponse} = 1;
				return $view->render('location_receiver.html', $p);
			}

			my $xml = XMLin($xml_code);
			if($xml->{status} ne 'true'){
				$p->{error} = 1;
				$p->{rgeocode_invalid} = 1;
				return $view->render('location_receiver.html', $p);
			}
			$p->{wx} = $wx;
			$p->{wy} = $wy;
			$p->{tx} = $tx;
			$p->{ty} = $ty;
			$p->{map_image_url} = google_map_image($wx, $wy, 'gif');
			$p->{address} = $xml->{prefecture}->{pname} .
					$xml->{municipality}->{mname} .
					$xml->{local}->{section};
			Encode::_utf8_off($p->{address}) if Encode::is_utf8($p->{address});
			Encode::from_to($p->{address}, 'utf8', $::cf->web_charset());
			return $view->render('location_receiver.html', $p);
		}

		return $view->render('location_receiver.html', $p);
	}
};

1;
