#include <string.h>
#include "debug.h"
#include "projection.h"
+#include "item.h"
#include "map.h"
#include "mapset.h"
#include "coord.h"
-#include "item.h"
#include "search.h"
struct search_list_level {
struct mapset *ms;
- struct item *parent;
- struct attr attr;
+ struct search_list_common *parent;
+ struct attr *attr;
int partial;
int selected;
struct mapset_search *search;
int level;
struct search_list_level levels[4];
struct search_list_result result;
+ struct search_list_result last_result;
+ int last_result_valid;
};
static guint
search_item_hash_hash(gconstpointer key)
{
const struct item *itm=key;
- gconstpointer hashkey=(gconstpointer)(itm->id_hi^itm->id_lo);
+ gconstpointer hashkey=(gconstpointer)GINT_TO_POINTER(itm->id_hi^itm->id_lo);
return g_direct_hash(hashkey);
}
case attr_town_postal:
return 1;
case attr_town_name:
+ case attr_district_name:
+ case attr_town_or_district_name:
return 1;
case attr_street_name:
return 2;
+ case attr_house_number:
+ return 3;
default:
+ dbg(0,"unknown search '%s'\n",attr_to_name(attr_type));
return -1;
}
}
{
struct search_list_level *le;
int level=search_list_level(search_attr->type);
- dbg(0,"level=%d\n", level);
+ dbg(1,"level=%d\n", level);
if (level != -1) {
this_->result.id=0;
this_->level=level;
le=&this_->levels[level];
- le->attr=*search_attr;
- if (search_attr->type != attr_country_id)
- le->attr.u.str=g_strdup(search_attr->u.str);
search_list_search_free(this_, level);
+ le->attr=attr_dup(search_attr);
le->partial=partial;
if (level > 0) {
le=&this_->levels[level-1];
}
}
-int
+struct search_list_common *
search_list_select(struct search_list *this_, enum attr_type attr_type, int id, int mode)
{
int level=search_list_level(attr_type);
GList *curr;
le=&this_->levels[level];
curr=le->list;
- if (mode > 0)
+ if (mode > 0 || !id)
le->selected=mode;
- dbg(0,"enter %d %d\n", id, mode);
+ dbg(1,"enter level=%d %d %d %p\n", level, id, mode, curr);
while (curr) {
num++;
if (! id || num == id) {
slc=curr->data;
slc->selected=mode;
if (id) {
+ le->last=curr;
dbg(0,"found\n");
- return 1;
+ return slc;
}
}
curr=g_list_next(curr);
}
- dbg(0,"not found\n");
- return 0;
+ dbg(1,"not found\n");
+ return NULL;
+}
+
+static void
+search_list_common_new(struct item *item, struct search_list_common *common)
+{
+ struct attr attr;
+ if (item_attr_get(item, attr_town_name, &attr))
+ common->town_name=map_convert_string(item->map, attr.u.str);
+ else
+ common->town_name=NULL;
+ if (item_attr_get(item, attr_district_name, &attr))
+ common->district_name=map_convert_string(item->map, attr.u.str);
+ else
+ common->district_name=NULL;
+ if (item_attr_get(item, attr_postal, &attr))
+ common->postal=map_convert_string(item->map, attr.u.str);
+ else if (item_attr_get(item, attr_town_postal, &attr))
+ common->postal=map_convert_string(item->map, attr.u.str);
+ else
+ common->postal=NULL;
+ if (item_attr_get(item, attr_postal_mask, &attr))
+ common->postal_mask=map_convert_string(item->map, attr.u.str);
+ else
+ common->postal_mask=NULL;
+}
+
+static void
+search_list_common_destroy(struct search_list_common *common)
+{
+ map_convert_free(common->town_name);
+ map_convert_free(common->district_name);
+ map_convert_free(common->postal);
+ map_convert_free(common->postal_mask);
}
static struct search_list_country *
struct search_list_country *ret=g_new0(struct search_list_country, 1);
struct attr attr;
- ret->item=*item;
+ ret->common.item=ret->common.unique=*item;
if (item_attr_get(item, attr_country_car, &attr))
ret->car=g_strdup(attr.u.str);
if (item_attr_get(item, attr_country_iso2, &attr)) {
struct coord c;
ret->itemt=*item;
+ ret->common.item=ret->common.unique=*item;
if (item_attr_get(item, attr_town_streets_item, &attr)) {
dbg(1,"town_assoc 0x%x 0x%x\n", attr.u.item->id_hi, attr.u.item->id_lo);
- ret->item=*attr.u.item;
+ ret->common.unique=*attr.u.item;
}
+ search_list_common_new(item, &ret->common);
+ if (item_attr_get(item, attr_county_name, &attr))
+ ret->county=map_convert_string(item->map,attr.u.str);
else
- ret->item=*item;
- if (item_attr_get(item, attr_town_name, &attr))
- ret->name=map_convert_string(item->map,attr.u.str);
- if (item_attr_get(item, attr_town_postal, &attr))
- ret->postal=map_convert_string(item->map,attr.u.str);
- if (item_attr_get(item, attr_district_name, &attr))
- ret->district=map_convert_string(item->map,attr.u.str);
+ ret->county=NULL;
if (item_coord_get(item, &c, 1)) {
- ret->c=g_new(struct pcoord, 1);
- ret->c->x=c.x;
- ret->c->y=c.y;
- ret->c->pro = map_projection(item->map);
+ ret->common.c=g_new(struct pcoord, 1);
+ ret->common.c->x=c.x;
+ ret->common.c->y=c.y;
+ ret->common.c->pro = map_projection(item->map);
}
return ret;
}
static void
search_list_town_destroy(struct search_list_town *this_)
{
- map_convert_free(this_->name);
- map_convert_free(this_->postal);
- if (this_->c)
- g_free(this_->c);
+ map_convert_free(this_->county);
+ search_list_common_destroy(&this_->common);
+ if (this_->common.c)
+ g_free(this_->common.c);
g_free(this_);
}
+
static struct search_list_street *
search_list_street_new(struct item *item)
{
struct attr attr;
struct coord c;
- ret->item=*item;
+ ret->common.item=ret->common.unique=*item;
if (item_attr_get(item, attr_street_name, &attr))
ret->name=map_convert_string(item->map, attr.u.str);
+ else
+ ret->name=NULL;
+ search_list_common_new(item, &ret->common);
if (item_coord_get(item, &c, 1)) {
- ret->c=g_new(struct pcoord, 1);
- ret->c->x=c.x;
- ret->c->y=c.y;
- ret->c->pro = map_projection(item->map);
+ ret->common.c=g_new(struct pcoord, 1);
+ ret->common.c->x=c.x;
+ ret->common.c->y=c.y;
+ ret->common.c->pro = map_projection(item->map);
}
return ret;
}
+
static void
search_list_street_destroy(struct search_list_street *this_)
{
map_convert_free(this_->name);
- if (this_->c)
- g_free(this_->c);
+ search_list_common_destroy(&this_->common);
+ if (this_->common.c)
+ g_free(this_->common.c);
g_free(this_);
}
+static struct search_list_house_number *
+search_list_house_number_new(struct item *item)
+{
+ struct search_list_house_number *ret=g_new0(struct search_list_house_number, 1);
+ struct attr attr;
+ struct coord c;
+
+ ret->common.item=ret->common.unique=*item;
+ if (item_attr_get(item, attr_house_number, &attr))
+ ret->house_number=map_convert_string(item->map, attr.u.str);
+ search_list_common_new(item, &ret->common);
+ if (item_coord_get(item, &c, 1)) {
+ ret->common.c=g_new(struct pcoord, 1);
+ ret->common.c->x=c.x;
+ ret->common.c->y=c.y;
+ ret->common.c->pro = map_projection(item->map);
+ }
+ return ret;
+}
+
+static void
+search_list_house_number_destroy(struct search_list_house_number *this_)
+{
+ map_convert_free(this_->house_number);
+ search_list_common_destroy(&this_->common);
+ if (this_->common.c)
+ g_free(this_->common.c);
+ g_free(this_);
+}
static void
search_list_result_destroy(int level, void *p)
case 2:
search_list_street_destroy(p);
break;
+ case 3:
+ search_list_house_number_destroy(p);
+ break;
}
}
next=g_list_next(curr);
curr=next;
}
+ attr_free(le->attr);
g_list_free(le->list);
le->list=NULL;
le->curr=NULL;
}
+static char *
+postal_merge(char *mask, char *new)
+{
+ dbg(1,"enter %s %s\n", mask, new);
+ int i;
+ char *ret=NULL;
+ if (!new)
+ return NULL;
+ if (!mask)
+ return g_strdup(new);
+ i=0;
+ while (mask[i] && new[i]) {
+ if (mask[i] != '.' && mask[i] != new[i])
+ break;
+ i++;
+
+ }
+ if (mask[i]) {
+ ret=g_strdup(mask);
+ while (mask[i])
+ ret[i++]='.';
+ }
+ dbg(1,"merged %s with %s as %s\n", mask, new, ret);
+ return ret;
+}
+
static int
-search_add_result(struct search_list_level *le, void *p)
+search_add_result(struct search_list_level *le, struct search_list_common *slc)
{
- if (! g_hash_table_lookup(le->hash, p)) {
- g_hash_table_insert(le->hash, p, (void *)1);
- le->list=g_list_append(le->list, p);
+ struct search_list_common *slo;
+ char *merged;
+ slo=g_hash_table_lookup(le->hash, &slc->unique);
+ if (!slo) {
+ g_hash_table_insert(le->hash, &slc->unique, slc);
+ if (slc->postal && !slc->postal_mask) {
+ slc->postal_mask=g_strdup(slc->postal);
+ }
+ le->list=g_list_append(le->list, slc);
return 1;
}
+ merged=postal_merge(slo->postal_mask, slc->postal);
+ if (merged) {
+ g_free(slo->postal_mask);
+ slo->postal_mask=merged;
+ }
return 0;
}
}
}
if (le->parent)
- dbg(1,"mapset_search_new with item(%d,%d)\n", le->parent->id_hi, le->parent->id_lo);
- dbg(1,"attr=%s\n", attr_to_name(le->attr.type));
- le->search=mapset_search_new(this_->ms, le->parent, &le->attr, le->partial);
+ dbg(1,"mapset_search_new with item(%d,%d)\n", le->parent->item.id_hi, le->parent->item.id_lo);
+ dbg(1,"attr=%s\n", attr_to_name(le->attr->type));
+ le->search=mapset_search_new(this_->ms, &le->parent->item, le->attr, le->partial);
le->hash=g_hash_table_new(search_item_hash_hash, search_item_hash_equal);
}
dbg(1,"le->search=%p\n", le->search);
case 0:
p=search_list_country_new(item);
this_->result.country=p;
+ this_->result.country->common.parent=NULL;
break;
case 1:
p=search_list_town_new(item);
- this_->result.country=this_->levels[0].last->data;
this_->result.town=p;
- this_->result.c=this_->result.town->c;
+ this_->result.town->common.parent=this_->levels[0].last->data;
+ this_->result.country=this_->result.town->common.parent;
+ this_->result.c=this_->result.town->common.c;
break;
case 2:
p=search_list_street_new(item);
- this_->result.country=this_->levels[0].last->data;
- this_->result.town=this_->levels[1].last->data;
this_->result.street=p;
- this_->result.c=this_->result.street->c;
+ this_->result.street->common.parent=this_->levels[1].last->data;
+ this_->result.town=this_->result.street->common.parent;
+ this_->result.country=this_->result.town->common.parent;
+ this_->result.c=this_->result.street->common.c;
break;
+ case 3:
+ p=search_list_house_number_new(item);
+ this_->result.house_number=p;
+ this_->result.house_number->common.parent=this_->levels[2].last->data;
+ this_->result.street=this_->result.house_number->common.parent;
+ this_->result.town=this_->result.street->common.parent;
+ this_->result.country=this_->result.town->common.parent;
+ this_->result.c=this_->result.house_number->common.c;
+
}
if (p) {
if (search_add_result(le, p)) {
search_init(void)
{
}
+
+#if 0
+static char *
+search_fix_spaces(char *str)
+{
+ int i;
+ int len=strlen(str);
+ char c,*s,*d,*ret=g_strdup(str);
+
+ for (i = 0 ; i < len ; i++) {
+ if (ret[i] == ',' || ret[i] == ',' || ret[i] == '/')
+ ret[i]=' ';
+ }
+ s=ret;
+ d=ret;
+ len=0;
+ do {
+ c=*s++;
+ if (c != ' ' || len != 0) {
+ *d++=c;
+ len++;
+ }
+ while (c == ' ' && *s == ' ')
+ s++;
+ if (c == ' ' && *s == '\0') {
+ d--;
+ len--;
+ }
+ } while (c);
+ return ret;
+}
+
+static GList *
+search_split_phrases(char *str)
+{
+ char *tmp,*s,*d;
+ s=str;
+ GList *ret=NULL;
+ do {
+ tmp=g_strdup(s);
+ d=tmp+strlen(s)-1;
+ ret=g_list_append(ret, g_strdup(s));
+ while (d >= tmp) {
+ if (*d == ' ') {
+ *d = '\0';
+ ret=g_list_append(ret, g_strdup(tmp));
+ }
+ d--;
+ }
+ g_free(tmp);
+ do {
+ s++;
+ if (*s == ' ') {
+ s++;
+ break;
+ }
+ } while (*s != '\0');
+ } while (*s != '\0');
+ return ret;
+}
+
+static void
+search_address_housenumber(struct search_list *sl, GList *phrases, GList *exclude1, GList *exclude2, GList *exclude3)
+{
+ struct search_list_result *slr;
+ GList *tmp=phrases;
+ int count=0;
+ struct attr attr;
+ attr.type=attr_street_name;
+ while (slr=search_list_get_result(sl)) {
+ dbg(0,"%p\n",slr);
+ dbg(0,"%p %p\n",slr->country,slr->town);
+ dbg(0,"%s %s %s %s %s\n",slr->country->car,slr->town->common.postal,slr->town->name,slr->town->district,slr->street->name);
+ count++;
+ }
+ if (!count)
+ return;
+ dbg(0,"count %d\n",count);
+ while (tmp) {
+ if (tmp != exclude1 && tmp != exclude2 && tmp != exclude3) {
+ attr.type=attr_house_number;
+ attr.u.str=tmp->data;
+ search_list_search(sl, &attr, 0);
+ while (slr=search_list_get_result(sl)) {
+ dbg(0,"result %s %s(%s) %s %s\n",slr->house_number->common.postal,slr->house_number->common.town_name, slr->house_number->common.district_name,slr->street->name,slr->house_number->house_number);
+ }
+
+ }
+ tmp=g_list_next(tmp);
+ }
+}
+static void
+search_address_street(struct search_list *sl, GList *phrases, GList *exclude1, GList *exclude2)
+{
+ struct search_list_result *slr;
+ GList *tmp=phrases;
+ int count=0;
+ struct attr attr;
+ attr.type=attr_street_name;
+ while (slr=search_list_get_result(sl)) {
+#if 0
+ dbg(0,"%s %s %s %s",slr->country->car,slr->town->name,slr->town->district,slr->street->name);
+#endif
+ dbg(0,"%s %s %s %s\n",slr->country->car,slr->town->common.postal,slr->town->name,slr->town->district);
+ count++;
+ }
+ if (!count)
+ return;
+ dbg(0,"count %d\n",count);
+ while (tmp) {
+ if (tmp != exclude1 && tmp != exclude2) {
+ attr.u.str=tmp->data;
+ search_list_search(sl, &attr, 0);
+ search_address_housenumber(sl, phrases, exclude1, exclude2, tmp);
+ }
+ tmp=g_list_next(tmp);
+ }
+}
+
+static void
+search_address_town(struct search_list *sl, GList *phrases, GList *exclude)
+{
+ GList *tmp=phrases;
+ int count=0;
+ struct attr attr;
+ attr.type=attr_town_or_district_name;
+ while (search_list_get_result(sl))
+ count++;
+ if (!count)
+ return;
+ dbg(0,"count %d\n",count);
+ while (tmp) {
+ if (tmp != exclude) {
+ attr.u.str=tmp->data;
+ search_list_search(sl, &attr, 0);
+ search_address_street(sl, phrases, exclude, tmp);
+ }
+ tmp=g_list_next(tmp);
+ }
+}
+
+void
+search_by_address(struct mapset *ms, char *addr)
+{
+ char *str=search_fix_spaces(addr);
+ GList *tmp,*phrases=search_split_phrases(str);
+ dbg(0,"enter %s\n",addr);
+ struct search_list *sl;
+ struct search_list_result *slr;
+ struct attr attr;
+ attr.type=attr_country_all;
+ tmp=phrases;
+ sl=search_list_new(ms);
+ while (tmp) {
+ attr.u.str=tmp->data;
+ search_list_search(sl, &attr, 0);
+ search_address_town(sl, phrases, tmp);
+ tmp=g_list_next(tmp);
+ }
+ search_list_search(sl, country_default(), 0);
+ search_address_town(sl, phrases, NULL);
+
+ g_free(str);
+}
+#endif
+