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

#define MAX_STUDENT_SIZE 1000

struct Student {
	char name[32];
	char id[16];
	int chinese_score;
	int math_score;
	int total_score;
};

struct Student students[MAX_STUDENT_SIZE];
int num_of_stu = 0;  /*学生总人数*/
FILE* fp = NULL;   /*保存学生信息的文件指针*/  

/*函数申明*/
void load();  /*从文件加载学生成绩数据*/
int main_menu(); /*主菜单*/
void exit_system(); /*退出系统*/
void input_scores(); /*学生成绩录入*/
void rank_by_total_score(); /*按总分排名次*/
void query_by_name();  /*按姓名查找某学生成绩*/
void course_statistical_analyse(); /*统计各课程的平均分、及格率、最高分、最低分*/
void print_report_card(); /*打印成绩单*/
void print_report_card_by_name(); /*根据学生姓名打印成绩单*/
void print_report_card_by_id(); /*根据学生学号打印成绩单*/


int main() {
	int option;
	load(); /*从文件中读取所有已经录入的学生成绩信息*/
	while (1) {
		option = main_menu();
		/*选项输入结束,处理具体事务*/
		switch(option) {
			case 0:
				exit_system();
				break;
			case 1:
				input_scores();
				break;
			case 2:
				rank_by_total_score();
				break;
			case 3:
				query_by_name();
				break;
			case 4:
				course_statistical_analyse();
				break;
			case 5:
				print_report_card();
				break;
			default:
				exit_system();
				break;
		}
		printf("\n\n1. 回到主菜单 0. 退出系统, 请选择您需要的选项:");
		scanf("%d", &option);
		if (option != 1) {
			break;
		}
	}
	if(fp != NULL) {
		fclose(fp); /*关闭文件*/
	}
	return 0;
}

void load() {
	/*读写打开一个二进制文件,允许读,或在文件末追加数据*/
	fp = fopen("student_info.db", "ab+");
	if (fp == NULL) {
		perror("cannot open the file!");
		exit(-1); 
	}
	/*加载保存在文件中的学生成绩信息*/
	fseek(fp, 0, SEEK_SET);
	while(fread(&students[num_of_stu], sizeof(struct Student), 1, fp) == 1) {
		num_of_stu++;
		printf("%d\n", num_of_stu);
	}
	printf("%d\n", num_of_stu);
}

int main_menu() {
	int option = 0;
	system("cls");
	printf("**********************学生成绩管理系统****************************\n");
	printf("* 1. 录入学生成绩(姓名、学号、语文、数学成绩,总分自动计算)\n");
	printf("* 2. 按总分排名次\n");
	printf("* 3. 按姓名查找某学生成绩\n");
	printf("* 4. 统计各课程的平均分、及格率、最高分、最低分\n");
	printf("* 5. 打印成绩表\n");
	printf("* 0. 退出系统\n");
	printf("******************************************************************\n");

	printf("请输入您需要的选项(0-5):");
	scanf("%d", &option);
	/*输入选项检查,选项必须是0-5,否则重新输入*/
	while (option < 0 ||  option > 5) { 
		printf("输入的选项有误,请重新输入您需要的选项(0-5):");
		scanf("%d", &option);
	}
	return option;
}

void exit_system() {
	exit(0);
}

void input_scores() {
	int sub_opt = 0;
	while (1) { 
		/*录入学生成绩时,首先学生总数是否已达到系统上限*/
		if (num_of_stu >= MAX_STUDENT_SIZE) {
			/*学生总数达系统上限,退出成绩录入*/
			printf("学生总数已达到系统上限(%d),无法录入学生成绩!", MAX_STUDENT_SIZE);
			break;
		}
		printf("请输入学生姓名、学号、语文、数学成绩,基本格式如(张三 13091121 85 90):\n");
		scanf("%s%s%d%d", students[num_of_stu].name,
							students[num_of_stu].id,
							&students[num_of_stu].chinese_score,
							&students[num_of_stu].math_score);
		/*判断语文成绩是否合法,成绩百分制*/
		if (students[num_of_stu].chinese_score < 0 || students[num_of_stu].chinese_score > 100) {
			printf("语文成绩(%d)有误!\n", students[num_of_stu].chinese_score);
			printf("请重新录入该生成绩!\n");
			continue;
		}
		/*判断数学成绩是否合法,成绩百分制*/
		if (students[num_of_stu].math_score < 0 || students[num_of_stu].math_score > 100) {
			printf("数学成绩(%d)有误!\n", students[num_of_stu].math_score);
			printf("请重新录入该生成绩!\n");
			continue;
		}
		students[num_of_stu].total_score 
				= students[num_of_stu].chinese_score + students[num_of_stu].math_score;
		
		if (fp != NULL) {
			/*录入学生成绩保存到文件中,系统启动时从文件加载所有录入的成绩*/
			if (fwrite(&students[num_of_stu], sizeof(struct Student), 1, fp) != 1) {
				perror("文件写入出错!");
				exit(-1);
			}
		}
		num_of_stu++; /*学生总数加1*/
		
		/*判断是否继续录入学生成绩*/
		printf("是否继续录入学生成绩,是(1), 否(0):");
		scanf("%d", &sub_opt);
		if (sub_opt != 1) { /*学生成绩录入结束*/
			break;
		}
	}
}

/*按总分排名次*/
void rank_by_total_score(){
	struct Student tmp_stu;
	for (int i = 0; i < num_of_stu - 1; i++) {
		for (int j = 0; j < num_of_stu - 1 - i; j++) {
			if (students[j].total_score > students[j+1].total_score) {
				memcpy(&tmp_stu, &students[j],sizeof(struct  Student));
				memcpy(&students[j], &students[j+1], sizeof(struct Student));
				memcpy(&students[j+1], &tmp_stu, sizeof(struct Student));
			}
		}
	}
	printf("--------------------------------------------------------------------------\n");
	printf("          姓名            学号        语文        数学       总分\n");
	for (int j = 0; j < num_of_stu; j++) {
		printf("%16s%16s%10d%10d%10d\n", students[j].name,
											students[j].id,
											students[j].chinese_score,
											students[j].math_score,
											students[j].total_score);
	}
	printf("--------------------------------------------------------------------------\n");
}

void query_by_name(){
	char name[32];
	int cnt  = 0 ;

	printf("请输入需要查询成绩的学生姓名:");
	scanf("%s", name);

	for (int i = 0; i < num_of_stu; i++) {
		if(strcmp(students[i].name, name) == 0) {
			if (cnt == 0){ /*可能存在同名同姓的同学,只有查找到第一个学生的时候输出表头*/
				printf("--------------------------------------------------------------------------\n");
				printf("          姓名            学号        语文        数学       总分\n");
			}
			printf("%16s%16s%10d%10d%10d\n", students[i].name,
											students[i].id,
											students[i].chinese_score,
											students[i].math_score,
											students[i].total_score);
			cnt++;
		}
	}
	if (cnt == 0) {
		printf("学生成绩管理系统中不存在姓名为的\"%s\"学生\n", name);
	}
	else {
		printf("--------------------------------------------------------------------------\n");

	}
}

void course_statistical_analyse(){
	if (num_of_stu == 0) {  /*学生总数为0时,单独处理,计算平均分和及格率时除0程序会出现错误*/
		printf("学生总数:0\n");
		printf("语文成绩统计情况:\n");
		printf("\t均分:0\n");
		printf("\t及格率:0\n");
		printf("\t最高分:0\n");
		printf("\t最低分:0\n");
		printf("数学成绩统计情况:\n");
		printf("\t均分:0\n");
		printf("\t及格率:0\n");
		printf("\t最高分:0\n");
		printf("\t最低分:0\n");
		return;
	}

	double total_chinese_scores = 0;
	double total_math_scores = 0;
	int max_chinese_score = students[0].chinese_score;
	int max_math_score = students[0].math_score;
	int min_chinese_score = students[0].chinese_score;
	int min_math_score = students[0].math_score;
	int chinese_passes = 0;
	int math_passes = 0;

	for (int i = 0; i < num_of_stu; i++) {
		/*统计总分*/
		total_chinese_scores += students[i].chinese_score;
		total_math_scores += students[i].math_score;

		/*统计最高分和最低分*/
		if (students[i].chinese_score > max_chinese_score) {
			max_chinese_score = students[i].chinese_score;
		}
		else if (students[i].chinese_score < min_chinese_score) {
			min_chinese_score = students[i].chinese_score;
		}
		if (students[i].math_score > max_math_score) {
			max_math_score = students[i].math_score;
		}
		else if (students[i].math_score < min_math_score) {
			min_math_score = students[i].math_score;
		}

		/*统计及格率*/
		if (students[i].chinese_score >= 60) {
			chinese_passes++;
		}
		if (students[i].math_score >= 60) {
			math_passes++;
		}
	}
	printf("学生总数:%d\n", num_of_stu);
	printf("语文成绩统计情况:\n");
	printf("\t均分:%.2lf\n", total_chinese_scores / num_of_stu); /*只保留两位小数*/
	printf("\t及格率:%.2lf%%\n", chinese_passes*100.0 /num_of_stu);/*只保留两位小数,百分比*/
	printf("\t最高分:%d\n", max_chinese_score);
	printf("\t最低分:%d\n", min_chinese_score);
	printf("数学成绩统计情况:\n");
	printf("\t均分:%.2lf\n", total_math_scores / num_of_stu);
	printf("\t及格率:%.2lf%%\n", math_passes*100.0 / num_of_stu);
	printf("\t最高分:%d\n", max_math_score);
	printf("\t最低分:%d\n", min_math_score);
}

void print_report_card(){
	int sub_opt = 1;
	printf("1.按学号打印成绩单 2.按姓名打印成绩单\n");
	printf("请输入您需要的选项(1-2):");
	scanf("%d", &sub_opt);
	while (sub_opt < 1 ||sub_opt > 2) {
		printf("输入选项(%d)不存在!", sub_opt);
		printf("1.按学号打印成绩单 2.按姓名打印成绩单\n");
		printf("请重新输入您需要的选项(1-2):");
		scanf("%d", &sub_opt);
	}
	switch(sub_opt) {
		case 1:
			print_report_card_by_id();
			break;
		case 2:
			print_report_card_by_name();
			break;
	}
}

void print_report_card_by_name() {
	char name[32];
	int cnt = 0;
	printf("请输入需要打印成绩的学生姓名:");
	scanf("%s", name);

	for (int i = 0; i < num_of_stu; i++) {
		if(strcmp(students[i].name, name) == 0) {
			printf("\n---------------------------------成绩单------------------------------------\n");
			printf("姓名:%s\t学号:%s\n", students[i].name, students[i].id);
			printf("语文:%d\n", students[i].chinese_score);
			printf("数学:%d\n", students[i].math_score);
			printf("总分:%d\n", students[i].total_score);
			printf("--------------------------------------------------------------------------\n");
			cnt++;
		}
	}
	if (cnt == 0) {
		printf("不存在姓名为\"%s\"的学生", name);	
	}	
}

void print_report_card_by_id() {
	char id[16];

	printf("请输入需要打印成绩单的学生学号:");
	scanf("%s", id);
	int i;
	for (i = 0; i < num_of_stu; i++) {
		if(strcmp(students[i].id, id) == 0) {
			printf("\n---------------------------------成绩单------------------------------------\n");
			printf("姓名:%s\t学号:%s\n", students[i].name, students[i].id);
			printf("语文:%d\n", students[i].chinese_score);
			printf("数学:%d\n", students[i].math_score);
			printf("总分:%d\n", students[i].total_score);
			printf("--------------------------------------------------------------------------\n");
			break;
		}
	}
	if (i == num_of_stu) {
		printf("不存在学号为\"%s\"的学生", id);
	}
}