/**********************************************************************
 
	Copyright (C) 2003-2004
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomoki SEKIYAMA <sekiyama@yahoo.co.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/



#include <time.h>

#include "v/VgbGPSBrowser.h"
#include "v/VGroupBox.h"
#include "v/VAlignView.h"
#include "v/VStaticText.h"

extern "C" {
#include "gps.h"
}

VExError
VgbGPSBrowser::create_do(const VObjectStatus* s, int flags,VObject * nmp, void * arg)
{
	VObjectStatus _sts;
	VExError err;
	VVAlignView *ali1;
	unsigned int i;

	gps_info = 0;

	_sts.parent = this;
	_sts.descriptor = l_string(std_cm, "GPS Browser");
	_sts.parent = VGroupBox::create(&_sts, VSF_PARENT | VSF_DESC, &err);
	if ( err.code ) {
		destroy();
		return err;
	}
	
	_sts.parent = ali1 = VVAlignView::create(&_sts, VSF_PARENT, &err);
	if ( err.code ) {
		destroy();
		return err;
	}

	_sts.parent = VHAlignView::create(&_sts, VSF_PARENT, &err);
	if ( err.code ) {
		destroy();
		return err;
	}
	
	_sts.alignh = VALIGN_LEFT;
	_sts.descriptor = l_string(std_cm, "Serial Port");
	VStaticText::create(&_sts, VSF_PARENT | VSF_ALIGN | VSF_DESC, &err);
	if ( err.code ) {
		destroy();
		return err;
	}
	
	_sts.alignh = VALIGN_FILL;
	_sts.value_event_handler = gps_selected;
	_sts.value_eh_arg = this;
	gps_selector = VPopupButton::create(&_sts, VSF_PARENT | VSF_ALIGN | VSF_VALUE_EH, &err);
	if ( err.code ) {
		destroy();
		return err;
	}
	
	_sts.parent = ali1;
	for ( i = 0 ; i < sizeof(gps_output)/sizeof(gps_output[0]) ; i++ ) {
		gps_output[i] = VStaticText::create(&_sts, VSF_PARENT, &err);
		if ( err.code ) {
			destroy();
			return err;
		}
	}
	
	SERIAL_PORT_INFO *spi, *spi0 = lookup_serial_port();
	int cnt;
	for ( cnt = 0, spi = spi0 ; spi ; spi = spi->next, cnt++ ) {}
	const L_CHAR **list = new const L_CHAR*[cnt+1];
	list[0] = l_string(std_cm, "(none)");
	for ( i = 1, spi = spi0 ; spi ; spi = spi->next, i++ )
		list[i] = l_string(std_cm, spi->name);
	gps_selector->set_list(cnt+1, list);
	delete[] list;
	
	return initial_VExError(V_ER_NO_ERR,0,0);
}


void
VgbGPSBrowser::destroy_do(VObject * nmp)
{
	if ( gps_info )
		kill_locator(gps_info);
	gps_info = 0;
}


VExError
VgbGPSBrowser::get_status(VObjectStatus * s,int flags) const
{
	VExError err = initial_VExError(V_ER_NO_ERR,flags,0);
	if ( flags & VSF_VALUE ) {
		VM_OP_START_EX
		gps_selector->get_status(s, VSF_VALUE);
		flags &= ~VSF_VALUE;
		VM_OP_END
	}
	err = merge_VExError_vstatus_type(err,VMacro::get_status(s,flags));
	return err;
}

VExError
VgbGPSBrowser::set_status(const VObjectStatus * s,int flags)
{
	VExError err = initial_VExError(V_ER_NO_ERR,flags,0);
	if ( flags & VSF_VALUE ) {
		VM_OP_START_EX
		gps_selector->set_status(s, VSF_VALUE);
		flags &= ~VSF_VALUE;
		VM_OP_END
	}
	flags &= ~VSF_DESC;
	err = merge_VExError_vstatus_type(err,VMacro::set_status(s,flags));
	return err;
}


VgbGPSBrowser::~VgbGPSBrowser()
{
}


V_CALLBACK_D(VgbGPSBrowser::gps_selected)
{
	VgbGPSBrowser *gpsb = (VgbGPSBrowser*)user_arg;
	gpsb->gps_selected_do();
}

void
VgbGPSBrowser::gps_selected_do()
{
	VObjectStatus _sts;
	unsigned int cnt, i;
	SERIAL_PORT_INFO *spi;

	_VM_OP_START_VOID
	if ( gps_info )
		kill_locator(gps_info);
	gps_info = 0;
	
	_sts.descriptor = 0;
	for ( i = 0 ; i < sizeof(gps_output)/sizeof(gps_output[0]) ; i++ ) {
		gps_output[i]->set_status(&_sts, VSF_DESC);
	}
	
	gps_selector->get_status(&_sts, VSF_VALUE);
	if ( _sts.value <= 0 )
		goto end;
	
	spi = lookup_serial_port();
	cnt = _sts.value;
	while ( spi && --cnt )
		spi = spi->next;
	
	if ( spi ) {
		LOCATOR_INIT init;
		init.locator_type = LT_ALLOW_ALL;
		init.listen_func = receive_gps_result;
		init.close_func = 0;
		init.listen_interval = 0;
		init.st = open_serial_port(spi, 4800);
		init.user_data = this;
		gps_info = init_locator_gps(&init);
	}
	
end:
	VM_OP_END
}

void
VgbGPSBrowser::receive_gps_result(LOCATOR_INFO *li, const LOCATION_INFO *info)
{
	if ( li->h.user_data == 0 )
		return;
	((VgbGPSBrowser*)li->h.user_data)->receive_gps_result_do(li, info);
}

void
VgbGPSBrowser::receive_gps_result_do(LOCATOR_INFO *li, const LOCATION_INFO *info)
{
	char buffer[200];
	VObjectStatus _sts;
	_sts.descriptor = l_string(std_cm, const_cast<char*>(
		info->locator_type == LT_GPS_STD ? "Mode: Normal" :
		info->locator_type == LT_GPS_DGPS? "Mode: DGPS" :
		info->locator_type == LT_GPS_SIM ? "Mode: Simulation" :
		"Mode: Unknown"));
	gps_output[0]->set_status(&_sts, VSF_DESC);

	if ( ! (info->state & LS_LOC_UNABLE) ) {
		sprintf(buffer, "x: %f %s  y: %f %s  z: %f %s", 
			info->x, info->x_unit, info->y, info->y_unit, info->z, info->z_unit);
		_sts.descriptor = l_string(std_cm, buffer);
		gps_output[1]->set_status(&_sts, VSF_DESC);
		sprintf(buffer, "sx: %f %s  sy: %f %s  sz: %f %s",
			info->sx, info->sx_unit, info->sy, info->sy_unit, info->sz, info->sz_unit);
		_sts.descriptor = l_string(std_cm, buffer);
		gps_output[2]->set_status(&_sts, VSF_DESC);
	}
	else {
		_sts.descriptor = l_string(std_cm, "x: ???  y: ???  z: ???");
		gps_output[1]->set_status(&_sts, VSF_DESC);
		_sts.descriptor = l_string(std_cm, "");
		gps_output[2]->set_status(&_sts, VSF_DESC);
	}
	if ( ! (info->state & LS_TIME_UNABLE) ) {
		time_t time = (time_t)info->t + UTC_00_00_00_01_01_2001;
		strftime(buffer, sizeof(buffer),
			"time: %a, %d %b %Y %H:%M:%S %z", localtime(&time));
		_sts.descriptor = l_string(std_cm, buffer);
		gps_output[3]->set_status(&_sts, VSF_DESC);
	}
	else {
		_sts.descriptor = l_string(std_cm, "time: ???");
		gps_output[3]->set_status(&_sts, VSF_DESC);
	}
}
