//static
CLayout * SBMLDocumentLoader::createLayout(const Layout & sbmlLayout,
    const std::map<std::string, std::string> & modelmap,
    std::map<std::string, std::string> & layoutmap
#ifdef USE_CRENDER_EXTENSION
    , const std::map<std::string, std::string>& globalIdToKeyMap
    //,const std::map<std::string,std::map<std::string,std::string> >& globalColorIdToKeyMapMap
    //,const std::map<std::string,std::map<std::string,std::string> >& globalGradientIdToKeyMapMap
    //,const std::map<std::string,std::map<std::string,std::string> >& globalLineEndingIdToKeyMapMap
#endif /* USE_CRENDER_EXTENSION */
    , const CCopasiContainer * pParent
                                          )
{
  CLayout* layout = new CLayout(sbmlLayout, layoutmap, pParent);

  //compartments
  unsigned C_INT32 i, iMax = sbmlLayout.getListOfCompartmentGlyphs()->size();

  for (i = 0; i < iMax; ++i)
    {
      const CompartmentGlyph* tmp
        = dynamic_cast<const CompartmentGlyph*>(sbmlLayout.getListOfCompartmentGlyphs()->get(i));

      if (tmp)
        layout->addCompartmentGlyph(new CLCompartmentGlyph(*tmp, modelmap, layoutmap));
    }

  //species
  iMax = sbmlLayout.getListOfSpeciesGlyphs()->size();

  for (i = 0; i < iMax; ++i)
    {
      const SpeciesGlyph* tmp
        = dynamic_cast<const SpeciesGlyph*>(sbmlLayout.getListOfSpeciesGlyphs()->get(i));

      if (tmp)
        layout->addMetaboliteGlyph(new CLMetabGlyph(*tmp, modelmap, layoutmap));
    }

  //reactions
  iMax = sbmlLayout.getListOfReactionGlyphs()->size();

  for (i = 0; i < iMax; ++i)
    {
      const ReactionGlyph* tmp
        = dynamic_cast<const ReactionGlyph*>(sbmlLayout.getListOfReactionGlyphs()->get(i));

      if (tmp)
        layout->addReactionGlyph(new CLReactionGlyph(*tmp, modelmap, layoutmap));
    }

  //text
  iMax = sbmlLayout.getListOfTextGlyphs()->size();

  for (i = 0; i < iMax; ++i)
    {
      const TextGlyph* tmp
        = dynamic_cast<const TextGlyph*>(sbmlLayout.getListOfTextGlyphs()->get(i));

      if (tmp)
        layout->addTextGlyph(new CLTextGlyph(*tmp, modelmap, layoutmap));
    }

  //additional
  iMax = sbmlLayout.getListOfAdditionalGraphicalObjects()->size();

  for (i = 0; i < iMax; ++i)
    {
      const GraphicalObject* graphical
        = dynamic_cast<const GraphicalObject*>(sbmlLayout.getListOfAdditionalGraphicalObjects()->get(i));

      if (graphical)
        layout->addGeneralGlyph(new CLGeneralGlyph(*graphical, modelmap, layoutmap));
    }

  //second pass text (the text glyph can refer to other glyphs. These references can)
  //only be resolved after all glyphs are created).
  iMax = sbmlLayout.getListOfTextGlyphs()->size();

  for (i = 0; i < iMax; ++i)
    {
      const TextGlyph* tmp
        = dynamic_cast<const TextGlyph*>(sbmlLayout.getListOfTextGlyphs()->get(i));

      if (tmp)
        postprocessTextGlyph(*tmp, layoutmap);
    }

#ifdef USE_CRENDER_EXTENSION
  RenderLayoutPlugin* rlPlugin = (RenderLayoutPlugin*) sbmlLayout.getPlugin("render");
  assert(rlPlugin != NULL);

  // import the local render information
  iMax = rlPlugin->getNumLocalRenderInformationObjects();
  std::map<std::string, std::string> idToKeyMap;
  CLLocalRenderInformation* pLRI = NULL;

  //std::map<std::string,std::string> colorIdToKeyMap;
  //std::map<std::string,std::string> gradientIdToKeyMap;
  //std::map<std::string,std::string> lineEndingIdToKeyMap;
  //std::map<std::string,std::map<std::string,std::string> > colorIdToKeyMapMap;
  //std::map<std::string,std::map<std::string,std::string> > gradientIdToKeyMapMap;
  //std::map<std::string,std::map<std::string,std::string> > lineEndingIdToKeyMapMap;
  for (i = 0; i < iMax; ++i)
    {
      //colorIdToKeyMap.clear();
      //gradientIdToKeyMap.clear();
      //lineEndingIdToKeyMap.clear();
      //pLRI=new CLLocalRenderInformation(*sbmlLayout.getRenderInformation(i),colorIdToKeyMap,gradientIdToKeyMap,lineEndingIdToKeyMap,layout);
      pLRI = new CLLocalRenderInformation(*rlPlugin->getRenderInformation(i), layout);

      if (rlPlugin->getRenderInformation(i)->isSetId())
        idToKeyMap.insert(std::pair<std::string, std::string>(rlPlugin->getRenderInformation(i)->getId(), pLRI->getKey()));
      else
        idToKeyMap.insert(std::pair<std::string, std::string>(pLRI->getKey(), pLRI->getKey()));

      //colorIdToKeyMapMap.insert(std::pair<std::string,std::map<std::string,std::string> >(pLRI->getKey(),colorIdToKeyMap));
      //gradientIdToKeyMapMap.insert(std::pair<std::string,std::map<std::string,std::string> >(pLRI->getKey(),gradientIdToKeyMap));
      //lineEndingIdToKeyMapMap.insert(std::pair<std::string,std::map<std::string,std::string> >(pLRI->getKey(),lineEndingIdToKeyMap));
      // fix the references to layout objects in id lists
      size_t j, jMax = pLRI->getNumStyles();

      for (j = 0; j < jMax; j++)
        {
          SBMLDocumentLoader::convertLayoutObjectIds(*(pLRI->getStyle(j)), layoutmap);
        }

      layout->addLocalRenderInformation(pLRI);
    }

  // fix the references
  // we have to consider the global ids as well
  // since all ids in these two map should be unique, we can just combine them
  size_t count = idToKeyMap.size() + globalIdToKeyMap.size();
  idToKeyMap.insert(globalIdToKeyMap.begin(), globalIdToKeyMap.end());
  // make sure the ids were really unique
  assert(idToKeyMap.size() == count);
  SBMLDocumentLoader::convertRenderInformationReferencesIds<CLLocalRenderInformation>(layout->getListOfLocalRenderInformationObjects(), idToKeyMap);
  // fix the color ids, gradient ids and line ending ids.
  /*
  std::map<std::string,std::map<std::string,std::string> >::const_iterator mapPos;
  std::map<std::string,std::map<std::string,std::string> > expandedColorIdToKeyMapMap, expandedGradientIdToKeyMapMap, expandedLineEndingIdToKeyMapMap;
  for(i=0;i < iMax; ++i)
  {
      pLRI=dynamic_cast<CLLocalRenderInformation*>(layout->getRenderInformation(i));
      assert(pLRI != NULL);

      std::set<std::string> chain;
      SBMLDocumentLoader::expandIdToKeyMaps<CLLocalRenderInformation>(pLRI,
                         layout->getListOfLocalRenderInformationObjects(),
                         expandedColorIdToKeyMapMap,
                         expandedGradientIdToKeyMapMap,
                         expandedLineEndingIdToKeyMapMap,
                         colorIdToKeyMapMap,
                         gradientIdToKeyMapMap,
                         lineEndingIdToKeyMapMap,
                         chain,
                         globalColorIdToKeyMapMap,
                         globalGradientIdToKeyMapMap,
                         globalLineEndingIdToKeyMapMap
                         );
      SBMLDocumentLoader::convertPropertyKeys<CLLocalRenderInformation>(pLRI,expandedColorIdToKeyMapMap[pLRI->getKey()],expandedGradientIdToKeyMapMap[pLRI->getKey()],expandedLineEndingIdToKeyMapMap[pLRI->getKey()]);
  }
  */
#endif /* USE_CRENDER_EXTENSION */

  return layout;
}
CLayout* CCopasiSpringLayout::createLayout(
  CDataContainer *parent,
  const std::set<const CCompartment*>& compartments,
  const std::set<const CReaction*>& reactions,
  const std::set<const CMetab*>& metabs,
  const std::set<const CMetab*>& sideMetabs,
  Parameters* mParams
)
{
  CLayout *pResult = new CLayout("Layout", parent);

  double fontSize = 16.0;
  double fontHeight = fontSize * 1.5;

  // create a species glyph for each species in metabs

  std::map<const CCompartment*, CompartmentInfo> compInfo;
  std::map<const CMetab*, CLMetabGlyph*> metabMap;

  std::set<const CMetab*>::const_iterator metabIt;

  for (metabIt = metabs.begin(); metabIt != metabs.end(); ++metabIt)
    {
      if (sideMetabs.find(*metabIt) != sideMetabs.end())
        continue;

      //estimate the size of the glyph
      double width = (double)((*metabIt)->getObjectName().length() * fontSize);
      double height = (double)fontHeight;

      if (width < height)
        {
          width = height;
        }

      //create the glyph
      CLMetabGlyph* pMetabGlyph = new CLMetabGlyph;
      pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4));
      pMetabGlyph->setModelObjectKey((*metabIt)->getKey());

      pResult->addMetaboliteGlyph(pMetabGlyph);
      metabMap[*metabIt] = pMetabGlyph;

      //create the text glyph for the label
      CLTextGlyph* pTextGlyph = new CLTextGlyph;
      pTextGlyph->setDimensions(CLDimensions(width, height));
      pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey());
      pTextGlyph->setModelObjectKey((*metabIt)->getKey());

      pResult->addTextGlyph(pTextGlyph);

      //add up the sizes for the compartment
      const CCompartment* pComp = NULL;

      if (compartments.find((*metabIt)->getCompartment()) != compartments.end())
        pComp = (*metabIt)->getCompartment();

      compInfo[pComp].add((width + 4) * (height + 4));
    }

  //now the reaction glyphs
  std::set<const CReaction*>::const_iterator reactIt;

  for (reactIt = reactions.begin(); reactIt != reactions.end(); ++reactIt)
    {
      CLReactionGlyph* pReactionGlyph = new CLReactionGlyph;
      //pResult->setDimensions(CLDimensions(width, height));
      pReactionGlyph->setModelObjectKey((*reactIt)->getKey());
      //pReactionGlyph->getCurve().addCurveSegment(CLLineSegment(CLPoint(x, y),
      //                                             CLPoint(x + length, y)));
      bool isReversible = (*reactIt)->isReversible();
      pResult->addReactionGlyph(pReactionGlyph);

      //now add the species reference glyphs.

      //substrates
      const CDataVector < CChemEqElement >& substrates = (*reactIt)->getChemEq().getSubstrates();
      bool substrateExists = false;
      CDataVector<CChemEqElement>::const_iterator elIt;

      for (elIt = substrates.begin(); elIt != substrates.end(); ++elIt)
        {
          const CMetab* pMetab = elIt->getMetabolite();

          if (!pMetab)
            continue;

          CLMetabGlyph* pMetabGlyph = NULL;
          CLMetabReferenceGlyph::Role role; // = CLMetabReferenceGlyph::SUBSTRATE;
          CLMetabReferenceGlyph::Role functionalRole;

          //is it a side reactant? If yes, create a new metab glyph
          if (sideMetabs.find(pMetab) != sideMetabs.end())
            {
              //estimate the size of the glyph
              double width = (double)((pMetab)->getObjectName().length() * fontSize);
              double height = (double)fontHeight;

              if (width < height)
                {
                  width = height;
                }

              //create the glyph
              pMetabGlyph = new CLMetabGlyph;
              pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4));
              pMetabGlyph->setModelObjectKey(pMetab->getKey());
              //TODO: mark as duplicate
              pResult->addMetaboliteGlyph(pMetabGlyph);

              //create the text glyph for the label
              CLTextGlyph* pTextGlyph = new CLTextGlyph;
              pTextGlyph->setDimensions(CLDimensions(width, height));
              pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey());
              pTextGlyph->setModelObjectKey(pMetab->getKey());

              pResult->addTextGlyph(pTextGlyph);

              //add up the sizes for the compartment
              const CCompartment* pComp = NULL;

              if (compartments.find(pMetab->getCompartment()) != compartments.end())
                pComp = pMetab->getCompartment();

              compInfo[pComp].add((width + 4) * (height + 4));

              role = isReversible
                     ? CLMetabReferenceGlyph::SIDEPRODUCT
                     : CLMetabReferenceGlyph::SIDESUBSTRATE;
              functionalRole = CLMetabReferenceGlyph::SIDESUBSTRATE;
            }
          else
            {
              //find the existing metab glyph
              std::map<const CMetab*, CLMetabGlyph*>::const_iterator mmIt;
              mmIt = metabMap.find(pMetab);

              if (mmIt != metabMap.end())
                pMetabGlyph = mmIt->second;

              role = isReversible
                     ? CLMetabReferenceGlyph::PRODUCT
                     : CLMetabReferenceGlyph::SUBSTRATE;
              functionalRole = CLMetabReferenceGlyph::SUBSTRATE;
            }

          if (!pMetabGlyph)
            continue;

          CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph;
          //pResult->setModelObjectKey(modelobjectkey);
          pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey());
          pRefGlyph->setRole(role);
          pRefGlyph->setFunctionalRole(functionalRole);
          pReactionGlyph->addMetabReferenceGlyph(pRefGlyph);
          substrateExists = true;
        } //substrates

      // if we have no substrates, add a dummy / invisible node for now
      if (!substrateExists)
        {
          CLMetabGlyph* pMetabGlyph = new CLMetabGlyph;
          pMetabGlyph->setDimensions(CLDimensions(1, 1));
          pMetabGlyph->setObjectRole("invisible");
          pResult->addMetaboliteGlyph(pMetabGlyph);

          CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph;
          //pResult->setModelObjectKey(modelobjectkey);
          pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey());
          pRefGlyph->setRole(CLMetabReferenceGlyph::SUBSTRATE); //TODO side substr?
          pRefGlyph->setFunctionalRole(CLMetabReferenceGlyph::SUBSTRATE);
          pReactionGlyph->addMetabReferenceGlyph(pRefGlyph);
        }

      //products
      const CDataVector < CChemEqElement >& products = (*reactIt)->getChemEq().getProducts();
      bool productExists = false;

      for (elIt = products.begin(); elIt != products.end(); ++elIt)
        {
          const CMetab* pMetab = elIt->getMetabolite();

          if (!pMetab)
            continue;

          CLMetabGlyph* pMetabGlyph = NULL;
          CLMetabReferenceGlyph::Role role; // = CLMetabReferenceGlyph::SUBSTRATE;
          CLMetabReferenceGlyph::Role functionalRole;

          //is it a side reactant? If yes, create a new metab glyph
          if (sideMetabs.find(pMetab) != sideMetabs.end())
            {
              //estimate the size of the glyph
              double width = (double)((pMetab)->getObjectName().length() * fontSize);
              double height = (double)fontHeight;

              if (width < height)
                {
                  width = height;
                }

              //create the glyph
              pMetabGlyph = new CLMetabGlyph;
              pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4));
              pMetabGlyph->setModelObjectKey(pMetab->getKey());
              //TODO: mark as duplicate
              pResult->addMetaboliteGlyph(pMetabGlyph);

              //create the text glyph for the label
              CLTextGlyph* pTextGlyph = new CLTextGlyph;
              pTextGlyph->setDimensions(CLDimensions(width, height));
              pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey());
              pTextGlyph->setModelObjectKey(pMetab->getKey());

              pResult->addTextGlyph(pTextGlyph);

              //add up the sizes for the compartment
              const CCompartment* pComp = NULL;

              if (compartments.find(pMetab->getCompartment()) != compartments.end())
                pComp = pMetab->getCompartment();

              compInfo[pComp].add((width + 4) * (height + 4));

              role = CLMetabReferenceGlyph::SIDEPRODUCT;
              functionalRole = CLMetabReferenceGlyph::SIDEPRODUCT;
            }
          else
            {
              //find the existing metab glyph
              std::map<const CMetab*, CLMetabGlyph*>::const_iterator mmIt;
              mmIt = metabMap.find(pMetab);

              if (mmIt != metabMap.end())
                pMetabGlyph = mmIt->second;

              role = CLMetabReferenceGlyph::PRODUCT;
              functionalRole = CLMetabReferenceGlyph::PRODUCT;
            }

          if (!pMetabGlyph)
            continue;

          CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph;
          //pResult->setModelObjectKey(modelobjectkey);
          pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey());
          pRefGlyph->setRole(role);
          pRefGlyph->setFunctionalRole(functionalRole);
          pReactionGlyph->addMetabReferenceGlyph(pRefGlyph);
          productExists = true;
        } //products

      // if we have no substrates, add a dummy / invisible node for now
      if (!productExists)
        {
          CLMetabGlyph* pMetabGlyph = new CLMetabGlyph;
          pMetabGlyph->setDimensions(CLDimensions(1, 1));
          pMetabGlyph->setObjectRole("invisible");
          pResult->addMetaboliteGlyph(pMetabGlyph);

          CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph;
          //pResult->setModelObjectKey(modelobjectkey);
          pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey());
          pRefGlyph->setRole(CLMetabReferenceGlyph::PRODUCT); //TODO side substr?
          pReactionGlyph->addMetabReferenceGlyph(pRefGlyph);
        }

      //modifiers
      const CDataVector < CChemEqElement >& modifiers = (*reactIt)->getChemEq().getModifiers();

      for (elIt = modifiers.begin(); elIt != modifiers.end(); ++elIt)
        {
          const CMetab* pMetab = elIt->getMetabolite();

          if (!pMetab)
            continue;

          CLMetabGlyph* pMetabGlyph = NULL;
          CLMetabReferenceGlyph::Role role; // = CLMetabReferenceGlyph::SUBSTRATE;

          //is it a side reactant? If yes, create a new metab glyph
          if (sideMetabs.find(pMetab) != sideMetabs.end())
            {
              //estimate the size of the glyph
              double width = (double)((pMetab)->getObjectName().length() * fontSize);
              double height = (double)fontHeight;

              if (width < height)
                {
                  width = height;
                }

              //create the glyph
              pMetabGlyph = new CLMetabGlyph;
              pMetabGlyph->setDimensions(CLDimensions(width + 4, height + 4));
              pMetabGlyph->setModelObjectKey(pMetab->getKey());
              //TODO: mark as duplicate
              pResult->addMetaboliteGlyph(pMetabGlyph);

              //create the text glyph for the label
              CLTextGlyph* pTextGlyph = new CLTextGlyph;
              pTextGlyph->setDimensions(CLDimensions(width, height));
              pTextGlyph->setGraphicalObjectKey(pMetabGlyph->getKey());
              pTextGlyph->setModelObjectKey(pMetab->getKey());

              pResult->addTextGlyph(pTextGlyph);

              //add up the sizes for the compartment
              const CCompartment* pComp = NULL;

              if (compartments.find(pMetab->getCompartment()) != compartments.end())
                pComp = pMetab->getCompartment();

              compInfo[pComp].add((width + 4) * (height + 4));

              role = CLMetabReferenceGlyph::MODIFIER; //TODO SIDEMODIFIER???
            }
          else
            {
              //find the existing metab glyph
              std::map<const CMetab*, CLMetabGlyph*>::const_iterator mmIt;
              mmIt = metabMap.find(pMetab);

              if (mmIt != metabMap.end())
                pMetabGlyph = mmIt->second;

              role = CLMetabReferenceGlyph::MODIFIER;
            }

          if (!pMetabGlyph)
            continue;

          CLMetabReferenceGlyph* pRefGlyph = new CLMetabReferenceGlyph;
          //pResult->setModelObjectKey(modelobjectkey);
          pRefGlyph->setMetabGlyphKey(pMetabGlyph->getKey());
          pRefGlyph->setRole(role);
          pReactionGlyph->addMetabReferenceGlyph(pRefGlyph);
        } //modifiers
    } //reactions

  //rules
  size_t i;

  for (i = 0; i < pResult->getListOfMetaboliteGlyphs().size(); ++i)
    {
      const CLMetabGlyph* pMetabGlyph = &pResult->getListOfMetaboliteGlyphs()[i];
      const CMetab* pMetab = dynamic_cast<const CMetab*>(pMetabGlyph->getModelObject());

      if (!pMetab)
        continue;

      if (pMetab->getStatus() == CModelEntity::Status::ODE || pMetab->getStatus() == CModelEntity::Status::ASSIGNMENT)
        {
          CLGeneralGlyph* pGG = new CLGeneralGlyph;
          pGG->setDimensions(CLDimensions(10, 10));
          pGG->setObjectRole("rule");

          pResult->addGeneralGlyph(pGG);

          CLReferenceGlyph* pRefGlyph = new CLReferenceGlyph;
          pRefGlyph->setDimensions(CLDimensions(10, 10));
          pRefGlyph->setTargetGlyphKey(pMetabGlyph->getKey());
          pRefGlyph->setRole("rule connection");
          pGG->addReferenceGlyph(pRefGlyph);
        }
    }

  //after all other glyphs are created, create the compartment glyphs
  double xxx = 0;
  std::set<const CCompartment*>::const_iterator compIt;

  for (compIt = compartments.begin(); compIt != compartments.end(); ++compIt)
    {
      double compSize = 10000;
      std::map<const CCompartment*, CompartmentInfo>::const_iterator ccIt;
      ccIt = compInfo.find(*compIt);

      if (ccIt != compInfo.end())
        {
          //some glyphs are placed inside this compartment glyph
          compSize = ccIt->second.mAreaSum * 40;
        }

      //create the glyph
      CLCompartmentGlyph* pCompGlyph = new CLCompartmentGlyph;
      pCompGlyph->setModelObjectKey((*compIt)->getKey());
      pCompGlyph->setDimensions(CLDimensions(CLDimensions(sqrt(compSize), sqrt(compSize))));
      pCompGlyph->setPosition(CLPoint(xxx, 5));
      xxx += sqrt(compSize) + 10;

      pResult->addCompartmentGlyph(pCompGlyph);
    }

  //
  // double sss = sqrt(compInfo[NULL].mAreaSum * 40);
  //
  // // determine and set the layout dimensions
  // CLBoundingBox box = pResult->calculateBoundingBox();
  // if (box.getDimensions().getWidth() < sss)
  //   box.getDimensions().setWidth(sss);
  //
  // if (box.getDimensions().getHeight() < sss)
  //   box.getDimensions().setHeight(sss);
  //
  // pResult->setDimensions(CLDimensions(box.getDimensions().getWidth() + 30.0, box.getDimensions().getHeight() + 30.0));

  // randomize
  CCopasiSpringLayout l(pResult, mParams);
  l.randomize();

  // determine and set the layout dimensions
  CLBoundingBox box = pResult->calculateBoundingBox();
  pResult->setDimensions(CLDimensions(box.getDimensions().getWidth() + 30.0, box.getDimensions().getHeight() + 30.0));

  return pResult;
}