
#include <string>
#include "base/user_info.h"

using std::string;
using namespace std;
using namespace bdm;

class Passenger : public bdmroot
{
public:

  Passenger() {
  }
};

class Human : public Passenger
{
public:
  string name;

  Human() {
    name = "none";
  }

  virtual void from_setting(const Setting &set) {
    set.lookupValue("name", name);
  }

  virtual void to_setting(Setting &set) const {
    Setting &name_setting = set.add("name", Setting::TypeString);
    name_setting = name;
  }

  string to_string() {
    return name;
  }
};

UIREGISTER(Human);

class Robot : public Passenger
{
public:
  int number;
  Array<string> software;

  Robot() : software() {
    number = -1;
  }

  virtual void from_setting(const Setting &set) {
    set.lookupValue("number", number);
	if( set.exists( "software" ) )
		UI::get(software, set, "software");
  }

  virtual void to_setting(Setting &set) const {
    Setting &number_setting = set.add("number", Setting::TypeInt);
    number_setting = number;

    UI::save(software, set, "software");
  }

  string to_string() {
    stringstream stream;
    stream << number;
    for (int i = 0; i < software.length(); i++)
      stream << "_" + software(i);
    return stream.str();
  }
};

UIREGISTER(Robot);

class Transport : public bdmroot
{
public:
  int year;
  string manufacturer;

  Transport() {
    year = 1900;
    manufacturer = "unknown";
  }

  Transport(int year, string manufacturer)
      : year(year), manufacturer(manufacturer) {
  }

  virtual void from_setting(const Setting &set) {
    set.lookupValue("year", year);
    set.lookupValue("manufacturer", manufacturer);
  }

  virtual void to_setting(Setting &set) const {
    Setting &year_setting = set.add("year", Setting::TypeInt);
    year_setting = year;

    Setting &manufacturer_setting = set.add("manufacturer", Setting::TypeString);
    manufacturer_setting = manufacturer;
  }
};

class Car : public Transport
{
public:
  int kilometers;
  Array<Passenger*> passengers;

  Car() : Transport() {
    kilometers = 0;
  }


  Car(int year, string manufacturer, int kilometers)
      : Transport(year, manufacturer), kilometers(kilometers) {
  }

  virtual void from_setting(const Setting &set) {
    Transport::from_setting(set);

    set.lookupValue("kilometers", kilometers);

	if( set.exists( "passengers" ) )
	    UI::get(passengers, set, "passengers");
  }

  virtual void to_setting(Setting &set) const {
    Transport::to_setting(set);

    Setting &kilometers_setting = set.add("kilometers", Setting::TypeInt);
    kilometers_setting = kilometers;

    UI::save(passengers, set, "passengers");
  }

  string to_string() {
    stringstream stream;
    stream << "A car made in " << year << " by " << manufacturer << ", having " << kilometers << " kilometers on the clock.";
    if (passengers.length()) {
      stream << "The names of passengers are as follows: ";
      for (int i = 0; i < passengers.length(); i++)
        stream << passengers(i)->to_string() << " ";
    }
    return stream.str();
  }
};

UIREGISTER(Car);

class Bike : public Transport
{
public:
  bool electricLights;
  mat matr;

  Bike() : Transport(), matr("2,2;3,4") {
    electricLights = false;
  }

  Bike(int year, string manufacturer, bool electricLights)
      : Transport(year, manufacturer), electricLights(electricLights) {
  }

  ~Bike() {
  }

  void from_setting(const Setting &set) {
    Transport::from_setting(set);

    set.lookupValue("electricLights", electricLights);

	UI::get(matr, set, "matr");
  }

  void to_setting(Setting &set) const {
    Transport::to_setting(set);

    Setting &electricLights_setting = set.add("electricLights", Setting::TypeBoolean);
    electricLights_setting = electricLights;

    UI::save(matr, set, "matr");
  }

  string to_string() {
    stringstream stream;
    stream << "a bike made in " << year << " by " << manufacturer;
    if (electricLights) stream << " with electric lights included";
    return stream.str();
  }
};

UIREGISTER(Bike);

int main()
{
  //////////////////////////////////// LOADING ////////////////////////////////
  UI_File in("test_user_info_input.cfg");
  Transport *pepikovo = UI::build<Transport>(in, "pepikovo");
  cout << "pepikovo: " << pepikovo->to_string() << endl;
  Transport *jardovo = UI::build<Transport>(in, "jardovo");
  cout << "jardovo: " << jardovo->to_string() << endl;
  Transport *ondrejovo = UI::build<Transport>(in, "ondrejovo");
  cout << "ondrejovo: " << ondrejovo->to_string() << endl;
  Transport *elisky = UI::build<Transport>(in, "elisky");
  cout << "elisky: " << elisky->to_string() << endl;
  Transport *kati = UI::build<Transport>(in, "kati");
  cout << "kati: " << kati->to_string() << endl;
  cout << endl << "press any key to continue..." << endl;
  getchar();

  /////////////////////////////////// SAVING //////////////////////////

  Car audi(1968, "zyl", 200);
  Car liaz(1989, "skoda", 1000);
  Bike author(2001, "noname", false);
  UI_File out;

  UI::save(&audi, out, "marty");
  UI::save(&liaz, out, "bohousovo");
  UI::save(&author, out, "karlovo");
  UI::save(pepikovo, out, "pepikovo");
  out.save("testUI_out.cfg");

  cout << "all the transport means were saved correctly" << endl;
  cout << endl << "press any key to end the program" << endl;
  getchar();
  return 0;
}
