//[1] ÀüÃ³¸®±â ¼±¾ðºÎ
#include <stdio.h>		// printf, puts, fopen, fwrite, fclose, getchar
#include <malloc.h>		// malloc, free
#include <string.h>		// strcpy, strstr
#include <conio.h>		// getch

//[2] ¸ÅÅ©·Î »ó¼ö ¼±¾ðºÎ
#define ADDRESS_DB		"c:\\AddressDB.txt" //EveryOne¿¡ ¸ðµç±ÇÇÑ ºÎ¿©

//[3] ±¸Á¶Ã¼ ¼±¾ðºÎ
typedef struct AddressRecord
{
	struct AddressRecord *Prev;		// ÀÌÀü ·¹ÄÚµå¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ
	char Name[30];					// ÀÌ¸§ ÇÊµå
	char Mobile[30];				// ÀüÈ­ ÇÊµå
	char Address[100];				// ÁÖ¼Ò ÇÊµå
	struct AddressRecord *Next;		// ´ÙÀ½ ·¹ÄÚµå¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ
}addressRecord;

//[4] Àü¿ªº¯¼ö ¼±¾ðºÎ
addressRecord *_Head = NULL;
addressRecord *_Find;
int _IsSave = 1;

//[5] ÇÔ¼ö ¿øÇü ¼±¾ðºÎ
void LoadAddress(void);		// ÁÖ¼Ò·Ï ·Îµå
void RemoveAddress(void);	// ¸Þ¸ð¸®(¸µÅ©µå¸®½ºÆ®)¿¡¼­ ÇØ´ç ·¹ÄÚµå Á¦°Å

int  AddList(const addressRecord *Address);	// ÁÖ¼Ò·Ï ¸Þ¸ð¸® Ãß°¡
int  FindList(const char *Name);			// ÁÖ¼Ò·Ï ¸Þ¸ð¸® Ã£±â

void SetHeadPosition(void);	// _Head Æ÷ÀÎÅÍ¸¦ Ã³À½ Æ÷ÀÎÅÍ·Î ÀÌµ¿
void SetTailPosition(void);	// _Head Æ÷ÀÎÅÍ¸¦ ¸¶Áö¸· Æ÷ÀÎÅÍ·Î ÀÌµ¿

void WriteAddress(void);	// ÁÖ¼Ò·Ï ÀÔ·Â
void ListAddress(void);		// ÁÖ¼Ò·Ï Ãâ·Â(¸®½ºÆ®)
void ModifyAddress(void);	// ÁÖ¼Ò·Ï ¼öÁ¤
void DeleteAddress(void);	// ÁÖ¼Ò·Ï »èÁ¦
void SearchAddress(void);	// ÁÖ¼Ò·Ï °Ë»ö
void SaveAddress(void);		// ÆÄÀÏ¿¡ ¸Þ¸ð¸® ³»¿ë ÀúÀå

//[6] ¸ÞÀÎ ÇÔ¼ö
void main(void)
{
	int intChar;

	//ÀÌ¹Ì ÆÄÀÏ¿¡ ÀúÀåµÈ µ¥ÀÌÅÍ¸¦ ÀÐ¾î¼­ ¸Þ¸ð¸® ·Îµå
	LoadAddress();

	puts("ÁÖ¼Ò·Ï ÇÁ·Î±×·¥ Version 1.0");

	// ÂüÀÏ µ¿¾È °è¼Ó¹Ýº¹
	while(1)
	{
		// ¸Þ´º Ãâ·Â
		printf("\n[1]ÀÔ·Â [2]Ãâ·Â [3]¼öÁ¤ [4]»èÁ¦ [5]°Ë»ö ([S]ÀúÀå [Q]Á¾·á) ");

		intChar = getch();

		switch(intChar)
		{
			case '1' : WriteAddress(); break;
			case '2' : ListAddress(); break;
			case '3' : ModifyAddress(); break;
			case '4' : DeleteAddress(); break;
			case '5' : SearchAddress(); break;
			case 's' :
			case 'S' : SaveAddress(); break;
			case 'q' :
			case 'Q' : 
				if(_IsSave == 0)
				{
					printf("\n\nº¯°æµÈ ÁÖ¼Ò µ¥ÀÌÅÍ¸¦ ¸ðµÎ ÀúÀåÇÏ½Ã°Ú½À´Ï±î (y/n) ? ");
					intChar = getchar();
					if(intChar == 'Y' || intChar == 'y') 
					{
						SaveAddress();
					}
				}
				RemoveAddress(); 
				return;
			default  : printf("\n\n1~5 ¶Ç´Â S/Q¸¦ ´©¸£½Ê½Ã¿À.\n\n"); break; 
		}
	}
}

//[7] ÁÖ¼Ò·Ï ·Îµå(Load)
void LoadAddress(void)
{
	addressRecord Address;
	FILE *objFile;

	objFile = fopen(ADDRESS_DB, "rb");
	if(objFile == NULL)
	{
		perror("ÆÄÀÏ °³¹æ ¿¡·¯");
		return;
	}

	while(!feof(objFile))
	{
		// fread(¹öÆÛ, ºí·°»çÀÌÁî, ºí·°°³¼ö, ÆÄÀÏÆ÷ÀÎÅÍ)
		fread(&Address, sizeof(addressRecord), 1, objFile);

		if(ferror(objFile))
		{
			fclose(objFile);
			perror("ÆÄÀÏ ÀÐ±â ¿¡·¯");
			return;
		}

		if(feof(objFile))	// ÆÄÀÏÀÇ ³¡ÀÌ¶ó¸é ·Îµå Á¾·á
		{
			break;
		}

		if(AddList(&Address) == 0)
		{
			printf("ÁÖ¼Ò µ¥ÀÌÅÍ¸¦ ¸µÅ©µå¸®½ºÆ®¿¡ Ãß°¡ÇÒ ¼ö ¾ø½À´Ï´Ù. \n");
		}
	}

	fclose(objFile);
}

//[8] ÁÖ¼Ò·Ï Ãß°¡(Fill)
int AddList(const addressRecord *Address)
{
	addressRecord *arPointer;
	addressRecord *arHeadToTail = _Head;

	SetHeadPosition();

	// _Head°¡ ÃÊ±âÈ­µÇÁö ¾ÊÀº °æ¿ì, ÇÑ ¹ø¸¸ ½ÇÇàµË´Ï´Ù.
	if(_Head == NULL)
	{
		arPointer = malloc(sizeof(addressRecord));	// addressRecord Å©±â¸¸Å­
		memset(arPointer, 0, sizeof(addressRecord));	// arPointer ±¸Á¶Ã¼¿¡ º¹»ç
		if(arPointer == NULL)
		{
			return 0;
		}

		_Head = arPointer;
		_Head->Prev = NULL;			// Ã³À½¿£ ¹Ýµå½Ã NULL·Î ÃÊ±âÈ­
		_Head->Next = NULL;			// Ã³À½¿£ ¹Ýµå½Ã NULL·Î ÃÊ±âÈ­
	}
	else	// _Head°¡ ÃÊ±âÈ­ µÈ ÈÄ °è¼Ó ½ÇÇàµË´Ï´Ù.
	{
		arPointer = malloc(sizeof(addressRecord));	// addressRecord ±¸Á¶Ã¼ ÇÒ´ç
		memset(arPointer, 0, sizeof(addressRecord));
		if(arPointer == NULL)
		{
			return 0;
		}

		while(arHeadToTail->Next)
		{
			arHeadToTail = arHeadToTail->Next;
		}

		arHeadToTail->Next = arPointer;		// ´ÙÀ½ ¸®½ºÆ®¸¦ ÁöÁ¤
		arPointer->Prev = arHeadToTail;		// ÀÌÀü ¸®½ºÆ®¸¦ ÁöÁ¤
		arPointer->Next = NULL;	// ´ÙÀ½ ¸®½ºÆ®¸¦ NULL·Î ÁöÁ¤
	}

	strcpy(arPointer->Name, Address->Name);
	strcpy(arPointer->Mobile , Address->Mobile );
	strcpy(arPointer->Address, Address->Address);

	return 1;
}

//[9] ÁÖ¼Ò·Ï _Head ¼¼ÆÃ
void SetHeadPosition(void)
{
	if(_Head == NULL) 
	{	
		return;
	}
	while(_Head->Prev)
	{
		_Head = _Head->Prev;
	}
}

//[10] ÁÖ¼Ò·Ï _Tail ¼¼ÆÃ
void SetTailPosition(void)
{
	if(_Head == NULL) 
	{
		return;
	}
	while(_Head->Next)
	{
		_Head = _Head->Next;
	}
}

//[11] ·ÎµåµÈ ÀÚ·áÁß¿¡¼­ ÀÌ¸§ °Ë»ö
int FindList(const char *Name)
{
	addressRecord *arPointer;
	SetHeadPosition();	// _Head¸¦ Ã¹ ÁÖ¼Ò µ¥ÀÌÅÍ¸¦ °¡¸®Å°µµ·Ï ÁöÁ¤
	arPointer = _Head;

	while(arPointer)
	{
		if(strstr(arPointer->Name, Name))	// ÀÌ¸§À» °Ë»ö
		{
			_Find = arPointer;
			return 1;
		}
		arPointer = arPointer->Next;
	}

	return 0;
}

//[12] ÁÖ¼Ò·Ï ÀúÀå
void WriteAddress(void)
{
	addressRecord Address;
	memset(&Address, 0, sizeof(addressRecord));

	printf("\n\nµî·ÏÇÒ ÀÌ¸§ : "); gets(Address.Name);		
	if(strlen(Address.Name) == 0)
	{
		return;
	}
		
	printf("µî·ÏÇÒ ÀüÈ­ : "); gets(Address.Mobile);
	printf("µî·ÏÇÒ ÁÖ¼Ò : "); gets(Address.Address);
	if(FindList(Address.Name) == 1)
	{
		printf("\nÀÌ¹Ì µî·ÏµÇ¾î ÀÖ´Â ÀÌ¸§ÀÔ´Ï´Ù. \n\n");
		puts(_Find->Name);
		puts(_Find->Mobile);
		puts(_Find->Address);
		return;
	}

	if(AddList(&Address))
	{
		_IsSave = 0;
		printf("\nµî·ÏµÇ¾ú½À´Ï´Ù. \n\n");
	}
	else
	{
		printf("\nµî·ÏÀÌ ½ÇÆÐµÇ¾ú½À´Ï´Ù. \n\n");
	}
}

//[13] ÁÖ¼Ò·Ï °Ë»ö
void SearchAddress(void)
{
	char strBuffer[100] = {0, };
	addressRecord *arPointer;

	printf("\n\n°Ë»öÇÒ ÀÌ¸§/ÀüÈ­/ÁÖ¼ÒÀÇ ÀÏºÎ¸¦ ÀÔ·ÂÇÏ¼¼¿ä. \n");
	printf("ÀÌ¸§/ÀüÈ­/ÁÖ¼Ò : "); gets(strBuffer);		
	if(strlen(strBuffer) == 0)
	{
		return;
	}

	SetHeadPosition();

	arPointer = _Head;
	_Find = NULL;

	while(arPointer)
	{
		if(strstr(arPointer->Name, strBuffer))	// ÀÌ¸§À» °Ë»ö
		{
			_Find = arPointer;
			break;
		}

		if(strstr(arPointer->Mobile , strBuffer))	// ÀüÈ­¸¦ °Ë»ö
		{
			_Find = arPointer;
			break;
		}
		
		if(strstr(arPointer->Address, strBuffer))	// ÁÖ¼Ò¸¦ °Ë»ö
		{
			_Find = arPointer;
			break;
		}

		arPointer = arPointer->Next;
	}

	if(_Find)
	{
		puts(_Find->Name);
		puts(_Find->Mobile);
		puts(_Find->Address);
	}
	else
	{
		printf("\n\n%sÀ» ÁÖ¼Ò·Ï¿¡¼­ Ã£À» ¼ö ¾ø½À´Ï´Ù. \n\n", strBuffer);
	}
}

//[14] ÁÖ¼Ò·Ï ¼öÁ¤
void ModifyAddress(void)
{
	char strName[100] = {0, };
	addressRecord Address;

	while(1)
	{
		printf("\n\n¼öÁ¤ÇÒ ÀÌ¸§ : "); gets(strName);
		
		if(strlen(strName) == 0)
		{
			return;
		}

		if(FindList(strName) == 0)
		{
			puts("¼öÁ¤ÇÒ ÀÌ¸§À» Ã£À» ¼ö ¾ø½À´Ï´Ù.");
			continue;
		}

		break;
	}

	printf("\n%s¿¡ ´ëÇÑ ÁÖ¼Ò µ¥ÀÌÅÍ´Â ¾Æ·¡¿Í °°½À´Ï´Ù. \n\n", strName);
	puts(_Find->Name);
	puts(_Find->Mobile);
	puts(_Find->Address);

	printf("\n¼öÁ¤ÇÏ·Á´Â ÀÌ¸§/ÀüÈ­/ÁÖ¼Ò¸¦ ÀÔ·ÂÇÑ ÈÄ ¿£ÅÍÅ°¸¦ Ä¡¼¼¿ä. \n\n");
	
	printf("ÀÌ¸§ : "); gets(Address.Name);
	printf("ÀüÈ­ : "); gets(Address.Mobile);
	printf("ÁÖ¼Ò : "); gets(Address.Address);
	if(strlen(Address.Name) == 0) 
	{
		strcpy(Address.Name, strName);
	}

	strcpy(_Find->Name, Address.Name);
	strcpy(_Find->Mobile , Address.Mobile);
	strcpy(_Find->Address, Address.Address);
	
	_IsSave = 0;

	printf("%s¿¡ ´ëÇÑ ÁÖ¼Ò µ¥ÀÌÅÍ¸¦ ¼öÁ¤ÇÏ¿´½À´Ï´Ù. \n", strName);
}

//[15] ÁÖ¼Ò·Ï »èÁ¦
void DeleteAddress(void)
{
	char strName[100] = { 0, };
	addressRecord *arPointer;
	int intChar;

	while(1)
	{
		printf("\n\n»èÁ¦ÇÒ ÀÌ¸§ : "); gets(strName);		

		if(strlen(strName) == 0) 
		{
			return;
		}

		if(FindList(strName) == 0)
		{
			puts("»èÁ¦ÇÒ ÀÌ¸§À» Ã£À» ¼ö ¾ø½À´Ï´Ù.");
			continue;
		}
		break;
	}

	puts(_Find->Name);
	puts(_Find->Mobile);
	puts(_Find->Address);

	printf("%sÀ» »èÁ¦ÇÏ½Ã°Ú½À´Ï±î (y/n)? ", strName);
	intChar = getch();
	fflush(stdin);	// Å°º¸µå ¹öÆÛ ºñ¿ì±â
	if(intChar == 'Y' || intChar == 'y')
	{
		if(_Find->Prev == NULL)			// ÀÌÀü µ¥ÀÌÅÍ°¡ ¾ø´Â °æ¿ì
		{
			if(_Find->Next == NULL)		// ´ÙÀ½ µ¥ÀÌÅÍµµ ¾ø´Â °æ¿ì
			{
				free(_Find);
				_Head = NULL;
			}
			else
			{
				arPointer = _Find->Next;
				free(_Find);
				arPointer->Prev = NULL;
				_Head = arPointer;
			}
		}
		else if(_Find->Next == NULL)	// ´ÙÀ½ µ¥ÀÌÅÍ°¡ ¾ø´Â °æ¿ì
		{
			arPointer = _Find->Prev;
			free(_Find);
			arPointer->Next = NULL;
			_Head = arPointer;
		}
		else					// ÀÌÀü°ú ´ÙÀ½µ¥ÀÌÅÍ°¡ ¸ðµÎ ÀÖ´Â °æ¿ì
		{
			arPointer = _Find->Prev;
			arPointer->Next = _Find->Next;
			arPointer = _Find->Next;
			arPointer->Prev = _Find->Prev;
			free(_Find);
			_Head = arPointer;
		}

		_IsSave = 0;

		printf("\n\n°Ë»öµÈ ÁÖ¼Ò µ¥ÀÌÅÍ¸¦ »èÁ¦ÇÏ¿´½À´Ï´Ù.\n\n");
	}
}

//[16] ÁÖ¼Ò·Ï ¸®½ºÆ® º¸¿©ÁÖ±â
void ListAddress(void)
{
	int intCount = 1;
	addressRecord *arPointer;

	SetHeadPosition();
	
	arPointer = _Head;

	// arPointer ¸®½ºÆ®ÀÇ ¸Ç Ã³À½À¸·Î ÀÌµ¿
	while(arPointer->Prev)
	{
		arPointer = arPointer->Prev;
	}
	printf("\n\n");

	// ÇÑ °³¾¿ Ãâ·Â
	while(arPointer)
	{
		printf("¹øÈ£. %d \n", intCount++);
		puts(arPointer->Name);
		puts(arPointer->Mobile);
		printf("%s \n\n", arPointer->Address);
		printf("¾Æ¹«Å°³ª ´©¸£¼¼¿ä, (ÁßÁö:q) \n\n");
		if(getch() == 'q')
		{ 
			return;
		}
		arPointer = arPointer->Next;
	}
}

//[17] ÁÖ¼Ò·Ï ÆÄÀÏ ÀúÀå
void SaveAddress(void)
{
	addressRecord *arPointer;
	FILE *objFile;
	if(_Head == NULL)
	{
		return;
	}
	
	objFile = fopen(ADDRESS_DB, "w+b");
	if(objFile == NULL)
	{
		perror("ÆÄÀÏ °³¹æ ¿¡·¯");
		return;
	}

	SetHeadPosition();

	// ÇÑ °³¾¿ ¸Þ¸ð¸® ÇØÁ¦
	while(_Head)
	{
		arPointer = _Head->Next;		
		fwrite(_Head, sizeof(addressRecord), 1, objFile);
		_Head = arPointer;
	}

	printf("\n¸ðµç µ¥ÀÌÅÍ¸¦ ÆÄÀÏ¿¡ ÀúÀåÇÏ¿´½À´Ï´Ù.");
	_IsSave = 1;

	fclose(objFile);
}

//[18] ÁÖ¼Ò·Ï ³»¿ë ¸Þ¸ð¸® ÇØÁ¦
void RemoveAddress(void)
{
	addressRecord *arPointer;
	if(_Head == NULL)
	{
		return;
	}
	
	SetHeadPosition();

	// ÇÑ °³¾¿ ¸Þ¸ð¸® ÇØÁ¦
	while(_Head)
	{
		arPointer = _Head->Next;		
		free(_Head);		
		_Head = arPointer;
	}

	_Head = NULL; // Àç »ç¿ëÀ» ÇÏ±â À§ÇÑ ÃÊ±âÈ­
}