#include<iostream>
#include<iomanip>
#include<string>
#include<fstream>
#include<windows.h>
#include<math.h>
#include<sys\stat.h>
using namespace std;
string strFilePathName3;
const int FilePathLen = 1024;
const int ClassNameLen = 32;
//-------------------------------------
//----------学生信息结构---------------
//-------------------------------------
struct StudentMessage
{
    int nNo;                //学号
    char chName[10];        //姓名
    char chCourse[20];        //专业
    char chGender[8];        //性别
    float fComprehensive;    //综合成绩
    int nBirthdate;            //出生日期
    int nAge;                //年龄
    //本科生
    float fEnglishResults;    //本科生英语成绩
    //研究生
    int nThesisCount;        //研究生发表论文数量
    StudentMessage *pNext;    //指向下一个学生的指针
};
//-------------------------------------
//------------函数预定义---------------
//-------------------------------------
bool FileExist (string strFilePathName);    //判断文件数否存在
bool IsDirectory(string strDirNaem);        //判断目录是否存在
string GetMessageFileName();                //根据输入文件目录及班级名称生成数据文件全名称
bool FreeMem(StudentMessage *pRsHead);        //释放链表
bool MessageToFile(string strFilePathName,StudentMessage* pStHead,int nSign=1);        //保存数据到文件
StudentMessage* MessageFromFile(string strFilePathName);                            //从文件中读取学生信息
bool StudentMessageInput();                    //学生信息输入
bool MessageDelete(StudentMessage* pStHead,string strFilePathName);                    //信息删除
void Display(StudentMessage *pStHead,int nNum,int nSign);                            //显示学生信息
bool MessageBrowser();                        //浏览学生信息
void InquiryByNo();                            //按学号检索
int InquiryByName();                        //按姓名检索
void MessageUpdate(StudentMessage *pStHead,StudentMessage *pStCur,string strFilePathName,int nSign);    //信息修改
void ResultsAverage();                        //本科生综合平均成绩、英语平均成绩
void nThesisCountSort(StudentMessage* pStHead,int nAscending);                        //研究生按论文数量排序
int MenuMain();                                //系统菜单
bool MessageInquiry();                        //成绩查询
//-------------------------------------
//-------------函数实现----------------
//-------------------------------------
//判断文件是否存在-------------------------
bool FileExist(string strFilePathName)
{
    int StudentMessage;
    struct _stat buf;
    StudentMessage= _stat(strFilePathName.c_str(),&buf);
    return(StudentMessage==0);
}
//判断目录是否存在-------------------------
bool IsDirectory(string strDirName)
{
    struct _stat buf;
    if(_stat(strDirName.c_str(),&buf)!=0)  //判断是否存在
    {
        return false;
    }
    return ((buf.st_mode&S_IFDIR)!=0);
}
//根据输入文件目录及班级名称生成数据文件全名称-------------------------
string GetMessageFileName()
{
    char chFilePath[FilePathLen];  //文件存放目录
    char chClass[ClassNameLen];    //班级名称
    string strFilePathName;
    string strFilePathName2;

    //输入成绩存放目录及班级
    //cin.ignore();
    cout<<"请输入文件目录:";
    cin.getline(chFilePath,FilePathLen);
    strFilePathName=string(chFilePath);
    while(!IsDirectory(strFilePathName))
    {
        cout<<"目录:"<<strFilePathName<<"不存在,请重新输入!"<<endl;
        cin.getline(chFilePath,FilePathLen);
        strFilePathName=string(chFilePath);
    }
    int nLen=strFilePathName.length();
    int nPos=strFilePathName.find_last_of('\\',nLen);
    if(nPos!=nLen)
    {
        strFilePathName=strFilePathName+string("\\");
    }
    strFilePathName2=strFilePathName;
    //输入班级成绩
    cout<<"请输入班级名称:";
    cin.getline(chClass,ClassNameLen);
    //
    strFilePathName=strFilePathName+string(chClass)+string(".dat");

    while(!FileExist(strFilePathName))
    {
        cout<<"文件:"<<strFilePathName<<"不存在,请重新输入!"<<endl;
        cin.getline(chClass,ClassNameLen);
        strFilePathName=strFilePathName2+string(chClass)+string(".dat");
    }
    return strFilePathName;
}
//释放链表内存-------------------------
bool FreeMem(StudentMessage* pStHead)
{
    StudentMessage *pStCur;

    if(pStHead==NULL)
        return false;
    do
    {
        pStCur=pStHead;
        pStHead=pStHead->pNext;
        delete pStCur;
    }while(pStHead!=NULL);

    return true;
}
//保存数据到文件-------------------------
bool MessageToFile(string strFilePathName,StudentMessage* pStHead,int nSign)
{
    StudentMessage* pStCur;
    ofstream fileOut;
    //
    if(pStHead==NULL)
        return false;

    //已追加方式打开文件
    if(nSign==1)
        fileOut.open(strFilePathName.c_str(),ios::out|ios::app|ios::binary);
    //如果文件存在,把文件长度设为0/文件更新
    if(nSign==0)
        fileOut.open(strFilePathName.c_str(),ios::out|ios::trunc|ios::binary);
    if(fileOut.fail())
    {
        cout<<"Can not open file:"<<strFilePathName<<endl;
        return false;
    }

    //保存成绩
    pStCur=pStHead;
    while(pStCur!=NULL)
    {
        fileOut.write((char*)pStCur,sizeof(*pStCur));
        pStCur=pStCur->pNext;
    };
    //关闭文件
    fileOut.close();
    return true;

}
//从给定文件读取学生成绩------------------------------
StudentMessage* MessageFromFile(string strFilePathName)
{
    SYSTEMTIME systime;        //windows.h中的函数
    GetLocalTime(&systime);        //获取当前时间
    StudentMessage *pStNew,*pStHead=NULL;
    ifstream fileIn;

    //打开文件
    fileIn.open(strFilePathName.c_str(),ios::in|ios::binary);    //binary:二进制方式
    if(fileIn.fail())
    {
        cout<<"Can not open file:"<<strFilePathName<<endl;
        return pStHead;
    }

    //成绩记录
    while(!fileIn.eof())
    {
        pStNew=new StudentMessage;
        fileIn.read((char*)pStNew,sizeof(*pStNew));
        int ng=fileIn.gcount();
        if(ng==0)
        {
            delete pStNew;
            break;
        }

        //根据不同的出生日期输入格式,计算年龄
        if(pStNew->nBirthdate/10000>=1)
        {
            pStNew->nAge=systime.wYear-pStNew->nBirthdate/10000;
        }
        else
        {
            pStNew->nAge=systime.wYear-pStNew->nBirthdate;
        }
        pStNew->pNext=NULL;
        if(pStHead==NULL)
            pStHead=pStNew;
        else
        {
            pStNew->pNext=pStHead;
            pStHead=pStNew;
        }
    }
    fileIn.close();

    return pStHead;
}
//成绩录入-------------------------
void StudentMessageInput(int nSign)
{
    char chChoice;
    bool bFileExist;
    //string strFilePathName;

    //录入班级和文件存放目录
    //strFilePathName=GetMessageFileName();
    bFileExist=FileExist(strFilePathName3);
    if(bFileExist)
    {
        cout<<"文件"<<strFilePathName3<<"已存在,是否追加(Y/N)";
        cin>>chChoice;
        if(toupper(chChoice)=='N')
            return ;
    }

    StudentMessage *pStHead=NULL;
    StudentMessage *pStNew,*pStPrev;

    //录入所有学生成绩
    cout<<"请依次输入每位学生信息,学号为 -1 结束输入"<<endl;
    do
    {
        pStNew=new StudentMessage;
        pStNew->pNext=NULL;
        pStNew->fComprehensive=0;
        pStNew->nBirthdate=0;
        pStNew->nAge=0;
        pStNew->fEnglishResults=0;
        pStNew->nThesisCount=0;
        cout<<"学号:";
        cin>>pStNew->nNo;
        if(pStNew->nNo==-1)
        {
            delete pStNew;
            break;
        }
        cout<<"姓名:"; cin>>pStNew->chName;
        cout<<"专业:"; cin>>pStNew->chCourse;
        cout<<"性别:"; cin>>pStNew->chGender;
        cout<<"出生日期:"; cin>>pStNew->nBirthdate;
        cout<<"综合成绩:"; cin>>pStNew->fComprehensive;
        if(nSign==0)
        {
            cout<<"英语成绩:"; cin>>pStNew->fEnglishResults;
        }
        else
        {
            cout<<"论文数量:"; cin>>pStNew->nThesisCount;
        }
        if(pStHead==NULL)
            pStHead=pStNew;
        else
        {
            pStPrev=pStHead;
            while(pStPrev->pNext!=NULL)
                pStPrev=pStPrev->pNext;
            pStPrev->pNext=pStNew;
        }
    }while(true);
    //bool bMes;
//    bMes=MessageToFile(strFilePathName3,pStHead);
    //释放内存
    FreeMem(pStHead);
    //return bMes;
}
//显示学生信息-----------------------------------
void Display(StudentMessage *pStHead,int nNum,int nSign)
{
    StudentMessage* pStCur;

    //
    if(pStHead==NULL)
    {
        cout<<"没有数据!"<<endl;
        return;
    }
    pStCur=pStHead;

    //显示单个学生成绩
    if(nNum==1)
    {
        cout<<"学号:"<<pStCur->nNo<<endl;
        cout<<"姓名:"<<pStCur->chName<<endl;
        cout<<"性别:"<<pStCur->chGender<<endl;
        cout<<"专业:"<<pStCur->chCourse<<endl;
        cout<<"出生日期:"<<pStCur->nBirthdate<<endl;
        cout<<"年龄:"<<pStCur->nAge<<endl;
        cout<<"综合成绩:"<<pStCur->fComprehensive<<endl;
        if(nSign==0)
            cout<<"英语成绩:"<<pStCur->fEnglishResults<<endl;
        else
            cout<<"论文数量:"<<pStCur->nThesisCount<<endl;
        return;
    }
    else
    {
        //显示所有学生成绩
        cout<<setw(5)<<"学号"<<setw(10)<<"姓名"<<setw(8)<<"性别";
        cout<<setw(10)<<"专业"<<setw(10)<<"出生日期"<<setw(5)<<"年龄";
        cout<<setw(10)<<"综合成绩"<<setw(10);
        if(nSign==0)
            cout<<"英语成绩"<<endl;
        else
            cout<<"论文数量"<<endl;
        do
        {

            if(nSign==0)
            {
                if(pStCur->fEnglishResults)
                {        
                    cout<<setw(5)<<pStCur->nNo;
                    cout<<setw(10)<<pStCur->chName;
                    cout<<setw(8)<<pStCur->chGender;
                    cout<<setw(10)<<pStCur->chCourse;
                    cout<<setw(10)<<pStCur->nBirthdate;
                    cout<<setw(5)<<pStCur->nAge;
                    cout<<setw(10)<<pStCur->fComprehensive;
                    cout<<setw(10)<<pStCur->fEnglishResults;
                }
            }
            else
            {
                if(pStCur->nThesisCount)
                {
                    cout<<setw(5)<<pStCur->nNo;
                    cout<<setw(10)<<pStCur->chName;
                    cout<<setw(8)<<pStCur->chGender;
                    cout<<setw(10)<<pStCur->chCourse;
                    cout<<setw(10)<<pStCur->nBirthdate;
                    cout<<setw(5)<<pStCur->nAge;
                    cout<<setw(10)<<pStCur->fComprehensive;
                    cout<<setw(10)<<pStCur->nThesisCount;
                }
            }
            cout<<endl;

            pStCur=pStCur->pNext;
        }while(pStCur!=NULL);
    }
    return;
}
//信息浏览--------------------------------------
bool MessageBrowser(int nSign)
{
    //string strFilePathName;
    ifstream fileIn;

    //
    //strFilePathName=GetMessageFileName();

    StudentMessage *pStHead;

    //成绩记录
    pStHead =MessageFromFile(strFilePathName3);
    Display(pStHead,0,nSign);
    FreeMem(pStHead);

    return true;
}
//信息删除--------------------------------
bool MessageDelete()
{
    //string strFilePathName;
    StudentMessage* pStHead=NULL;
    //strFilePathName=GetMessageFileName();
    pStHead =MessageFromFile(strFilePathName3);

    if(pStHead==NULL)
        return false;
    StudentMessage* pStCur;
    int nNo,nNum;

    cout<<"请输入要删除的信息学生号:";
    cin>>nNo;
    nNum=0;
    pStCur=pStHead;
    if(pStCur->nNo==nNo)
    {
        pStCur=pStCur->pNext;
        pStHead=NULL;
        nNum++;
    }
    else
    {
        while(pStCur!=NULL)
        {
            if(pStCur->pNext->nNo==nNo&&pStCur->pNext!=NULL)
            {
                pStCur->pNext=pStCur->pNext->pNext;
                nNum++;
                break;
            }
            else
            {
                pStCur->pNext=NULL;
                nNum++;
            }
            pStCur =pStCur->pNext;
        }
    }
    if(nNum==0)
        cout<<"学号:"<<nNo<<",无该学生成绩"<<endl;
    else
        cout<<"删除成功!"<<endl;
    MessageToFile(strFilePathName3,pStCur,0);
    FreeMem(pStCur);
    return true;
}
//信息更新--------------------------------
void MessageUpdate(StudentMessage *pStHead,StudentMessage *pStCur,string strFilePathName)
{

    pStCur->pNext=NULL;
    pStCur->fComprehensive=0;
    pStCur->nBirthdate=0;
    pStCur->nAge=0;
    cout<<"姓名:"; cin>>pStCur->chName;
    cout<<"专业:"; cin>>pStCur->chCourse;
    cout<<"性别:"; cin>>pStCur->chGender;
    cout<<"出生日期:"; cin>>pStCur->nBirthdate;
    cout<<"综合成绩:"; cin>>pStCur->fComprehensive;
    cout<<"英语成绩:"; cin>>pStCur->fEnglishResults;
    MessageToFile(strFilePathName,pStHead,0);
    cout<<"修改成功!"<<endl;
}
//按学号检索-------------------------------
void InquiryByNo()
{
    //string strFilePathName;
    StudentMessage* pStHead=NULL;
    //strFilePathName=GetMessageFileName();
    pStHead =MessageFromFile(strFilePathName3);
    if(pStHead==NULL)
        return;

    StudentMessage *pStCur;
    int nNo,nNum;

    cout<<"请输入要更改的信息学生号:";
    cin>>nNo;

    nNum=0;
    pStCur=pStHead;
    while(pStCur!=NULL)
    {
        if(pStCur->nNo==nNo)
        {
            nNum++;
            MessageUpdate(pStHead,pStCur,strFilePathName3);
            break;
        }
        pStCur =pStCur->pNext;
    }

    if(nNum==0)
        cout<<"学号:"<<nNo<<",无该学生成绩"<<endl;
}
//按姓名检索学生-------------------------
int InquiryByName()
{
    cin.ignore();
    //string strFilePathName;
    StudentMessage* pStHead=NULL;
    //strFilePathName=GetMessageFileName();
    pStHead =MessageFromFile(strFilePathName3);
    int nNum;
    char chName[20];
    StudentMessage *pStCur;

    cout<<"请输入查询学生姓名:";
    cin.getline(chName,20);

    nNum=0;
    pStCur =pStHead;
    while(pStCur!=NULL)
    {
        if((strcmp(pStCur->chName,chName)==0))
        {
            nNum++;
            Display(pStCur,1,0);
        }
        pStCur=pStCur->pNext;
    }
    if(nNum==0)
                cout<<"姓名:"<<chName<<",无该学生成绩"<<endl;
    return nNum;
}
//本科生综合平均成绩、英语平均成绩----------------------------
void ResultsAverage()
{
    //string strFilePathName;
    StudentMessage* pStHead=NULL;
    //strFilePathName=GetMessageFileName();
    pStHead =MessageFromFile(strFilePathName3);
    //
    StudentMessage* pStCur=NULL;
    pStCur=pStHead;
    float fAverage=0;
    float fCSum=0;    //综合成绩和
    float fESum=0;    //英语成绩和
    int nCount=0;
    if(pStHead==NULL)
        return;
    do
    {
        if(pStCur->fEnglishResults)
        {
            fCSum=fCSum+pStCur->fComprehensive;
            fESum=fESum+pStCur->fEnglishResults;
            nCount++;
        }
    
        pStCur=pStCur->pNext;

    }while(pStCur!=NULL);
    Display(pStHead,0,0);
    cout<<"综合平均成绩:"<<setprecision(3)<<fCSum/nCount<<endl;
    cout<<"英语平均成绩:"<<setprecision(3)<<fESum/nCount<<endl;
}
//研究生按论文数量排序-----------------------------------------
    //nAscending==1:升序
    //nAscending==0:降序
void nThesisCountSort(int nAscending)
{
    //string strFilePathName;
    StudentMessage* pStHead=NULL;
    //strFilePathName=GetMessageFileName();
    pStHead =MessageFromFile(strFilePathName3);
    //
    StudentMessage*pStMax,*pStMaxPrev;
    StudentMessage*pStCur,*pStCurPrev;
    StudentMessage*pStSort=NULL;
    //
    if(pStHead==NULL||pStHead->pNext==NULL)
       return;
    while(pStHead!=NULL)
    {
        pStMaxPrev=NULL;
        pStMax    =pStHead;
        pStCurPrev=pStHead;
        pStCur    =pStCurPrev->pNext;

        //查找最大值
        while(pStCur!=NULL)
        {
            if(pStCur->nThesisCount>pStMax->nThesisCount)
            {
                pStMax =pStCur;
                pStMaxPrev=pStCurPrev;
            }
            pStCurPrev =pStCur;
            pStCur=pStCur->pNext;
        };
        //将最大(最小)节点从链表pRsHead摘出
        if(pStMaxPrev==NULL) //第一个节点
            pStHead=pStHead->pNext;
        else if(pStMax->pNext==NULL)    //最后节点
            pStMaxPrev->pNext=NULL;
        else                           //中间节点
            pStMaxPrev->pNext=pStMax->pNext;

        pStMax->pNext =NULL;

        //将最大(最小)节点插入排序链表pRsSort的前端
        if(pStSort==NULL)
        {
            pStSort=pStMax;
        }
        else
        {
            if(nAscending ==1)  //升序,次大值插入排序链表首部
            {
                pStMax->pNext=pStSort;
                pStSort=pStMax;
            }
            else             //降序,插入排序链表尾部
            {
                pStCur=pStSort;
                while(pStCur->pNext!=NULL)
                    pStCur=pStCur->pNext;
                //次大值连接到尾部
                pStCur->pNext=pStMax;
            }
        }
    }
    MessageToFile(strFilePathName3,pStSort,0);
    Display(pStSort,0,1);
}
//系统菜单--------------------------------------------------
int MenuMain()
{
    int nChoice=0;
    do
    {
        cout<<endl;
        cout<<"学生信息管理系统"<<endl;
        cout<<"1: 本科生信息增加"<<endl;
        cout<<"2: 本科生信息修改"<<endl;
        cout<<"3: 研究生信息增加"<<endl;
        cout<<"4: 研究生信息删除"<<endl;
        cout<<"5: 本科生综合平均成绩、英语平均成绩"<<endl;
        cout<<"6: 研究生论文数量排序"<<endl;
        cout<<"7: 显示全部学生信息"<<endl;
        cout<<"8: 按姓名检索学生"<<endl;
        cout<<"0: 退出"<<endl;

        cout<<"请选择功能:";
        cin>>nChoice;
    }while(nChoice<0||nChoice>8);

    return nChoice;
}
int MenuInquiry()
{
    int nChoice=0;

    do
    {
        cout<<endl;
        cout<<"    成绩查询    "<<endl;
        cout<<"1: 显示本科生成绩"<<endl;
        cout<<"2: 显示研究生成绩"<<endl;
        cout<<"0: 退出"<<endl<<endl;

        cout<<"请选择:";
        cin>>nChoice;
    }while(nChoice<0||nChoice>4);
      return nChoice;
}
//信息查询-----------------------------------------------------
bool MessageInquiry()
{
    int nChoice=0;
    /*
    string strFilePathName;
    StudentMessage* pStHead=NULL;
    //
    strFilePathName=GetMessageFileName();
    pStHead=MessageFromFile(strFilePathName);
    if(pStHead==NULL)
        return false;
    */
    do
    {
        nChoice=MenuInquiry();
        switch(nChoice)
        {
        case 0:
            break;
        case 1:    //显示本科生信息,
            MessageBrowser(0);    //0表示本科生
            break;
        case 2:
            MessageBrowser(1);    //1表示研究生
            break;
        default:
            cout<<"输入错误!";
            break;
        }
    }while(nChoice!=0);

    //FreeMem(pStHead);

    return true;
}
//--------------------------------------
//-------------系统主程序---------------
//--------------------------------------
int main()
{

    strFilePathName3=GetMessageFileName();
    int nChoice=0;
    int nNd=0;
    do
    {
        nChoice=MenuMain();
        switch(nChoice)
        {
        case 0:
            break;
        case 1:
            StudentMessageInput(0);
            break;
        case 2:
            InquiryByNo();
            break;
        case 3:
            StudentMessageInput(1);
            break;
        case 4:
            MessageDelete();
            break;
        case 5:
            ResultsAverage();
            break;
        case 6:
            //nThesisCountSort(1);
            cout<<"0   降序\n"<<"1   升序\n"<<endl;
            cin>>nNd;
            if(nNd==0||nNd==1)
                nThesisCountSort(nNd);

            else
                cout<<"输入错误!"<<endl;
            break;

               
        case 7:
            MessageInquiry();
            break;
        case 8:
            InquiryByName();
            break;
        default:
            cout<<"选择错误!"<<endl;
        }
    }while(nChoice!=0);
    return 0;
}