/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.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 <memory.h>
#include <string.h>
#include "kibandata_util.h"
#include "arc_data.h"
#include "attr_data.h"
#include "poly_data.h"

typedef struct {
	char srcPath[512];
	char destPath[512];
}MARGE_KOKUDO_CONTEXT;

int GetMaxArcId(ARC_DATA *arc){
	int ret;
	int i;
	ret = 0;
	for(i=0;i<arc->header.record_count; ++i){
		if(arc->record[i].id > ret)
			ret = arc->record[i].id;
	}
	return ret;
}

int GetMaxPolyId(POLY_DATA *poly){
	int ret;
	int i;
	for(ret=0,i=0; i<poly->header.record_count; ++i){
		if(poly->record[i].id > ret)
			ret = poly->record[i].id;
	}
	return ret;
}

int arc_record_equals(ARC_ID_RECORD *lhs, ARC_ID_RECORD *rhs){
	if(lhs->point_count == rhs->point_count && 
		memcmp(lhs->points, rhs->points, sizeof(GB_POINT) * lhs->point_count)==0){
		return 1;
	}
	return 0;
}

ATTR_RECORD *find_attr_record(ATTR_DATA *attr, int id)
{
	int i;
	for(i=0; i<attr->header.record_count; ++i){
		if(attr->record[i].id == id){
			return &(attr->record[i]);
		}
	}
	return 0;
}

void WriteFileHeader(FILE *fp, KIBAN_FILE_HEADER *header)
{
	fprintf(fp,"FH,%s,%s,%d,%d,%d,%02d,%.1f,%.1f,%.1f,%.1f\n",
		header->name,
		header->file_name,
		0,
		header->record_count+header->new_record_count,
		header->coordinate_flag,
		header->coordinate_no,
		header->r.left,
		header->r.top,
		header->r.right,
		header->r.bottom);
}

void WriteArcRecord(FILE *fp, ARC_ID_RECORD *record){
	int point_count;
	int i;
	fprintf(fp, "%s,%d,%d,%d\n",
		record->code,
		record->kind,
		record->id,
		record->point_count);
	point_count = record->point_count;
	for(i=0; i<point_count; ++i){
		fprintf(fp, "%.1f,%.1f\n", record->points[i].x, record->points[i].y);
	}
}

void WriteArcFile(FILE *fp,  ARC_DATA *arc)
{
	int i;
	WriteFileHeader(fp, &(arc->header));
	for(i=0; i<arc->header.record_count; ++i){
		WriteArcRecord(fp, &(arc->record[i]));
	}
}

void WriteAttrRecord(FILE *fp, ATTR_RECORD *record){
	int i;
	fprintf(fp, "%s,%d,%d", record->code, record->id, record->attr_count);
	for(i=0; i<record->attr_count; ++i){
		fprintf(fp, ",%s", record->pszAttrs[i]);
	}
	fprintf(fp, "\n");
}

void WriteAttrFile(FILE *fp,  ATTR_DATA *attr)
{
	int i;
	WriteFileHeader(fp, &(attr->header));
	for(i=0; i<attr->header.record_count; ++i){
		WriteAttrRecord(fp, &attr->record[i]);
	}
}

void WriteArcRecordsPtrList(FILE *fp, ARC_RECORD_PTR_LIST *list){
	ARC_RECORD_PTR_LIST *l;
	for(l=list; l; l=l->next){
		WriteArcRecord(fp, l->record);
	}
}

void WriteAttrRecordsPtrList(FILE *fp, ATTR_RECORD_PTR_LIST *list){
	int i;
	ATTR_RECORD_PTR_LIST *l;
	for(l=list; l; l=l->next){
		fprintf(fp, "%s,%d,%d", l->record->code, l->new_id, l->record->attr_count);
		for(i=0; i<l->record->attr_count; ++i){
			fprintf(fp, ",%s", l->record->pszAttrs[i]);
		}
		fprintf(fp, "\n");
	}
}

void WritePolyRecord(FILE *fp, POLY_ID_RECORD *record){
int i,id;
	fprintf(fp, "%s,%d,%d,%.1f,%.1f\n", 
		record->code,
		record->id,
		record->count,
		record->point.x,
		record->point.y);
	for(i=0; i<record->count; ++i){
		id = record->arcs[i].arc_id;
		if(record->arcs[i].direction==0){
			id=-id;
		}
		fprintf(fp, "%d\n", id);
	}
}

void WritePolyFile(FILE *fp, POLY_DATA *poly_data){
int i;

	WriteFileHeader(fp, &poly_data->header);
	for(i=0; i<poly_data->header.record_count; ++i){
		WritePolyRecord(fp, &(poly_data->record[i]));
	}
}

void WritePolyRecordsPtrList(FILE *fp, POLY_RECORD_PTR_LIST *records){
	for(;records; records=records->next){
		WritePolyRecord(fp, records->record);
	}
}

ARC_ID_RECORD *GetArcRecord(ARC_DATA *arc_data, int id){
	int i;
	for(i=0; i<arc_data->header.record_count; ++i){
		if(arc_data->record[i].id == id){
			return &(arc_data->record[i]);
		}
	}
	return NULL;
}

ARC_RECORD_PTR_LIST *GetArcRecords(ARC_DATA *arc_data, POLY_ID_RECORD *poly_record)
{
	int i;
	ARC_ID_RECORD *rec;
	ARC_RECORD_PTR_LIST *ret;
	ARC_RECORD_PTR_LIST *l;
	ret = NULL;
	for(i=poly_record->count-1; i>=0; --i){
		rec = GetArcRecord(arc_data, poly_record->arcs[i].arc_id);
		if(rec){
			l = (ARC_RECORD_PTR_LIST*)calloc(1, sizeof(*ret));
			l->record = rec;
			l->next = ret;
			ret = l;
		}
	}
	return ret;
}

int arc_records_equals(ARC_RECORD_PTR_LIST *lhs, ARC_RECORD_PTR_LIST *rhs){
	while(lhs&&rhs){
		if( !arc_record_equals(lhs->record, rhs->record) ){
			return 0;
		}
		lhs = lhs->next;
		rhs = rhs->next;
	}
	if(lhs)
		return 0;
	if(rhs)
		return 0;
	return 1;
}

		

void MargePoly(char *src_arc_file,
				char *src_poly_file,
				char *src_attr_file, 
				char *dest_arc_file,
				char *dest_poly_file,
				char *dest_attr_file){
	FILE * fp;
	ARC_DATA *dest_arc;
	ARC_DATA *src_arc;
	ATTR_DATA *dest_attr;
	ATTR_DATA *src_attr;
	POLY_DATA *dest_poly;
	POLY_DATA *src_poly;

	int new_poly_id;
	int new_arc_id;

	int i,j;
	int code;
	ARC_RECORD_PTR_LIST *src_arc_records;
	ARC_RECORD_PTR_LIST *new_arc_records;
	ATTR_RECORD_PTR_LIST *new_attr_records;
	ATTR_RECORD_PTR_LIST *new_attr_record;
	POLY_RECORD_PTR_LIST *new_poly_records;
	POLY_RECORD_PTR_LIST *new_poly_record;
	
	int new_arc_record_count;
	int new_attr_record_count;
	int new_poly_record_count;
	
	ATTR_RECORD *tmp_attr_record;
	
	dest_arc = NULL;
	src_arc = NULL;
	dest_attr = NULL;
	src_attr = NULL;
	dest_poly = NULL;
	src_poly = NULL;
	
	/* if there is some error in dest file, overwrite that by new file*/
	code = ReadKibanFile(dest_arc_file, ID_ARC, (void**)&dest_arc, 0);
	if(code == ID_ERR_NOERROR)
		code = ReadKibanFile(dest_poly_file, ID_POLYGON, (void**)&dest_poly, 0);
	if(code == ID_ERR_NOERROR)
		code = ReadKibanFile(dest_attr_file, ID_ATTER, (void**)&dest_attr, 0);
	
	if(code != ID_ERR_NOERROR){
		FileCopy(src_arc_file, dest_arc_file);
		FileCopy(src_poly_file, dest_poly_file);
		FileCopy(src_attr_file, dest_attr_file);
		goto exit;
	}
	
	code = ReadKibanFile(src_arc_file, ID_ARC, (void**)&src_arc, 0);
	if(code == ID_ERR_NOERROR)
		code = ReadKibanFile(src_poly_file, ID_POLYGON, (void**)&src_poly, 0);
	if(code == ID_ERR_NOERROR)
		code = ReadKibanFile(src_attr_file, ID_ATTER, (void**)&src_attr, 0);
	
	new_arc_records = NULL;
	new_arc_record_count = 0;
	new_attr_records = NULL;
	new_attr_record_count = 0;
	new_poly_records = NULL;
	new_poly_record_count = 0;
	
	if(code == ID_ERR_NOERROR){
		new_arc_id = GetMaxArcId(dest_arc) + 1;
		new_poly_id = GetMaxPolyId(dest_poly) + 1;
		for(i=0; i<src_poly->header.record_count; ++i){
			src_arc_records = GetArcRecords(src_arc, &(src_poly->record[i]));
			for(j=0; j<dest_poly->header.record_count; ++j){
				if(src_poly->record[i].count == dest_poly->record[j].count){
					ARC_RECORD_PTR_LIST *dest_arc_records;
					dest_arc_records = GetArcRecords(dest_arc, &(dest_poly->record[j]));
					if(arc_records_equals(src_arc_records, dest_arc_records)){
						goto skip;
					}
					free_arc_record_ptr_list(dest_arc_records);
				}
			}
			
			new_poly_record = (POLY_RECORD_PTR_LIST*)calloc(1,sizeof(POLY_RECORD_PTR_LIST));
			new_poly_record->record = &(src_poly->record[i]);
			
			tmp_attr_record = find_attr_record(src_attr, new_poly_record->record->id);
			if(tmp_attr_record){
				new_attr_record = (ATTR_RECORD_PTR_LIST*)calloc(1,sizeof(ATTR_RECORD_PTR_LIST));
				new_attr_record->record = tmp_attr_record;
				new_attr_record->new_id = new_poly_id;
				new_attr_record->next = new_attr_records;
				new_attr_records = new_attr_record;
				++new_attr_record_count;
			}

			{
				ARC_RECORD_PTR_LIST *p;
				int k;
				for(k=0,p=src_arc_records; p->next; p=p->next, ++k){
					p->record->id = new_arc_id;
					new_poly_record->record->arcs[k].arc_id = new_arc_id;
					++new_arc_record_count;
					++new_arc_id;
				}
				p->record->id = new_arc_id;
				new_poly_record->record->arcs[k].arc_id = new_arc_id;
				++new_arc_record_count;
				++new_arc_id;
				p->next = new_arc_records;
				new_arc_records = src_arc_records;
			}
			
			new_poly_record->record->id = new_poly_id;
			new_poly_record->next = new_poly_records;
			new_poly_records = new_poly_record;
			++new_poly_record_count;
			++new_poly_id;
			
skip:;
		}

		dest_arc->header.new_record_count = new_arc_record_count;
		fp = fopen(dest_arc_file, "w");
		WriteArcFile(fp, dest_arc);
		WriteArcRecordsPtrList(fp, new_arc_records);
		fclose(fp);
		dest_attr->header.new_record_count = new_attr_record_count;
		fp = fopen(dest_attr_file, "w");
		WriteAttrFile(fp, dest_attr);
		WriteAttrRecordsPtrList(fp, new_attr_records);
		fclose(fp);
		
		dest_poly->header.new_record_count = new_poly_record_count;
		fp = fopen(dest_poly_file, "w");
		WritePolyFile(fp, dest_poly);
		WritePolyRecordsPtrList(fp, new_poly_records);
		fclose(fp);
		
		free_arc_record_ptr_list(new_arc_records);
		free_attr_record_ptr_list(new_attr_records);
		free_poly_record_ptr_list(new_poly_records);
	}
	
exit:
	free_arc_data(dest_arc);
	free_arc_data(src_arc);
	free_attr_data(dest_attr);
	free_attr_data(src_attr);
}

void MargeArc(char *src_arc_file, 
			  char *src_attr_file, 
			  char *dest_arc_file, 
			  char *dest_attr_file){
	FILE * fp;
	ARC_DATA *dest_arc;
	ARC_DATA *src_arc;
	ATTR_DATA *dest_attr;
	ATTR_DATA *src_attr;
	int new_id;
	int i,j;
	int code;
	ARC_RECORD_PTR_LIST *new_arc_records;
	ARC_RECORD_PTR_LIST *new_arc_record;
	int new_arc_record_count;
	int new_attr_record_count;
	ATTR_RECORD_PTR_LIST *new_attr_records;
	ATTR_RECORD_PTR_LIST *new_attr_record;
	ATTR_RECORD *tmp_attr_record;
	
	dest_arc = NULL;
	src_arc = NULL;
	dest_attr = NULL;
	src_attr = NULL;
	
	/* if there is some error in dest file, overwrite that by new file*/
	code = ReadKibanFile(dest_arc_file, ID_ARC, (void**)&dest_arc, 0);
	if(code == ID_ERR_NOERROR)
		code = ReadKibanFile(dest_attr_file, ID_ATTER, (void**)&dest_attr, 0);
	if(code != ID_ERR_NOERROR){
		FileCopy(src_arc_file, dest_arc_file);
		FileCopy(src_attr_file, dest_attr_file);
		goto exit;
	}
	
	code = ReadKibanFile(src_arc_file, ID_ARC, (void**)&src_arc, 0);
	if(code == ID_ERR_NOERROR)
		code = ReadKibanFile(src_attr_file, ID_ATTER, (void**)&src_attr, 0);
	
	new_arc_records = 0;
	new_arc_record_count = 0;
	new_attr_record_count = 0;
	new_attr_records = 0;
	
	if(code == ID_ERR_NOERROR){
		new_id = GetMaxArcId(dest_arc) + 1;
		for(i=0; i<src_arc->header.record_count; ++i){
			for(j=0; j<dest_arc->header.record_count; ++j){
				if(arc_record_equals(
					&(src_arc->record[i]),
					&(dest_arc->record[j]))){
					goto skip;
				}
			}
			
			new_arc_record = (ARC_RECORD_PTR_LIST*)calloc(1,sizeof(ARC_RECORD_PTR_LIST));
			new_arc_record->record = &(src_arc->record[i]);
			
			tmp_attr_record = find_attr_record(src_attr, new_arc_record->record->id);
			if(tmp_attr_record){
				new_attr_record = (ATTR_RECORD_PTR_LIST*)calloc(1,sizeof(ATTR_RECORD_PTR_LIST));
				new_attr_record->record = tmp_attr_record;
				new_attr_record->new_id = new_id;
				new_attr_record->next = new_attr_records;
				new_attr_records = new_attr_record;
				++new_attr_record_count;
			}
			new_arc_record->record->id = new_id;
			new_arc_record->next = new_arc_records;
			new_arc_records = new_arc_record;
			++new_arc_record_count;
			++new_id;

skip:;
		}
		dest_arc->header.new_record_count = new_arc_record_count;
		fp = fopen(dest_arc_file, "w");
		WriteArcFile(fp, dest_arc);
		WriteArcRecordsPtrList(fp, new_arc_records);
		fclose(fp);
		dest_attr->header.new_record_count = new_attr_record_count;
		fp = fopen(dest_attr_file, "w");
		WriteAttrFile(fp, dest_attr);
		WriteAttrRecordsPtrList(fp, new_attr_records);
		fclose(fp);
		
		free_arc_record_ptr_list(new_arc_records);
		free_attr_record_ptr_list(new_attr_records);
	}
	
exit:
	free_arc_data(dest_arc);
	free_arc_data(src_arc);
	free_attr_data(dest_attr);
	free_attr_data(src_attr);
}


void MargeZuyou(char *src, char *dest, char *zuyou_name){
	char sub_dir[MAX_PATH];
	char src_arc_file[MAX_PATH];
	char src_poly_file[MAX_PATH];
	char src_atr_file[MAX_PATH];
	char dest_arc_file[MAX_PATH];
	char dest_poly_file[MAX_PATH];
	char dest_atr_file[MAX_PATH];
	char tmp1[MAX_PATH],tmp2[MAX_PATH];

	MakeDirectory(dest);
	
	sprintf(tmp1, "%s/%s.txt", src, zuyou_name);
	sprintf(tmp2, "%s/%s.txt", dest, zuyou_name);
	FileCopy(tmp1, tmp2);
	
	/* road */
	sprintf(src_arc_file, "%s/road/roadntwk.arc", src);
	sprintf(src_atr_file, "%s/road/road.atr", src);
	sprintf(dest_arc_file, "%s/road/roadntwk.arc", dest);
	sprintf(dest_atr_file, "%s/road/road.atr", dest);
	sprintf(sub_dir, "%s/road", dest);
	MakeDirectory(sub_dir);
	MargeArc(src_arc_file, src_atr_file, dest_arc_file, dest_atr_file);
	
	/* kokudou */
	sprintf(src_arc_file, "%s/kokudou/kokudou.arc", src);
	sprintf(src_atr_file, "%s/kokudou/kokudou.atr", src);
	sprintf(dest_arc_file, "%s/kokudou/kokudou.arc", dest);
	sprintf(dest_atr_file, "%s/kokudou/kokudou.atr", dest);
	sprintf(sub_dir, "%s/kokudou", dest);
	MakeDirectory(sub_dir);
	MargeArc(src_arc_file, src_atr_file, dest_arc_file, dest_atr_file);
	
	/* tetudou */
	sprintf(src_arc_file, "%s/others/others.arc", src);
	sprintf(src_atr_file, "%s/others/tetudou.atr", src);
	sprintf(dest_arc_file, "%s/others/others.arc", dest);
	sprintf(dest_atr_file, "%s/others/tetudou.atr", dest);
	sprintf(sub_dir, "%s/others", dest);
	MakeDirectory(sub_dir);
	MargeArc(src_arc_file, src_atr_file, dest_arc_file, dest_atr_file);
	
	/* si_tyo */
	sprintf(src_arc_file, "%s/gyousei/gyousei.arc", src);
	sprintf(src_poly_file, "%s/gyousei/si_tyo.pgn", src);
	sprintf(src_atr_file, "%s/gyousei/si_tyo.atr", src);
	sprintf(dest_arc_file, "%s/gyousei/gyousei.arc", dest);
	sprintf(dest_poly_file, "%s/gyousei/si_tyo.pgn", dest);
	sprintf(dest_atr_file, "%s/gyousei/si_tyo.atr", dest);
	sprintf(sub_dir, "%s/gyousei", dest);
	MakeDirectory(sub_dir);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
	/* tyome */
	sprintf(src_arc_file, "%s/gyousei/gyousei.arc", src);
	sprintf(src_poly_file, "%s/gyousei/tyome.pgn", src);
	sprintf(src_atr_file, "%s/gyousei/tyome.atr", src);
	sprintf(dest_arc_file, "%s/gyousei/gyousei.arc", dest);
	sprintf(dest_poly_file, "%s/gyousei/tyome.pgn", dest);
	sprintf(dest_atr_file, "%s/gyousei/tyome.atr", dest);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
	/* gaiku */
	sprintf(src_arc_file, "%s/gaiku/gaiku.arc", src);
	sprintf(src_poly_file, "%s/gaiku/gaiku.pgn", src);
	sprintf(src_atr_file, "%s/gaiku/gaiku.atr", src);
	sprintf(dest_arc_file, "%s/gaiku/gaiku.arc", dest);
	sprintf(dest_poly_file, "%s/gaiku/gaiku.pgn", dest);
	sprintf(dest_atr_file, "%s/gaiku/gaiku.atr", dest);
	sprintf(sub_dir, "%s/gaiku", dest);
	MakeDirectory(sub_dir);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
	/* kasen */
	sprintf(src_arc_file, "%s/kasen/kasen.arc", src);
	sprintf(src_poly_file, "%s/kasen/kasen.pgn", src);
	sprintf(src_atr_file, "%s/kasen/kasen.atr", src);
	sprintf(dest_arc_file, "%s/kasen/kasen.arc", dest);
	sprintf(dest_poly_file, "%s/kasen/kasen.pgn", dest);
	sprintf(dest_atr_file, "%s/kasen/kasen.atr", dest);
	sprintf(sub_dir, "%s/kasen", dest);
	MakeDirectory(sub_dir);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
	/* zyouti */
	sprintf(src_arc_file, "%s/others/others.arc", src);
	sprintf(src_poly_file, "%s/others/zyouti.pgn", src);
	sprintf(src_atr_file, "%s/others/zyouti.atr", src);
	sprintf(dest_arc_file, "%s/others/others.arc", dest);
	sprintf(dest_poly_file, "%s/others/zyouti.pgn", dest);
	sprintf(dest_atr_file, "%s/others/zyouti.atr", dest);
	sprintf(sub_dir, "%s/others", dest);
	MakeDirectory(sub_dir);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
	/* mizu */
	sprintf(src_arc_file, "%s/mizu/mizu.arc", src);
	sprintf(src_poly_file, "%s/mizu/mizu.pgn", src);
	sprintf(src_atr_file, "%s/mizu/mizu.atr", src);
	sprintf(dest_arc_file, "%s/mizu/mizu.arc", dest);
	sprintf(dest_poly_file, "%s/mizu/mizu.pgn", dest);
	sprintf(dest_atr_file, "%s/mizu/mizu.atr", dest);
	sprintf(sub_dir, "%s/mizu", dest);
	MakeDirectory(sub_dir);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
	/* tatemono */
	sprintf(src_arc_file, "%s/tatemono/tatemono.arc", src);
	sprintf(src_poly_file, "%s/tatemono/tatemono.pgn", src);
	sprintf(src_atr_file, "%s/tatemono/tatemono.atr", src);
	sprintf(dest_arc_file, "%s/tatemono/tatemono.arc", dest);
	sprintf(dest_poly_file, "%s/tatemono/tatemono.pgn", dest);
	sprintf(dest_atr_file, "%s/tatemono/tatemono.atr", dest);
	sprintf(sub_dir, "%s/tatemono", dest);
	MakeDirectory(sub_dir);
	MargePoly(
			src_arc_file, src_poly_file, src_atr_file, 
			dest_arc_file, dest_poly_file, dest_atr_file);
	
}

void EachZuyouFunc(char *dirname, int param){
	char destZuyouPath[MAX_PATH];
	char srcZuyouPath[MAX_PATH];
	MARGE_KOKUDO_CONTEXT *ctx;
	ctx = (MARGE_KOKUDO_CONTEXT *)param;
	
	sprintf(srcZuyouPath, "%s%s", ctx->srcPath, dirname);
	sprintf(destZuyouPath, "%s%s", ctx->destPath, dirname);
	MargeZuyou(srcZuyouPath, destZuyouPath, dirname);
}

int main(int argc, char* argv[])
{
	MARGE_KOKUDO_CONTEXT ctx;
	memset(&ctx, 0, sizeof(ctx));
	
	if(argc < 3){
		printf("usage: marge_kokud_cd cdrom_path marge_target_path\n");
		printf("ex: marge_kokud_cd /mnt/cdrom/ output/06/\n");
		return 0;
	}
	ToFullPath(ctx.srcPath, argv[1]);
	ToFullPath(ctx.destPath, argv[2]);

/*
	strcpy(ctx.srcPath, "C:\\MyDocuments\\gbs\\Kiban2SVG\\cdrom\\");
	strcpy(ctx.destPath, "C:\\MyDocuments\\gbs\\Kiban2SVG\\marge_kokudo\\06\\");
*/	
	EnumDirNames(ctx.srcPath, EachZuyouFunc, (int)&ctx);
	
	return 0;
}
