#include <GConsoleLib.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define SEIZAMAX 12
//星座データ
struct Star{
	int x, y;		//座標
	int magnitude;	//等級
};
struct Line{
	int startpt, endpt;
};
struct Seiza{
	char *name;		//星座名
	Star *stars;	//星の配列
	int starnum;	//星の数
	Line *lines;	//線の配列
	int linenum;	//線の数
};
#define SEIZAMAX 12
Seiza g_seiza[SEIZAMAX];

//関数プロトタイプ宣言
void DrawSeiza(Seiza*);
void EditSeiza(Seiza*);

int main(){
	//ファイル読み込み
	FILE *fp;
	if( fopen_s(&fp, "zodiac.txt", "r") != 0 ) {
		printf("ファイル読み込みエラー\n");
		return -1;
	}
	char rbuf[256];
	for(int i=0; i<SEIZAMAX; i++){
		if(fgets( rbuf, 256, fp ) == NULL) break;
		//最初は星座名
		int len = strlen(rbuf);
		g_seiza[i].name = (char *)malloc( sizeof(char) * len );
		strncpy_s(g_seiza[i].name, len, rbuf, len-1);
		g_seiza[i].name[len-1] = '\0';//改行削除
		//星の数
		if(fgets( rbuf, 256, fp ) == NULL) break;
		sscanf_s(rbuf, "%d", &g_seiza[i].starnum);
		//メモリ確保
		g_seiza[i].stars = 
			(Star *)malloc( sizeof(Star) * g_seiza[i].starnum);
		//星データ読み込み
		for(int j=0; j<g_seiza[i].starnum; j++){
			if(fgets( rbuf, 256, fp ) == NULL) break;
			int x, y, m;
			sscanf_s(rbuf, "%d, %d, %d", &x, &y, &m);
			g_seiza[i].stars[j].x = x;
			g_seiza[i].stars[j].y = y;
			g_seiza[i].stars[j].magnitude = m;
		}
		//線の数
		if(fgets( rbuf, 256, fp ) == NULL) break;
		sscanf_s(rbuf, "%d", &g_seiza[i].linenum);
		//メモリ確保
		g_seiza[i].lines = 
			(Line *)malloc( sizeof(Line) * g_seiza[i].starnum);
		//線データ読み込み
		for(int j=0; j<g_seiza[i].linenum; j++){
			if(fgets( rbuf, 256, fp ) == NULL) break;
			int sp, ep;
			sscanf_s(rbuf, "%d, %d", &sp, &ep);
			g_seiza[i].lines[j].startpt = sp;
			g_seiza[i].lines[j].endpt = ep;
		}
	}
	fclose(fp);

	gcls();
	gfront();

	int curseiza = 0;	//表示・編集する星座
	char buf[64];
	while(1){
		gcls();
		gimage("C:\\GConsole追加ファイル\\sampleimg\\chap7-1.png", 0, 0);
		DrawSeiza( &g_seiza[curseiza] );
		gcolor(0,0,0);
		glocate(0, 17);
		gprintf("星座番号(0-%d)または編集(e)、終了(x)", SEIZAMAX-1 );
		ggets(buf, 64);
		char com = buf[0];	//先頭文字取り出し
		switch(com){
			case 'e':
				//編集
				EditSeiza( &g_seiza[curseiza] );
				break;
			case 'x':
				//終了
				goto PROGRAMQUIT;
				break;
			default:
				//表示星座の切り替え
				int num = atoi(buf);
				if( num >=0 && num < SEIZAMAX ){
					curseiza = num;
				}
		}
	}
PROGRAMQUIT:
	//メモリ解放
	for(int i=0; i<SEIZAMAX; i++){
		free( g_seiza[i].name );
		free( g_seiza[i].stars );
		free( g_seiza[i].lines );
	}
}

//星座の表示
void DrawSeiza(Seiza *sz){
	//Seiza *sz = &g_seiza[seizaid];
	//星座名の表示
	gcolor(255, 255, 0);	//黄色に設定
	glocate(6, 1);
	gprintf("%s", sz->name );
	//星の表示
	for(int i=0; i < sz->starnum; i++){
		gpoint( sz->stars[i].x, sz->stars[i].y, 
			sz->stars[i].magnitude * 2); 
	}
	for(int i=0; i < sz->linenum; i++){
		int sp = sz->lines[i].startpt;
		int ep = sz->lines[i].endpt;
		gline( sz->stars[sp].x, sz->stars[sp].y,
			   sz->stars[ep].x, sz->stars[ep].y );
	}	
	
}

//ファイルの保存
void SaveToTextFile(){
	FILE *fp;
	if( fopen_s(&fp, "zodiac.txt", "w") != 0 ) {
		printf("ファイル書き込みエラー\n");
		return;
	}
	for(int i=0; i<SEIZAMAX; i++){
		//名前の書き出し
		fprintf( fp, "%s\n", g_seiza[i].name );
		//星の数
		fprintf( fp, "%d\n", g_seiza[i].starnum );
		//星データ書き出し
		for(int j=0; j<g_seiza[i].starnum; j++){
			fprintf( fp, "%d, %d, %d\n", 
				g_seiza[i].stars[j].x, 
				g_seiza[i].stars[j].y, 
				g_seiza[i].stars[j].magnitude );
		}
		//線の数
		fprintf( fp, "%d\n", g_seiza[i].linenum );
		//線データ書き出し
		for(int j=0; j<g_seiza[i].linenum; j++){
			fprintf( fp, "%d, %d\n", 
				g_seiza[i].lines[j].startpt, 
				g_seiza[i].lines[j].endpt );
		}
	}
	fclose(fp);
}

//編集用の星表示
void DrawStarsForEdit(Seiza *sz){
	//星番号を表示
	glocate(0,0);
	gcolor(0,0,0);
	for(int i=0; i<20; i++){
		gprintf("%2d ", i);
	}
	//星を色分けして表示
	int rcol = 64, gcol = 64, bcol = 64;
	for(int i=0; i < sz->starnum; i++){
		gcolor(rcol & 0xFF, gcol & 0xFF, bcol & 0xFF);
		gpoint( sz->stars[i].x, sz->stars[i].y, 
			4); 
		gpoint( i * 30 + 16, 20, 4); 
		rcol += 32;
		if(rcol > 255) gcol += 32;
		if(gcol > 255) bcol += 32;
	}
}

//編集用の線表示
void DrawLineForEdit(Star *stars, Line *lines, int linenum){
	gcolor(128, 128, 0);
	for(int i=0; i<linenum; i++){
		int sp = lines[i].startpt;
		int ep = lines[i].endpt;
		gline( stars[sp].x, stars[sp].y,
			   stars[ep].x, stars[ep].y );
	}
}

//星座データの編集
void EditSeiza(Seiza *sz){
	//編集用メモリ領域
	Line *editlines = (Line *)malloc( sizeof(Line) * 40 );
	int editlinenum = 0;
	//既存のデータがあればコピー
	if(sz->linenum > 0){
		memcpy_s(editlines, sizeof(Line) * 40, 
			sz->lines, sizeof(Line) * sz->linenum );
		editlinenum = sz->linenum;
	}
	//コマンド入力
	char com = '\0';
	while(com != 'e'){
		//星の表示
		gcls();
		DrawLineForEdit( sz->stars, editlines, editlinenum );
		DrawStarsForEdit(sz);
		glocate(0,15);
		gcolor(0,0,0);
		gprintf("線追加(a), 線削除(d), 終了(e), 反映して終了(s)");
		com = ggetchar();
		char buf[64];
		int sp=0, ep=0, dl=0;
		switch(com){
			case 'a':
				//線の追加コマンド
				gprintf("\n始点の星番号(0-%d)？", sz->starnum - 1);
				ggets(buf, 64);
				sp = atoi(buf);
				gprintf("\n終点の星番号(0-%d)？", sz->starnum - 1);
				ggets(buf, 64);
				ep = atoi(buf);
				//確認
				if( sp < 0 || sp >= sz->starnum ||
					ep < 0 || ep >= sz->starnum ) break;
				gcolor(255,0,0);
				gline( sz->stars[sp].x, sz->stars[sp].y,
					   sz->stars[ep].x, sz->stars[ep].y );
				gprintf("\n追加しますか（y/n）？");
				com = ggetchar();
				if(com == 'y'){
					if(editlinenum < 40){
						editlines[editlinenum].startpt = sp;
						editlines[editlinenum].endpt = ep;
						editlinenum++;
					}
				}
				break;
			case 'd':
				//線の削除コマンド
				gprintf("\n削除する線番号(0-%d)？", editlinenum - 1);
				ggets(buf, 64);
				dl = atoi(buf);
				//確認
				if( dl < 0 || dl >= editlinenum) break;
				sp = editlines[dl].startpt;
				ep = editlines[dl].endpt;
				gcolor(255,0,0);
				gline( sz->stars[sp].x, sz->stars[sp].y,
					   sz->stars[ep].x, sz->stars[ep].y );
				gprintf("\n削除しますか（y/n）？");
				com = ggetchar();
				if(com == 'y'){
					//最後の要素でなければ詰める
					if(dl < editlinenum - 1){
						for(int j=dl; j < editlinenum-1; j++){
							editlines[j] = editlines[j+1];
						}
					}
					editlinenum--;
				}
				break;
			case 's':
				//反映＆保存
				gprintf("\n反映して編集を終了しますか（y/n）？");
				com = ggetchar();
				if(com == 'y'){
					//g_seizaにデータを反映
					free(sz->lines);	//古いメモリを解放
					sz->linenum = editlinenum;
					sz->lines = (Line *)malloc( sizeof(Line) * editlinenum );
					memcpy_s( sz->lines, sizeof(Line) * editlinenum,
						editlines, sizeof(Line) * editlinenum);
					//ファイルの保存
					SaveToTextFile();
					com = 'e';
				}
				break;
		}
	}
	//メモリ解放
	free(editlines);
}