#ifndef ERIS_PERL_ATLAS_CONVERSION_H
#define ERIS_PERL_ATLAS_CONVERSION_H

#include <Atlas/Message/Object.h>

#include "refcount.h"

SV* AtlasToSV(const Atlas::Message::Element &obj)
{
  switch(obj.getType()) {
    case Atlas::Message::Element::TYPE_NONE:
      return NEWSV(0, 0);
    case Atlas::Message::Element::TYPE_INT:
      return newSViv(obj.asInt());
    case Atlas::Message::Element::TYPE_FLOAT:
      return newSVnv(obj.asFloat());
    case Atlas::Message::Element::TYPE_STRING:
      {
        const std::string &str = obj.asString();
        return newSVpv(str.c_str(), str.size());
      }
    case Atlas::Message::Element::TYPE_MAP:
      {
        HV *hv = newHV();
        const Atlas::Message::Element::MapType &map = obj.asMap();
        Atlas::Message::Element::MapType::const_iterator I;
        for(I = map.begin(); I != map.end(); ++I)
             hv_store(hv, I->first.c_str(), I->first.size(), AtlasToSV(I->second), 0);
        return newRV_noinc((SV*) hv);
      }
    case Atlas::Message::Element::TYPE_LIST:
      {
        AV *av = newAV();
        const Atlas::Message::Element::ListType &list = obj.asList();
        av_extend(av, list.size() - 1);
        for(I32 i; i < list.size(); ++i)
          av_store(av, i, AtlasToSV(list[i]));
        return newRV_noinc((SV*) av);
      }
    default:
      assert(false);
  }
}

namespace SigCPerl {
  inline SV* GetSV(const Atlas::Message::Element &obj) {return AtlasToSV(obj);}
}

void SVToAtlas(SV *sv, Atlas::Message::Element& obj)
{
  svtype type = (svtype) SvTYPE(sv);
  if(type == SVt_RV)
    type = (svtype) SvTYPE((SV*) SvRV(sv));

  switch(type) {
    case SVt_IV:
      obj = SvIV(sv);
      break;
    case SVt_NV:
      obj = SvNV(sv);
      break;
    case SVt_PV:
      {
        STRLEN len;
        const char *str = SvPV(sv, len);
        obj = std::string(str, len);
      }
      break;
    case SVt_PVAV:
      {
        AV* av = (AV*) SvRV(sv);
        I32 len = av_len(av);
        assert(len >= -1);
        obj = Atlas::Message::Element::ListType(len + 1);
        if(len == -1)
          break;
        assert(obj.isList());
        Atlas::Message::Element::ListType& list = obj.asList();
        for(I32 i = 0; i <= len; ++i) {
          SV **val = av_fetch(av, i, 0);
          assert(val);
          SVToAtlas(*val, list[i]);
        }
      }
      break;
    case SVt_PVHV:
      {
        HV* hv = (HV*) SvRV(sv);
        obj = Atlas::Message::Element::MapType();
	assert(obj.isMap());
	Atlas::Message::Element::MapType& map = obj.asMap();
        I32 havekeys = hv_iterinit(hv);
        while(havekeys) {
          char *key;
          SV *val = hv_iternextsv(hv, &key, &havekeys);
          SVToAtlas(val, map[key]);
        }
      }
      break;
    case SVt_NULL: // undef -> TYPE_NONE (?)
      obj = Atlas::Message::Element();
      break;
    default:
      throw Atlas::Message::WrongTypeException();
  }
}

#endif // ERIS_PERL_ATLAS_CONVERSION_H


syntax highlighted by Code2HTML, v. 0.9.1