#include <iostream>
#include <fstream>
#include <cstring>

using namespace std;

class Person {
public:
    Person();
    Person(char*,char*,char*,int,long);
    void writeToFile(fstream&) const;
    void readFromFile(fstream&);
    void readKey();
    int size() const {
        return 9 + nameLen + cityLen + sizeof(year) + sizeof(salary);
    }
    bool operator==(const Person& pr) const {
        return strncmp(pr.ID,ID,9) == 0;
    }
protected:
    const int nameLen, cityLen;
    char ID[10], *name, *city;
    int year;
    long salary;
    ostream& writeLegibly(ostream&);
    friend ostream& operator<<(ostream& out, Person& pr) {
        return pr.writeLegibly(out);
    }
    istream& readFromConsole(istream&);
    friend istream& operator>>(istream& in, Person& pr) {
        return pr.readFromConsole(in);
    }
};

Person::Person() : nameLen(10), cityLen(10) {
    name = new char[nameLen+1];
    city = new char[cityLen+1];
}
Person::Person(char *ID, char *n, char *c, int y, long s) :
        nameLen(10), cityLen(10) {
    name = new char[nameLen+1];
    city = new char[cityLen+1];
    strcpy(ID,ID);
    strcpy(name,n);
    strcpy(city,c);
    year = y;
    salary = s;
}
void Person::writeToFile(fstream& out) const {
    out.write(ID,9);
    out.write(name,nameLen);
    out.write(city,cityLen);
    out.write(reinterpret_cast<const char*>(&year),sizeof(int));
    out.write(reinterpret_cast<const char*>(&salary),sizeof(long));
}
void Person::readFromFile(fstream& in) {
    in.read(ID,9);
    in.read(name,nameLen);
    in.read(city,cityLen);
    in.read(reinterpret_cast<char*>(&year),sizeof(int));
    in.read(reinterpret_cast<char*>(&salary),sizeof(long));
}
void Person::readKey() {
    char s[80];
    cout << "Enter ID: ";
    cin.getline(s,80);
    strncpy(ID,s,9);
}
ostream& Person::writeLegibly(ostream& out) {
    ID[9] = name[nameLen] = city[cityLen] = '\0';
    out << "ID = " << ID << ", name = " << name
        << ", city = " << city << ", year = " << year
        << ", salary = " << salary;
    return out;
}
istream& Person::readFromConsole(istream& in) {
    ID[9] = name[nameLen] = city[cityLen] = '\0';
    char s[80];
    cout << "ID: ";
    in.getline(s,80);
    strncpy(ID,s,9);
    cout << "Name: ";
    in.getline(s,80);
    strncpy(name,s,nameLen);
    cout << "City: ";
    in.getline(s,80);
    strncpy(city,s,cityLen);
    cout << "Birthyear: ";
    in >> year;
    cout << "Salary: ";
    in >> salary;
    in.getline(s,80); // get '\n'
    return in;
}

//----------------------------------------------
#include "Person.h"

class Student : public Person {
public:
    Student();
    Student(char*,char*,char*,int,long,char*);
    void writeToFile(fstream&) const;
    void readFromFile(fstream&);
    int size() const {
        return Person::size() + majorLen;
    }
protected:
    char *major;
    const int majorLen;
    ostream& writeLegibly(ostream&);
    friend ostream& operator<<(ostream& out, Student& sr) {
        return sr.writeLegibly(out);
    }
    istream& readFromConsole(istream&);
    friend istream& operator>>(istream& in, Student& sr) {
        return sr.readFromConsole(in);
    }
};

Student::Student() : majorLen(10) {
    Person();
    major = new char[majorLen+1];
}
Student::Student(char *ssn, char *n, char *c, int y, long s, char *m) :
        majorLen(11) {
    Person(ID,n,c,y,s);
    major = new char[majorLen+1];
    strcpy(major,m);
}
void Student::writeToFile(fstream& out) const {
    Personal::writeToFile(out);
    out.write(major,majorLen);
}
void Student::readFromFile(fstream& in) {
    Personal::readFromFile(in);
    in.read(major,majorLen);
}
ostream& Student::writeLegibly(ostream& out) {
    Personal::writeLegibly(out);
    major[majorLen] = '\0';
    out << ", major = " << major;
    return out;
}
istream& Student::readFromConsole(istream& in) {
    Personal::readFromConsole(in);
    char s[80];
    cout << "Major: ";
    in.getline(s,80);
    strncpy(major,s,9);
    return in;
}

//--------------------------------------------
#include <fstream>

template<class T>
class Database {
public:
    Database();
    void run();
private:
    std::fstream database;
    char fName[20];
    std::ostream& print(std::ostream&);
    void add(T&);
    bool find(const T&);
    void modify(const T&);
    friend std::ostream& operator<<(std::ostream& out, Database& db) {
        return db.print(out);
    }
};

template<class T>
Database<T>::Database() {
}
template<class T>
void Database<T>::add(T& d) {
    database.open(fName,std::ios::in|std::ios::out|std::ios::binary);
    database.clear();
    database.seekp(0,std::ios::end);
    d.writeToFile(database);
    database.close();
}
template<class T>
void Database<T>::modify(const T& d) {
    T tmp;
    database.open(fName,std::ios::in|std::ios::out|std::ios::binary);
    database.clear();
    while (!database.eof()) {
        tmp.readFromFile(database);
        if (tmp == d) {  // overloaded ==
             std::cin >> tmp; // overloaded >>
             database.seekp(-d.size(),std::ios::cur);
             tmp.writeToFile(database);
             database.close();
             return;
        }
    }
    database.close();
    std::cout << "The record to be modified is not in the database\n";
}
template<class T>
bool Database<T>::find(const T& d) {
    T tmp;
    database.open(fName,std::ios::in|std::ios::binary);
    database.clear();
    while (!database.eof()) {
        tmp.readFromFile(database);
        if (tmp == d) { // overloaded ==
            database.close();
            return true;
        }
    }
    database.close();
    return false;
}
template<class T>
std::ostream& Database<T>::print(std::ostream& out) {
    T tmp;
    database.open(fName,std::ios::in|std::ios::binary);
    database.clear();
    while (true) {
        tmp.readFromFile(database);
        if (database.eof())
            break;
        out << tmp << std::endl; // overloaded <<
    }
    database.close();
    return out;
}
template<class T>
void Database<T>::run() {
    std::cout << "File name: ";
    std::cin >> fName;
    std::cin.ignore();	// skip '\n';
    database.open(fName,std::ios::in);
    if (database.fail())
        database.open(fName,std::ios::out);
    database.close();
    char option[5];
    T rec;
    std::cout << "1. Add 2. Find 3. Modify a record; 4. Exit\n";
    std::cout << "Enter an option: ";
    while (std::cin.getline(option,5)) {
        if (*option == '1') {
             std::cin >> rec;   // overloaded >>
             add(rec);
        }
        else if (*option == '2') {
             rec.readKey();
             std::cout << "The record is ";
             if (find(rec) == false)
                 std::cout << "not ";
             std::cout << "in the database\n";
        }
        else if (*option == '3') {
             rec.readKey();
             modify(rec);
        }
        else if (*option != '4')
             std::cout << "Wrong option\n";
        else return;
        std::cout << *this;   // overloaded <<
        std::cout << "Enter an option: ";
    }
}

//----------------------------------------
#include <iostream>
#include "Person.h"
#include "Database.h"
using namespace std;

int main() {
    Database<Person>().run();
//  Database<Student>().run();
    return 0;
}