2013-09-18 08:05:24 +00:00
# include <errno.h>
# include <gio/gio.h>
# include <libxml/parser.h>
# include <libxml/xpath.h>
2013-09-17 08:00:12 +00:00
# include <swe-glib.h>
2013-09-13 23:25:46 +00:00
# include "ag-chart.h"
struct _AgChartPrivate {
2013-09-17 20:18:24 +00:00
gchar * name ;
gchar * country ;
gchar * city ;
2013-09-13 23:25:46 +00:00
gchar * save_buffer ;
} ;
2013-09-17 20:18:24 +00:00
enum {
PROP_0 ,
PROP_NAME ,
PROP_COUNTRY ,
PROP_CITY
} ;
2013-09-18 08:05:24 +00:00
typedef enum {
XML_CONVERT_STRING ,
XML_CONVERT_DOUBLE ,
XML_CONVERT_INT
} XmlConvertType ;
2013-09-18 08:02:23 +00:00
G_DEFINE_QUARK ( ag - chart - error - quark , ag_chart_error ) ;
2013-09-13 23:25:46 +00:00
G_DEFINE_TYPE ( AgChart , ag_chart , GSWE_TYPE_MOMENT ) ;
# define GET_PRIVATE(instance) (G_TYPE_INSTANCE_GET_PRIVATE((instance), AG_TYPE_CHART, AgChartPrivate))
2013-09-17 20:18:24 +00:00
static void ag_chart_set_property ( GObject * gobject , guint prop_id , const GValue * value , GParamSpec * param_spec ) ;
static void ag_chart_get_property ( GObject * gobject , guint prop_id , GValue * value , GParamSpec * param_spec ) ;
static void ag_chart_finalize ( GObject * gobject ) ;
2013-09-13 23:25:46 +00:00
static void
ag_chart_class_init ( AgChartClass * klass )
{
2013-09-17 20:18:24 +00:00
GObjectClass * gobject_class = G_OBJECT_CLASS ( klass ) ;
2013-09-13 23:25:46 +00:00
g_type_class_add_private ( klass , sizeof ( AgChartPrivate ) ) ;
2013-09-17 20:18:24 +00:00
gobject_class - > set_property = ag_chart_set_property ;
gobject_class - > get_property = ag_chart_get_property ;
gobject_class - > finalize = ag_chart_finalize ;
g_object_class_install_property ( gobject_class , PROP_NAME , g_param_spec_string ( " name " , " Chart name " , " Name of the person on this chart " , NULL , G_PARAM_READWRITE ) ) ;
g_object_class_install_property ( gobject_class , PROP_COUNTRY , g_param_spec_string ( " country " , " Country name " , " Name of the country of birth " , NULL , G_PARAM_READWRITE ) ) ;
g_object_class_install_property ( gobject_class , PROP_CITY , g_param_spec_string ( " city " , " City name " , " Name of the city of birth " , NULL , G_PARAM_READWRITE ) ) ;
2013-09-13 23:25:46 +00:00
}
static void
ag_chart_init ( AgChart * chart )
{
chart - > priv = GET_PRIVATE ( chart ) ;
2013-09-17 20:18:24 +00:00
chart - > priv - > name = NULL ;
chart - > priv - > country = NULL ;
chart - > priv - > city = NULL ;
chart - > priv - > save_buffer = NULL ;
}
static void
ag_chart_set_property ( GObject * gobject , guint prop_id , const GValue * value , GParamSpec * param_spec )
{
switch ( prop_id ) {
case PROP_NAME :
ag_chart_set_name ( AG_CHART ( gobject ) , g_value_get_string ( value ) ) ;
break ;
case PROP_COUNTRY :
ag_chart_set_country ( AG_CHART ( gobject ) , g_value_get_string ( value ) ) ;
break ;
case PROP_CITY :
ag_chart_set_city ( AG_CHART ( gobject ) , g_value_get_string ( value ) ) ;
break ;
}
}
static void
ag_chart_get_property ( GObject * gobject , guint prop_id , GValue * value , GParamSpec * param_spec )
{
switch ( prop_id ) {
case PROP_NAME :
g_value_set_string ( value , AG_CHART ( gobject ) - > priv - > name ) ;
break ;
case PROP_COUNTRY :
g_value_set_string ( value , AG_CHART ( gobject ) - > priv - > country ) ;
break ;
case PROP_CITY :
g_value_set_string ( value , AG_CHART ( gobject ) - > priv - > city ) ;
break ;
}
}
static void
ag_chart_finalize ( GObject * gobject )
{
AgChart * chart = AG_CHART ( gobject ) ;
if ( chart - > priv - > name ! = NULL ) {
g_free ( chart - > priv - > name ) ;
}
if ( chart - > priv - > country ! = NULL ) {
g_free ( chart - > priv - > country ) ;
}
if ( chart - > priv - > city ! = NULL ) {
g_free ( chart - > priv - > city ) ;
}
if ( chart - > priv - > save_buffer ! = NULL ) {
g_free ( chart - > priv - > save_buffer ) ;
}
2013-09-13 23:25:46 +00:00
}
AgChart *
2013-09-14 15:37:33 +00:00
ag_chart_new_full ( GsweTimestamp * timestamp , gdouble longitude , gdouble latitude , gdouble altitude , GsweHouseSystem house_system )
2013-09-13 23:25:46 +00:00
{
2013-09-17 07:31:37 +00:00
AgChart * chart ;
2013-09-14 15:37:33 +00:00
GsweCoordinates * coords = g_new0 ( GsweCoordinates , 1 ) ;
coords - > longitude = longitude ;
coords - > latitude = latitude ;
coords - > altitude = altitude ;
2013-09-17 07:31:37 +00:00
chart = AG_CHART ( g_object_new ( AG_TYPE_CHART ,
2013-09-14 15:37:33 +00:00
" timestamp " , timestamp ,
" coordinates " , coords ,
" house-system " , house_system ,
NULL ) ) ;
g_free ( coords ) ;
2013-09-17 08:00:12 +00:00
gswe_moment_add_all_planets ( GSWE_MOMENT ( chart ) ) ;
2013-09-17 07:31:37 +00:00
return chart ;
2013-09-13 23:25:46 +00:00
}
2013-09-17 20:18:24 +00:00
void
ag_chart_set_name ( AgChart * chart , const gchar * name )
{
if ( chart - > priv - > name ! = NULL ) {
g_free ( chart - > priv - > name ) ;
}
chart - > priv - > name = g_strdup ( name ) ;
}
gchar *
ag_chart_get_name ( AgChart * chart )
{
return g_strdup ( chart - > priv - > name ) ;
}
void
ag_chart_set_country ( AgChart * chart , const gchar * country )
{
if ( chart - > priv - > country ! = NULL ) {
g_free ( chart - > priv - > country ) ;
}
chart - > priv - > country = g_strdup ( country ) ;
}
gchar *
ag_chart_get_country ( AgChart * chart )
{
return g_strdup ( chart - > priv - > country ) ;
}
void
ag_chart_set_city ( AgChart * chart , const gchar * city )
{
if ( chart - > priv - > city ! = NULL ) {
g_free ( chart - > priv - > city ) ;
}
chart - > priv - > city = g_strdup ( city ) ;
}
gchar *
ag_chart_get_city ( AgChart * chart )
{
return g_strdup ( chart - > priv - > city ) ;
}
2013-09-18 08:05:24 +00:00
static GVariant *
get_by_xpath ( xmlXPathContextPtr xpath_context , const gchar * uri , const gchar * xpath , XmlConvertType type , GError * * err )
{
xmlXPathObjectPtr xpathObj ;
const gchar * text ;
char * endptr ;
GVariant * ret = NULL ;
gdouble d ;
gint i ;
if ( ( xpathObj = xmlXPathEvalExpression ( ( const xmlChar * ) xpath , xpath_context ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_LIBXML , " File '%s' could not be parsed due to internal XML error. " , uri ) ;
return NULL ;
}
if ( xpathObj - > nodesetval = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
xmlXPathFreeObject ( xpathObj ) ;
return NULL ;
}
if ( xpathObj - > nodesetval - > nodeNr > 1 ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
xmlXPathFreeObject ( xpathObj ) ;
return NULL ;
}
text = ( const gchar * ) xpathObj - > nodesetval - > nodeTab [ 0 ] - > content ;
switch ( type ) {
case XML_CONVERT_STRING :
ret = g_variant_new_string ( text ) ;
break ;
case XML_CONVERT_DOUBLE :
d = g_ascii_strtod ( text , & endptr ) ;
if ( ( * endptr ! = 0 ) | | ( errno ! = 0 ) ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
ret = NULL ;
} else {
ret = g_variant_new_double ( d ) ;
}
break ;
case XML_CONVERT_INT :
i = strtol ( text , & endptr , 10 ) ;
if ( ( * endptr ! = 0 ) | | ( errno ! = 0 ) ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' doesn't look like a valid saved chart. " , uri ) ;
ret = NULL ;
} else {
ret = g_variant_new_int32 ( i ) ;
}
break ;
}
xmlXPathFreeObject ( xpathObj ) ;
return ret ;
}
AgChart *
ag_chart_load_from_file ( GFile * file , GError * * err )
{
AgChart * chart = NULL ;
gchar * uri ,
* xml = NULL ;
guint length ;
xmlDocPtr doc ;
xmlXPathContextPtr xpath_context ;
GVariant * chart_name ,
* country ,
* city ,
* longitude ,
* latitude ,
* altitude ,
* year ,
* month ,
* day ,
* hour ,
* minute ,
* second ,
* timezone ;
GsweTimestamp * timestamp ;
uri = g_file_get_uri ( file ) ;
if ( ! g_file_load_contents ( file , NULL , & xml , & length , NULL , err ) ) {
g_free ( uri ) ;
return NULL ;
}
if ( ( doc = xmlReadMemory ( xml , length , " chart.xml " , NULL , 0 ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_CORRUPT_FILE , " File '%s' can not be read. Maybe it is corrupt, or not a save file at all " , uri ) ;
g_free ( xml ) ;
g_free ( uri ) ;
return NULL ;
}
if ( ( xpath_context = xmlXPathNewContext ( doc ) ) = = NULL ) {
g_set_error ( err , AG_CHART_ERROR , AG_CHART_ERROR_LIBXML , " File '%s' could not be loaded due to internal LibXML error " , uri ) ;
xmlFreeDoc ( doc ) ;
g_free ( xml ) ;
g_free ( uri ) ;
return NULL ;
}
chart_name = get_by_xpath ( xpath_context , uri , " /chartinfo/data/name/text() " , XML_CONVERT_STRING , err ) ;
country = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/country/text() " , XML_CONVERT_STRING , err ) ;
city = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/city/text() " , XML_CONVERT_STRING , err ) ;
longitude = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/longitude/text() " , XML_CONVERT_DOUBLE , err ) ;
latitude = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/latitude/text() " , XML_CONVERT_DOUBLE , err ) ;
altitude = get_by_xpath ( xpath_context , uri , " /chartinfo/data/place/altitude/text() " , XML_CONVERT_DOUBLE , err ) ;
year = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/year/text() " , XML_CONVERT_INT , err ) ;
month = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/month/text() " , XML_CONVERT_INT , err ) ;
day = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/day/text() " , XML_CONVERT_INT , err ) ;
hour = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/hour/text() " , XML_CONVERT_INT , err ) ;
minute = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/minute/text() " , XML_CONVERT_INT , err ) ;
second = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/second/text() " , XML_CONVERT_INT , err ) ;
timezone = get_by_xpath ( xpath_context , uri , " /chartinfo/data/time/timezone/text() " , XML_CONVERT_DOUBLE , err ) ;
timestamp = gswe_timestamp_new_from_gregorian_full (
g_variant_get_int32 ( year ) ,
g_variant_get_int32 ( month ) ,
g_variant_get_int32 ( day ) ,
g_variant_get_int32 ( hour ) ,
g_variant_get_int32 ( minute ) ,
g_variant_get_int32 ( second ) ,
0 ,
g_variant_get_double ( timezone )
) ;
g_variant_unref ( year ) ;
g_variant_unref ( month ) ;
g_variant_unref ( day ) ;
g_variant_unref ( hour ) ;
g_variant_unref ( minute ) ;
g_variant_unref ( second ) ;
g_variant_unref ( timezone ) ;
// TODO: Make house system configurable (and saveable)
chart = ag_chart_new_full ( timestamp , g_variant_get_double ( longitude ) , g_variant_get_double ( latitude ) , g_variant_get_double ( altitude ) , GSWE_HOUSE_SYSTEM_PLACIDUS ) ;
g_variant_unref ( longitude ) ;
g_variant_unref ( latitude ) ;
g_variant_unref ( altitude ) ;
ag_chart_set_name ( chart , g_variant_get_string ( chart_name , NULL ) ) ;
g_variant_unref ( chart_name ) ;
ag_chart_set_country ( chart , g_variant_get_string ( country , NULL ) ) ;
g_variant_unref ( country ) ;
ag_chart_set_city ( chart , g_variant_get_string ( city , NULL ) ) ;
g_variant_unref ( city ) ;
g_free ( xml ) ;
g_free ( uri ) ;
xmlXPathFreeContext ( xpath_context ) ;
xmlFreeDoc ( doc ) ;
return chart ;
}
2013-09-18 08:06:12 +00:00
void
ag_chart_save_to_file ( AgChart * chart , GFile * file , GError * * err )
{
}