#include "yaml-cpp/yaml.h"
#include <iostream>
#include <fstream>
#include <string>
#include <vector>

struct Vec3 {
   double x, y, z;
};

struct Power {
   std::string name;
   int damage;
};

namespace YAML {
template<>
struct convert<Vec3> {
  static Node encode(const Vec3& rhs) {
    Node node;
    node.push_back(rhs.x);
    node.push_back(rhs.y);
    node.push_back(rhs.z);
    return node;
  }

  static bool decode(const Node& node, Vec3& rhs) {
    if(!node.IsSequence() || node.size() != 3) {
      return false;
    }

    rhs.x = node[0].as<double>();
    rhs.y = node[1].as<double>();
    rhs.z = node[2].as<double>();
    return true;
  }
};

template<>
struct convert<Power> {
  static Node encode(const Power& rhs) {
    Node node;
    
  }

  static bool decode(const Node& node, Power& rhs) {
    if( !node.IsMap() || node.size() != 2) {
      return false;
    }

    rhs.name = node["name"].as<std::string>();
    rhs.damage = node["damage"].as<int>(); 
  }
};
}



struct Monster {
   std::string name;
   Vec3 position;
   std::vector <Power> powers;
};

void operator >> (const YAML::Node& node, Vec3& v) {
   v.x = node[0].as<float>();
   v.y = node[1].as<float>();
   v.z = node[2].as<float>();
}

void operator >> (const YAML::Node& node, Power& power) {
   power.name = node["name"].as<std::string>();
   power.damage = node["damage"].as<int>();
}

void operator >> (const YAML::Node& node, Monster& monster) {
   monster.name = node["name"].as<std::string>();
   //node["position"] >> monster.position;
   monster.position = node["position"].as<Vec3>();;
   const YAML::Node& powers = node["powers"];
   for(unsigned i=0;i<powers.size();i++) {
      Power power;
//      powers[i] >> power;
     power = powers[i].as<Power>(); 
      monster.powers.push_back(power);
   }
}

int main()
{
   YAML::Parser parser();
   YAML::Node doc;
   doc = YAML::LoadFile("m.yaml");
   if ( doc.IsNull() )
     std::cout << "Doc size null " << doc.size() << std::endl;
   std::cout << "Doc size " << doc.size() << std::endl;

   for( YAML::Node::const_iterator it = doc.begin(); it != doc.end(); ++it )
   {
      Monster monster;
      *it >> monster;
      std::cout << monster.name << "\n";
   }

   return 0;
}

void operator >> (const YAML::Node& node, Field f) {
IIntField::Builder bldr = IIntField::IBuilder::create();

std::string name = node["name"].as<std::string>();
int lsBit = node["lsBit"] ? node["lsBit"].as<int>() : IIntField::DFLT_LS_BIT;

  bldr.name( name );
  bldr.lsBit( lsBit );
  f = bldr.build();
}

void operator >> (const YAML::Node& node, MMIODev mmio) {
  std::string name = node["name"].as<std::string>();
  int size = node["size"].as<int>();

  mmio = IMMIO::create( name, size );
  Field f;

  const YAML::Node& registers = node["registers"];
  for( int i = 0; i < registers.size(); i++ )
  {
    int address = register[i]["address"].as<int>();
    registers[i] >> f;
    mmio->CMMIODevImpl::addAtAddress( f, address ); 
  } 
}
