/**********************************************************************
 
	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 "poly_data.h"
#include <string.h>

/* ポリゴンファイルから読み込み */
int ReadPoly(const char *filename, FILE *fp, POLY_DATA *pData, int Flags){
	char szBuff[256];
	KIBAN_FILE_HEADER *pHeader=&(pData->header);
	POLY_ID_RECORD *pRecord;
	int nReturn;
	int i;
	
	/* ヘッダの切り出し */
	char seps[] = " ,\t\n";
	char *token;

	/* ヘッダ読み込み */
	if(!(nReturn = ReadKibanFileHeader(fp, pHeader))==ID_ERR_NOERROR){
		printf("::header error at %s\n", filename);
		return nReturn;
	}
	
	/* ポリゴンＩＤレコード読み込み */
	pData->record = (POLY_ID_RECORD *)malloc(pHeader->record_count*sizeof(POLY_ID_RECORD));
	memset(pData->record,'\0',pHeader->record_count*sizeof(POLY_ID_RECORD));
	pRecord = pData->record ;
	for(i=0;i<pHeader->record_count;){
		ARC_REF *arc;
		int j;
		if(!fgets(szBuff,sizeof(szBuff),fp)){
			pHeader->record_count=i;
			printf("record count error at %s\n", pData->header.file_name);
			return ID_ERR_NOERROR;
		/*			return ID_ERR_FILE_FORMAT;*/
		}
		chop(szBuff);
		
		/* 書式分類レコード ：L2110 */
		token = strtok( szBuff, seps );
		if(token==NULL){
			printf("::record format error at %s\n", pData->header.file_name);
			continue;
		}
		strcpy(pRecord->code,token);
		
		/* 個別番号：9 */
		token = strtok( NULL, seps );
		if(token==NULL){
			printf("::record format error at %s\n", pData->header.file_name);
			continue;
		}
		pRecord->id = atoi(token);
		
		/* 座標レコード数：24 */
		token = strtok( NULL, seps );
		if(token==NULL){
			printf("::record format error at %s\n", pData->header.file_name);
			continue;
		}
		pRecord->count = atoi(token);
		pRecord->arcs = (ARC_REF*)malloc(pRecord->count * sizeof(ARC_REF));
		
		/* 各座標情報の読み込み */
		arc=pRecord->arcs;
		for(j=0;j<pRecord->count;++j){
			int id;
			if(!fgets(szBuff,sizeof(szBuff),fp)){
				pRecord->count = j;
				printf("point count error at %s\n", pData->header.file_name);
				er_panic("");
				return ID_ERR_NOERROR;
			}
			chop(szBuff);
			token = strtok(szBuff,seps);
			if(token==NULL){
				printf("::record format error at %s\n", pData->header.file_name);
				goto continue2;
			}
			id = atoi(token);
			arc->arc_id = id>0 ? id:-id;
			arc->direction = id>0 ? 1:0;
			++arc;
		}
		++pRecord;
		++i;
continue2:;
	}
	return ID_ERR_NOERROR;
}


/* ポリゴンデータの形式をアーク指定から、各座標直接格納形式に変換する */
void ChangePolyDataType(POLY_DATA *pPoly, ARC_DATA *pArc)
{
	int i;
	for(i=0;i<pPoly->header.record_count;++i){
		POLY_ID_RECORD *pPolyID = &(pPoly->record[i]);
		ARC_ID_RECORD *pArcID;
		unsigned int nTotalPoints=0;
		int j;
		for(j=0;j<pPolyID->count;++j){
			pArcID = GetArcIDRecord(pArc, pPolyID->arcs[j].arc_id);
			nTotalPoints += pArcID->point_count;
		}
		if(pPolyID->points)
			free(pPolyID->points);
		if(pPolyID->points = (GB_POINT*)malloc(nTotalPoints*sizeof(GB_POINT)))
		{
			GB_POINT *ptPoly = &(pPolyID->points[0]);
			int j;
			for(j=0;j<pPolyID->count;++j){
				pArcID = GetArcIDRecord(pArc, pPolyID->arcs[j].arc_id);
				/* 順方向アーク */
				if(pPolyID->arcs[j].direction){
					memcpy(ptPoly, &(pArcID->points[0]), sizeof(GB_POINT)*pArcID->point_count);
					ptPoly += pArcID->point_count;
				}

				/* 逆方向アーク */
				else{
					GB_POINT *ptArc = &(pArcID->points[pArcID->point_count]);
					int k;
					for(k=0;k<pArcID->point_count;++k,--ptArc,++ptPoly){
						memcpy(ptPoly, ptArc, sizeof(GB_POINT));
					}
				}
			}
			free(pPolyID->arcs);
			pPolyID->arcs = NULL;
			pPolyID->count = nTotalPoints;
		}
	}
}

int PolyAddPoint(POLY_ID_RECORD *pDstPolyRecord, const GB_POINT *ptAdd, int *pnMalloced)
{
	if(*pnMalloced <= pDstPolyRecord->count){
		void *p;
		if(pDstPolyRecord->points)
			p = realloc(pDstPolyRecord->points, sizeof(GB_POINT)*((*pnMalloced)*2)+10);
		else
			p = malloc(sizeof(GB_POINT)*pDstPolyRecord->count*2+10);
		
		if(p){
			*pnMalloced = sizeof(GB_POINT)*((*pnMalloced)*2)+10;
			pDstPolyRecord->points = (GB_POINT*)p;
		}
		else
			return ID_ERR_NOT_ENOUGH_MEMORY;
	}
	memcpy(&(pDstPolyRecord->points[pDstPolyRecord->count]),ptAdd,sizeof(GB_POINT));
	pDstPolyRecord->count++;
	return ID_ERR_NOERROR;
}

void CleanupPoly(POLY_DATA *pPoly){
	int i;
	for(i=0;i<pPoly->header.record_count;++i){
		POLY_ID_RECORD *pPolyRecord = &(pPoly->record[i]);
		int j;
		
		if(memcmp(&(pPolyRecord->points[0]),&(pPolyRecord->points[pPolyRecord->count-1]),sizeof(GB_POINT))!=0){
			if(pPolyRecord->count>0)
				free(pPolyRecord->points);
			for(j=i;j<pPoly->header.record_count-1;++j){
				memcpy(&(pPoly->record[j]),&(pPoly->record[j+1]),sizeof(POLY_ID_RECORD));
			}
			pPoly->header.record_count--;
			i--;
		}
		
	}
}


void free_poly_id_record(POLY_ID_RECORD *pRecord){
	if(pRecord->arcs != NULL){
		free(pRecord->arcs);
		pRecord->arcs = NULL;
	}
	if(pRecord->points != NULL){
		free(pRecord->points);
		pRecord->points = NULL;
	}
}

void PolyRecord2SVG(FILE *fp, ARC_DATA *pArc, POLY_ID_RECORD *pPolyRecord, const char *szFillColor, const char *szStrokeColor){
int j;
ARC_ID_RECORD *pArcID;

	if(pPolyRecord->count<=0){
		return;
	}
	
	/* １つのポリゴンレコードが一つのパスに対応 */
	fprintf(fp,"<path id=\"%s_%d\" style=\"fill:%s;stroke:%s;\" d=\"",
				pPolyRecord->code, pPolyRecord->id, szFillColor, szStrokeColor);
	if(pArc){
		/* 一つ目のアークを出力(PA_STARTを指定して、ポリゴンの開始であることを指定する) */
		pArcID = GetArcIDRecord(pArc, pPolyRecord->arcs[0].arc_id);
		PrintArc(fp, pArcID, pPolyRecord->arcs[0].direction,PA_START);
		/* 残りのアークを出力 */
		for(j=1;j<pPolyRecord->count;++j){
			pArcID = GetArcIDRecord(pArc, pPolyRecord->arcs[j].arc_id);
			PrintArc(fp, pArcID, pPolyRecord->arcs[j].direction,0);
		}
	}
	else{
		/* アークデータが設定されていないなら、pointsに入っているデータを出力 */
		fprintf(fp, "M %.1f %.1f", pPolyRecord->points[0].x, pPolyRecord->points[0].y);
		for(j=1; j<pPolyRecord->count; ++j){
			fprintf(fp," L %.1f %.1f", pPolyRecord->points[j].x, pPolyRecord->points[j].y);
		}
	}
	
	/* パスの閉じタグ */
	fprintf(fp,"\" />\n");
}

void Poly2SVG(FILE *fp, ARC_DATA *pArc, POLY_DATA *pPoly, const char *szFillColor, const char *szStrokeColor){
	int i;
	for(i=0;i<pPoly->header.record_count;++i){
		/* １つのポリゴンレコードが一つのパスに対応 */
		POLY_ID_RECORD *pPolyID = &(pPoly->record[i]);
		fprintf(fp,"<path id=\"%s_%d\" style=\"fill:%s;stroke:%s;\" d=\"",
				pPolyID->code, pPolyID->id, szFillColor, szStrokeColor);
		if(pPolyID->count>0){
			if(pArc){
				int j;
				/* 一つ目のアークを出力(PA_STARTを指定して、ポリゴンの開始であることを指定する) */
				ARC_ID_RECORD *pArcID = GetArcIDRecord(pArc, pPolyID->arcs[0].arc_id);
				PrintArc(fp, pArcID, pPolyID->arcs[0].direction,PA_START);
				
				/* 残りのアークを出力 */
				for(j=1;j<pPolyID->count;++j){
					pArcID = GetArcIDRecord(pArc, pPolyID->arcs[j].arc_id);
					PrintArc(fp, pArcID, pPolyID->arcs[j].direction,0);
				}
			}
			else{
				/* アークデータが設定されていないなら、pointsに入っているデータを出力 */
				int j;
				fprintf(fp, "M %.1f %.1f", pPolyID->points[0].x, pPolyID->points[0].y);
				for(j=1; j<pPolyID->count; ++j){
					fprintf(fp," L %.1f %.1f", pPolyID->points[j].x, pPolyID->points[j].y);
				}
			}
		}
		
		/* パスの閉じタグ */
		fprintf(fp,"\" />\n");
	}
}


POLY_DATA *malloc_poly_data(){
	POLY_DATA *pData = (POLY_DATA*)(malloc(sizeof(POLY_DATA)));
	memset(pData,0,sizeof(POLY_DATA));
	return pData;
}

void free_poly_data(POLY_DATA *pData){
	if(!pData)
		return;
	if(pData->record != NULL){
		int i;
		for(i=pData->header.record_count-1;i>=0;--i){
			free_poly_id_record(&pData->record[i]);
		}
		free(pData->record);
	}
	free(pData);
}
