// file      : boost/employee.hxx
// copyright : not copyrighted - public domain

#ifndef EMPLOYEE_HXX
#define EMPLOYEE_HXX

#include <vector>
#include <string>

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/optional.hpp>
#include <boost/unordered_set.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>

#include <odb/core.hxx>

#include <odb/boost/lazy-ptr.hxx>

using boost::shared_ptr;
using boost::weak_ptr;

using odb::boost::lazy_shared_ptr;
using odb::boost::lazy_weak_ptr;

using boost::uuids::uuid;
using boost::gregorian::date;

// Forward declarations.
//
class employer;
class employee;

using emails = boost::unordered_set<std::string>;
using employees = std::vector<lazy_weak_ptr<employee>>;

#pragma db object
class employer
{
public:
  employer (const std::string& name)
      : name_ (name)
  {
  }

  const std::string&
  name () const
  {
    return name_;
  }

  // Employees of this employer.
  //
  using employees_type = ::employees;

  const employees_type&
  employees () const
  {
    return employees_;
  }

  employees_type&
  employees ()
  {
    return employees_;
  }

private:
  friend class odb::access;

  employer () {}

  #pragma db id
  std::string name_;

  #pragma db value_not_null inverse(employer_)
  employees_type employees_;
};

#pragma db object
class employee
{
public:
  using employer_type = ::employer;

  employee (const std::string& first,
            const std::string& last,
            const date& born,
            shared_ptr<employer_type> employer)
      : id_ (boost::uuids::random_generator () ()),
        first_ (first), last_ (last),
        born_ (born),
        employer_ (employer)
  {
  }

  employee (const std::string& first,
            const std::string& middle,
            const std::string& last,
            const date& born,
            shared_ptr<employer_type> employer)
      : id_ (boost::uuids::random_generator () ()),
        first_ (first), middle_ (middle), last_ (last),
        born_ (born),
        employer_ (employer)
  {
  }

  // Id.
  //
  const uuid&
  id () const
  {
    return id_;
  }

  // Name.
  //
  const std::string&
  first () const
  {
    return first_;
  }

  const boost::optional<std::string>&
  middle () const
  {
    return middle_;
  }

  const std::string&
  last () const
  {
    return last_;
  }

  // Date of birth.
  //
  const date&
  born () const
  {
    return born_;
  }

  // Emails.
  //
  using emails_type = ::emails;

  const emails_type&
  emails () const
  {
    return emails_;
  }

  emails_type&
  emails ()
  {
    return emails_;
  }

  // Employer.
  //
  shared_ptr<employer_type>
  employer () const
  {
    return employer_;
  }

  void
  employer (shared_ptr<employer_type> employer)
  {
    employer_ = employer;
  }

private:
  friend class odb::access;

  employee () {}

  #pragma db id
  uuid id_;

  std::string first_;
  boost::optional<std::string> middle_;
  std::string last_;

  date born_;
  emails_type emails_;

  #pragma db not_null
  shared_ptr<employer_type> employer_;
};

#endif // EMPLOYEE_HXX
