// This file is part of the Coral project.
// Please read the copyright notice in the LICENSE file.

#include "simple_lang_creator.h"
#include <coral/core/CorePrimitives.h>

#include <iostream>

namespace coral { namespace util { namespace mmcreator {
	namespace {
		autounref<AbstractElementDefinition>
		getElementWithDoubleColon(Package* p,
					  const char* name) {
			const char* dcolon = strstr(name, "::");
			if (!dcolon || dcolon == name) {
				return p->getElement(name);
			}
			std::string mm(name, dcolon - name);
			name = dcolon + 2;
			if (mm == "CORE") {
				p = CORE::language;
			} else {
				std::cerr << "Can't support "
					  << mm << "." << std::endl;
				coral_assert(0);
			}
			return p->getElement(name);
		}
	}


    void create_elems(Language* metamodel,
		      const Enumeration** list_of_enums,
		      const Datatype* list_of_dtypes,
		      const Element* list_of_elems,
		      const SubAndSuper* list_of_structure,
		      const Feature* list_of_slots
		      ) {
	    coral_assert(metamodel);
	    coral_assert(list_of_enums);
	    coral_assert(list_of_elems);
	    coral_assert(list_of_dtypes);
	    coral_assert(list_of_structure);
	    coral_assert(list_of_slots);

      /*
       * Create enumerations
       */
      for (const Enumeration** p = list_of_enums;
	   *p != NULL;
	   ++p) {
	const Enumeration* i = *p;
	coral_assert(i->ptr);
	//coral_assert(i->type); /* We don't have MOF yet.. */
	coral_assert(i->name);
	coral_assert(i->enumerations);
	coral::EnumerationDefinition* ptr = new coral::EnumerationDefinition(metamodel, i->name);
	*(i->ptr) = ptr;
	for (const char** ccenum = i->enumerations;
	     *ccenum != NULL;
	     ++ccenum) {
	  ptr->__addEnum__(*ccenum);
	}
      }


      /*
       * Create Datatypes
       */
      //dlog << DEBUGLEVEL_DEBUG << "Create datatypes..." << std::endl;
      for (const Datatype* p = list_of_dtypes;
	   p->ptr != NULL;
	   ++p) {
	coral_assert(p->ptr);
	//coral_assert(i->type); /* We don't have MOF yet.. */
	coral_assert(p->name);
	*(p->ptr) = new coral::DatatypeDefinition(metamodel, p->name);
      }

      /*
       * Create elements
       */
      //dlog << DEBUGLEVEL_DEBUG << "Create elements..." << std::endl;
      for (const Element* p = list_of_elems;
	   p->ptr != NULL;
	   ++p) {
	const Element* i = p;
	coral_assert(i->ptr);
	//coral_assert(i->type); /* We don't have MOF yet.. */
	coral_assert(i->name);
	*(i->ptr) = new coral::ElementDefinition(metamodel, i->name);
      }

      /*
       * Create sub/superclass structure
       */
      //dlog << DEBUGLEVEL_DEBUG << "Create sub/super..." << std::endl;
      for (const SubAndSuper* p = list_of_structure;
	   p->sub != NULL;
	   ++p) {
	const SubAndSuper* i = p;
	coral_assert(i->sub);
	coral_assert(i->super);
	autounref<coral::AbstractElementDefinition> sub
		= getElementWithDoubleColon(metamodel, i->sub);
	autounref<coral::AbstractElementDefinition> super
		= getElementWithDoubleColon(metamodel, i->super);
	coral_assert(sub.get());
	coral_assert(super.get());
	sub->addSuperclass(super.get());
      }

      /*
       * Create slots, and connect them
       */
      //dlog << DEBUGLEVEL_DEBUG << "Create slots..." << std::endl;
      for (const Feature* p = list_of_slots;
	   p->from_element != NULL;
	   ++p) {
	const Feature* i = p;

	autounref<coral::AbstractElementDefinition> from;
	autounref<coral::AbstractElementDefinition> to;

	/*
	 * This will also look in appropriate languages
	 * using the LANG::Element syntax.
	 */
	from = getElementWithDoubleColon(metamodel, i->from_element);
	to = getElementWithDoubleColon(metamodel, i->element_kind);

	if (!from)
		dlog << DEBUGLEVEL_DEBUG << "ARGH I can't find " << i->from_element << std::endl;
	if (!to)
		dlog << DEBUGLEVEL_DEBUG << "ARGH I can't find " << i->element_kind << std::endl;

	coral_assert(from.get() && to.get());

	kind_t k = i->kind;
	coral::Property* f =
		new coral::Property(
			i->key,
			to.get(),
			i->other_key,
			i->mult_lower,
			i->mult_upper,
			k);
	coral::autounref<ref_counted> _t(f);
	coral_assert(!from->isDatatypeDefinition());
	coral::ElementDefinition* ed =
		dynamic_cast<coral::ElementDefinition*>(from.get());
	coral_assert(ed);
	ed->addPropertyRecursive(f);
      }


    }

} } }

