/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 *   
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

/* $Rev$ $Date$ */

//////////////////////////////////////////////////////////////////////
// DataFactoryImpl.cpp: implementation of the DataFactory class.
//
//////////////////////////////////////////////////////////////////////
#include "commonj/sdo/SDORuntimeException.h"

#include "commonj/sdo/DataFactoryImpl.h"
#include "commonj/sdo/DataObjectImpl.h"

#include "commonj/sdo/Logger.h"

#include "commonj/sdo/SDOUtils.h"

#include "commonj/sdo/PropertyList.h"

#include <iostream>
#include <stdio.h>


using namespace std;
using namespace commonj::sdo;

namespace commonj{
namespace sdo {

      using internal::SDOUtils;
// ===================================================================
// Constructor
// ===================================================================
DataFactoryImpl::DataFactoryImpl()
{

    /* add the primitives to every mdg - */

    isResolved = false;
    addType(SDOUtils::sdoURI,"Decimal");
    addType(SDOUtils::sdoURI,"Integer");
    addType(SDOUtils::sdoURI,"Boolean");

    addType(SDOUtils::sdoURI,"Byte");
    addType(SDOUtils::sdoURI,"Bytes");
    addType(SDOUtils::sdoURI,"Character");

    addType(SDOUtils::sdoURI,"String");
    addType(SDOUtils::sdoURI,"DataObject", false, false, true, false);
    addType(SDOUtils::sdoURI,"OpenDataObject", true, true, false, false);
    addType(SDOUtils::sdoURI,"Date");
    addType(SDOUtils::sdoURI,"Double");
    addType(SDOUtils::sdoURI,"Float");
    addType(SDOUtils::sdoURI,"Int");
    addType(SDOUtils::sdoURI,"Long");
    addType(SDOUtils::sdoURI,"Short");
    addType(SDOUtils::sdoURI,"URI");

    // abstract
    addType(SDOUtils::sdoURI,"ChangeSummary");

}

// ===================================================================
// Destructor
// ===================================================================
DataFactoryImpl::~DataFactoryImpl()
{

   resolvePending.clear();
   
    TYPES_MAP::iterator typeIter;
    for (typeIter = types.begin() ; typeIter != types.end() ; ++typeIter)
    {
        if (strncmp((typeIter->first).c_str(),"ALIAS::", 7)) 
        {
            delete typeIter->second;
        }
    }
}

// ===================================================================
// copy constructor
// ===================================================================
DataFactoryImpl::DataFactoryImpl(const DataFactoryImpl& inmdg)
{
    isResolved = false;
    copyTypes(inmdg);
}

// ===================================================================
// Assignment operator
// ===================================================================
DataFactoryImpl& DataFactoryImpl::operator=(const DataFactoryImpl& inmdg)
{
    if (this != &inmdg)
    {
        copyTypes(inmdg);
    }
    return *this;
}

RefCountingPointer<DataFactory> DataFactoryImpl::clone()
{
    const DataFactoryImpl* df = (const DataFactoryImpl*)this;
    DataFactory* dob = (DataFactory*)(new DataFactoryImpl(*df));
    return RefCountingPointer<DataFactory> (dob);
}

// ===================================================================
// copy Types to this DataFactory
// ===================================================================
void DataFactoryImpl::copyTypes(const DataFactoryImpl& inmdg)
{


    TYPES_MAP::const_iterator typeIter;
    TYPES_MAP::iterator typeIter2;
    SDOString fullTypeName;

    for (typeIter = inmdg.types.begin() ; typeIter != inmdg.types.end() ; ++typeIter)
    {
        // add this type to this metadata
        addType((typeIter->second)->getURI(), (typeIter->second)->getName());

        // re-find the type we just added.
        getFullTypeName(fullTypeName,
                (typeIter->second)->getURI(), 
                (typeIter->second)->getName());
        typeIter2 = types.find(fullTypeName);

        // copy the aliases , if there are any.

        if ((typeIter->second)->getAliasCount() > 0)
        {
            for (unsigned int j=0;j<(typeIter->second)->getAliasCount();j++)
            {
                (typeIter2->second)->setAlias(
                    (typeIter->second)->getAlias());
            }
        }

        
        // Now add all the properties
        std::vector<PropertyImplPtr> props = typeIter->second->getPropertyListReference();

        for (std::vector<PropertyImplPtr>::const_iterator i = props.begin();
             i != props.end();
             i++)
        {
            // Ensure the properties type is added
            const Type& propType = (*i)->getType();
            addType(propType.getURI(), propType.getName());

            // Now add the property
            addPropertyToType((typeIter->second)->getURI(),
                              (typeIter->second)->getName(),
                              (*i)->getName(),
                              propType.getURI(), 
                              propType.getName(),
                              (*i)->isMany(),
                              (*i)->isReadOnly(),
                              (*i)->isContainment());

            // copy the aliases if there are any.
            if ((*i)->getAliasCount() > 0) 
            {

                PropertyImpl* p = (typeIter2->second)->
                    getPropertyImpl((*i)->getName());
                if (p != 0)
                {
                    for (unsigned int j=0;j<p->getAliasCount();j++)
                    {
                        p->setAlias((*i)->getAlias(j));
                    }
                }

            }

        } // end - iterate over Properties
    } // end - iterate over Types
}

// ===================================================================
// addType - adds a new Type if it does not already exist
// ===================================================================
void DataFactoryImpl::addType(const char* uri, const char* inTypeName, 
                                bool isSeq,
                                bool isOp,
                                bool isAbs,
                                bool isData)
{
    addType(uri,inTypeName,isSeq,isOp,isAbs,isData,false);
}

void DataFactoryImpl::addType(const SDOString& uri, const SDOString& inTypeName, 
                                bool isSeq,
                                bool isOp,
                                bool isAbs,
                                bool isData)
{
    addType(uri.c_str(),inTypeName.c_str(),isSeq,isOp,isAbs,isData,false);
}

bool empty(const char* inTypeName)
{
    return inTypeName == 0 || strlen(inTypeName) == 0;
}
void assertTypeName(const char* inTypeName, const char* function)
{
    if (empty(inTypeName))
    {
        throw SDOIllegalArgumentException(TUSCANY_SDO_EINFO,
                                          " Type has empty name");
    }
}

void DataFactoryImpl::addType(const char* uri, const char* inTypeName, 
                                bool isSeq,
                                bool isOp,
                                bool isAbs,
                                bool isData,
                                bool isFromList)
{
    assertTypeName(inTypeName, "DataFactory::addType");

    SDOString typeUri;

    if (uri)
        typeUri = uri;
    if (findType(typeUri, inTypeName) == 0) 
    {
        SDOString fullTypeName;
		getFullTypeName(fullTypeName, uri, inTypeName);
        types[fullTypeName] = new TypeImpl(uri, inTypeName, isSeq, isOp, isAbs, isData, isFromList);
        resolvePending[fullTypeName] = types[fullTypeName];
    }
}

void DataFactoryImpl::addType(const SDOString& uri, const SDOString& inTypeName, 
                                bool isSeq,
                                bool isOp,
                                bool isAbs,
                                bool isData,
                                bool isFromList)
{
    addType(uri.c_str(), inTypeName.c_str(), isSeq, isOp, isAbs, isData, isFromList);
}

// ===================================================================
//  Check whether a change summary would clash.
// ===================================================================

bool DataFactoryImpl::recursiveCheck(TypeImpl* cs, TypeImpl* t)
{
    if (cs->isDataType()) return false;

    if (! strcmp(cs->getName(), t->getName()) &&
        ! strcmp(cs->getURI() , t->getURI()) )
    {
        return true;
    }

    const std::vector<PropertyImplPtr> pl = cs->getPropertyListReference();
    
    for (std::vector<PropertyImplPtr>::const_iterator j = pl.begin();
         j != pl.end();
         j++)
    {
        if (recursiveCheck((TypeImpl*)&((*j)->getType()), t)) return true;
    }
    return false;
}

// ===================================================================
//  Check whether a change summary would clash.
// ===================================================================
bool DataFactoryImpl::checkForValidChangeSummary(TypeImpl* t)
{
    // None of the containing types can have a cs already.
    // None of the properties of this type can hold a type
    // which has a change summary.

   if (t->isResolved)
    {
      throw SDOUnsupportedOperationException(TUSCANY_SDO_EINFO,
                                             "Adding Change Summary after type completed");
    }

    if (cstypes.size() > 0) {
        for (unsigned int i = 0 ;i < cstypes.size(); i++) 
        {
            if (recursiveCheck(cstypes[i], t)) 
            {
                return false;

            }
        }
    }
    cstypes.push_back(t);
    return true;
}

void assertNames(const char* inTypeName, const char* propname)
{
    assertTypeName(inTypeName, "DataFactory::addPropertyToType");
    if (empty(propname))
    {
        throw SDOIllegalArgumentException(TUSCANY_SDO_EINFO,
                                          "Property has an empty name");
    }
}

// ===================================================================
// addPropertyToType - adds a Property to an existing Type
// ===================================================================
void DataFactoryImpl::addPropertyToType(const char* uri, 
                                      const char* inTypeName, 
                                      const char* propname,
                                      const char* propTypeUri,
                                      const char* propTypeName,
                                      bool    many)
{
    assertNames(inTypeName, propname);
    SDOString fullPropTypeName;
    getFullTypeName(fullPropTypeName, propTypeUri, propTypeName);

    TYPES_MAP::iterator typeIter;
    typeIter = types.find(fullPropTypeName);
    if (typeIter != types.end())
    {
        addPropertyToType(uri,inTypeName, 
                                  propname,
                                  propTypeUri,
                                  propTypeName,
                                  many, 
                                  false,
                                  !(typeIter->second)->isDataType());
    }
}

void DataFactoryImpl::addPropertyToType(const SDOString& uri,
                                        const SDOString& inTypeName,
                                        const SDOString& propname,
                                        const SDOString& propTypeUri,
                                        const SDOString& propTypeName,
                                        bool many)
{
  addPropertyToType(uri.c_str(), inTypeName.c_str(), propname.c_str(), propTypeUri.c_str(), propTypeName.c_str(), many);
}

void DataFactoryImpl::addPropertyToType(const char* uri, 
                                        const char* inTypeName, 
                                        const char* propname,
                                        const char* propTypeUri,
                                        const char* propTypeName,
                                        bool many,
                                        bool rdonly,
                                        bool cont)
{
    assertNames(inTypeName, propname);

    TYPES_MAP::iterator typeIter, typeIter2;
    
    //cout << "Adding property " << propname << "(" << propTypeUri << "#" << propTypeName
    //    << ") to type " << uri << "#" << inTypeName << endl;


    SDOString fullTypeName;
	getFullTypeName(fullTypeName, uri, inTypeName);
    typeIter = types.find(fullTypeName);

    if(typeIter == types.end())
    {
        string msg("Type not found: ");
        if (uri != 0)msg += uri;
        msg += " ";
        if (inTypeName != 0)msg += inTypeName;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());

    }

    if ((typeIter->second)->isDataType())
    {
        string msg("Cannot add property ");
        msg += propname;
        msg += " of type ";
        msg += propTypeUri;
        msg += "#";
        msg += propTypeName;
        msg += " to this data type ";
        msg += uri;
        msg += "#";
        msg += inTypeName;
        throw SDOIllegalArgumentException(TUSCANY_SDO_EINFO,
                                          msg.c_str());
    }

    getFullTypeName(fullTypeName, propTypeUri, propTypeName);
    typeIter2 = types.find(fullTypeName);
    
    if (typeIter2 == types.end())
    {
        string msg("Type not found: ");
        if (propTypeUri != 0)msg += propTypeUri;
        msg += " ";
        if (propTypeName != 0)msg += propTypeName;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());
    }
    
    // Check if its a ChangeSummary
    if (propTypeUri != 0 && !strcmp(propTypeUri,SDOUtils::sdoURI) &&
        !strcmp(propTypeName,"ChangeSummary") )
    {
        if (checkForValidChangeSummary(typeIter->second)) 
        {
            // The change summary is allowable if we got to here - force the right params.
            // we will not use this property - its just for compatibility.
            // we have to use getChangeSummary to get the change summary, 
            // and isChangeSummaryType to see if this is a type which may have
            // a change summary.
            (typeIter->second)->addChangeSummary();
            // dont even show the property - its not needed
            //((typeIter->second)->addProperty(propname, *(typeIter2->second),false,true, false));

        }
        return;
    }
    

    if ((typeIter->second)->isDataType())
    {
        string msg("Cannot add property to a data type : ");
        msg += (typeIter->second)->getName();
        throw SDOIllegalArgumentException(TUSCANY_SDO_EINFO,
                                          msg.c_str());
           // cannot add a property to a primitive
    }

    // @PGR@ containment should be ignored for DataType
/*    if ((typeIter2->second)->isDataType() && cont == true)
    {
        string msg("Data types may not be containment : ");
        msg += (typeIter2->second)->getName();
        throw SDOIllegalArgumentException(TUSCANY_SDO_EINFO,
                                          msg.c_str());
        // cannot try to make a property containment on a data type
    }
*/

    if ((typeIter->second)->isResolved)
    {
        throw SDOUnsupportedOperationException(TUSCANY_SDO_EINFO,
            "Adding Properties after type completed");
    }

    ((typeIter->second)->addProperty(propname, *(typeIter2->second),many,rdonly, cont));
    return;
}

void DataFactoryImpl::addPropertyToType(const SDOString& uri,
                                        const SDOString& inTypeName,
                                        const SDOString& propname,
                                        const SDOString& propTypeUri,
                                        const SDOString& propTypeName,
                                        bool many,
                                        bool rdonly,
                                        bool cont)
{
  addPropertyToType(uri.c_str(),
                           inTypeName.c_str(),
                           propname.c_str(),
                           propTypeUri.c_str(),
                           propTypeName.c_str(),
                           many,
                           rdonly,
                           cont);
}

// ===================================================================
// addPropertyToType - adds a Property to an existing Type
// ===================================================================

void DataFactoryImpl::addPropertyToType(const char* uri, 
                                      const char* inTypeName, 
                                      const char* propname,
                                      const Type& tprop,
                                      bool    many)
{
    addPropertyToType(uri, 
                    inTypeName, 
                    propname,
                    tprop,
                    many,
                    false,
                    !tprop.isDataType());
}

void DataFactoryImpl::addPropertyToType(const SDOString& uri, 
                                        const SDOString& inTypeName, 
                                        const SDOString& propname,
                                        const Type& tprop,
                                        bool many)
{
  addPropertyToType(uri.c_str(), 
                    inTypeName.c_str(), 
                    propname.c_str(),
                    tprop,
                    many,
                    false,
                    !tprop.isDataType());
}

void DataFactoryImpl::addPropertyToType(const char* uri, 
                                      const char* inTypeName, 
                                      const char* propname,
                                      const Type& tprop,
                                      bool    many,
                                      bool    rdonly,
                                      bool cont)
{
    addPropertyToType(uri, 
                      inTypeName,
                      propname,
                      tprop.getURI(),
                      tprop.getName(),
                      many,
                      rdonly, cont);
}

void DataFactoryImpl::addPropertyToType(const SDOString& uri, 
                                        const SDOString& inTypeName, 
                                        const SDOString& propname,
                                        const Type& tprop,
                                        bool many,
                                        bool rdonly,
                                        bool cont)
{
  addPropertyToType(uri.c_str(), 
                    inTypeName.c_str(),
                    propname.c_str(),
                    tprop.getURI(),
                    tprop.getName(),
                    many,
                    rdonly,
                    cont);
}

// ===================================================================
// addPropertyToType - adds a Property to an existing Type
// ===================================================================
void DataFactoryImpl::addPropertyToType(const Type& cont,
                                      const char* propname,
                                      const char* propTypeUri,
                                      const char* propTypeName,
                                      bool  many)
{
    addPropertyToType(cont.getURI(),
                      cont.getName(),
                      propname,
                      propTypeUri,
                      propTypeName,
                      many);
}

void DataFactoryImpl::addPropertyToType(const Type& cont,
                                        const SDOString& propname,
                                        const SDOString& propTypeUri,
                                        const SDOString& propTypeName,
                                        bool many)
{
  addPropertyToType(cont.getURI(),
                    cont.getName(),
                    propname.c_str(),
                    propTypeUri.c_str(),
                    propTypeName.c_str(),
                    many);
}

void DataFactoryImpl::addPropertyToType(const Type& cont,
                                      const char* propname,
                                      const char* propTypeUri,
                                      const char* propTypeName,
                                      bool  many,
                                      bool  rdonly,
                                      bool contain)
{
    addPropertyToType(cont.getURI(),
                      cont.getName(),
                      propname,
                      propTypeUri,
                      propTypeName,
                      many,
                      rdonly,
                      contain);
}

void DataFactoryImpl::addPropertyToType(const Type& cont,
                                      const SDOString& propname,
                                      const SDOString& propTypeUri,
                                      const SDOString& propTypeName,
                                      bool many,
                                      bool rdonly,
                                      bool contain)
{
    addPropertyToType(cont.getURI(),
                      cont.getName(),
                      propname.c_str(),
                      propTypeUri.c_str(),
                      propTypeName.c_str(),
                      many,
                      rdonly,
                      contain);
}

// ===================================================================
// addPropertyToType - adds a Property to an existing Type
// ===================================================================
void DataFactoryImpl::addPropertyToType(const Type& tp,
                                      const char* propname,
                                      const Type& tprop,
                                      bool  many)
{
        addPropertyToType(tp.getURI(),
                      tp.getName(),
                      propname,
                      tprop.getURI(),
                      tprop.getName(),
                      many);
}

void DataFactoryImpl::addPropertyToType(const Type& tp,
                                        const SDOString& propname,
                                        const Type& tprop,
                                        bool many)
{
  addPropertyToType(tp.getURI(),
                    tp.getName(),
                    propname.c_str(),
                    tprop.getURI(),
                    tprop.getName(),
                    many);
}

void DataFactoryImpl::addPropertyToType(const Type& tp,
                                      const char* propname,
                                      const Type& tprop,
                                      bool  many,
                                      bool  rdonly,
                                      bool cont)
{
    addPropertyToType(tp.getURI(),
                      tp.getName(),
                      propname,
                      tprop.getURI(),
                      tprop.getName(),
                      many,
                      rdonly,
                      cont);
}

void DataFactoryImpl::addPropertyToType(const Type& tp,
                                        const SDOString& propname,
                                        const Type& tprop,
                                        bool many,
                                        bool rdonly,
                                        bool cont)
{
  addPropertyToType(tp.getURI(),
                    tp.getName(),
                    propname.c_str(),
                    tprop.getURI(),
                    tprop.getName(),
                    many,
                    rdonly,
                    cont);
}

// ===================================================================
// getFullTypeName - return the name used as a key in the types map
// ===================================================================
SDOString& DataFactoryImpl::getFullTypeName(SDOString& stringBuffer, const SDOString& uri, const SDOString& inTypeName)
{
   stringBuffer = uri;
   stringBuffer += "#";
   stringBuffer += inTypeName;
   return stringBuffer;
}

// ===================================================================
// getAliasTypeName - return the name used as a key in the types map
// ===================================================================
SDOString& DataFactoryImpl::getAliasTypeName(SDOString& stringBuffer, const SDOString& uri, const SDOString& inTypeName)
{
  getFullTypeName(stringBuffer, uri, inTypeName);
  stringBuffer.insert(0, "ALIAS::");
  return stringBuffer;
}

// ===================================================================
// getType - return a pointer to the required Type
// ===================================================================
const Type& DataFactoryImpl::getType(const char* uri, const char* inTypeName) const
{

    const Type* type = findType(uri, inTypeName);

    if (type == 0)
    {
        string msg("Type not found :");
        if (uri != 0) msg += uri;
        msg += " ";
        if (inTypeName != 0) msg += inTypeName;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());
    }
    
    return *type;
}

const Type& DataFactoryImpl::getType(const SDOString& uri, const SDOString& inTypeName) const
{
    return getType(uri.c_str(), inTypeName.c_str());
}

// ===================================================================
// setBaseType - sets the type from which this type inherits properties
// ===================================================================

void DataFactoryImpl::setBaseType( const Type& type,
                  const Type& base, bool isRestriction) 
{
    setBaseType(type.getURI(),type.getName(),base.getURI(), base.getName(),
        isRestriction);
}

// ===================================================================
// setBaseType - sets the type from which this type inherits properties
// ===================================================================

void DataFactoryImpl::setBaseType( const char* typeuri,
                  const char* typenam,
                  const char* baseuri,
                     const char* basename,
                     bool isRestriction )
{
    const TypeImpl* base = findTypeImpl(baseuri, basename);
    if (base == 0)
    {
        string msg("Type not found :");
        if (baseuri != 0) msg += baseuri;
        msg += " ";
        if (basename != 0) msg += basename;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());
    }

    TYPES_MAP::const_iterator typeIter;

    SDOString fullTypeName;
	getFullTypeName(fullTypeName, typeuri, typenam);
    typeIter = types.find(fullTypeName);
    
    if(typeIter == types.end())
    {
        string msg("Type not found :");
        if (typeuri != 0) msg += typeuri;
        msg += " ";
        if (typenam != 0) msg += typenam;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());
    }

    (typeIter->second)->setBaseType(base, isRestriction);
}

void DataFactoryImpl::setBaseType(const SDOString& typeuri,
                                  const SDOString& typenam,
                                  const SDOString& baseuri,
                                  const SDOString& basename,
                                  bool isRestriction)
{
    setBaseType(typeuri.c_str(),
        typenam.c_str(),
        baseuri.c_str(),
        basename.c_str(),
        isRestriction);
}


// ===================================================================
// setPropertySubstitute - additional type for a property
// ===================================================================

    void DataFactoryImpl::setPropertySubstitute(
            const char* uri, 
            const char* inTypeName,
            const char* propname,
            const char* subname,
            const char* subTypeUri, 
            const char* subTypeName)
    {
        const TypeImpl* cont = findTypeImpl(uri, inTypeName);
        if (cont == 0)
        {
            string msg("Type not found :");
            if (uri != 0) msg += uri;
            msg += " ";
            if (inTypeName != 0) msg += inTypeName;
            throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                           msg.c_str());
        }
        PropertyImpl* pi = cont->getPropertyImpl(propname);
        const Type& tsub = getType(subTypeUri,
                                subTypeName);
        if (pi != 0)pi->setSubstitution(this,subname,tsub);
    }

    void DataFactoryImpl::setPropertySubstitute(
            const SDOString& uri, 
            const SDOString& inTypeName,
            const SDOString& propname,
            const SDOString& subname,
            const SDOString& subTypeUri, 
            const SDOString& subTypeName)
    {
      setPropertySubstitute(uri.c_str(),
                            inTypeName.c_str(),
                            propname.c_str(),
                            subname.c_str(),
                            subTypeUri.c_str(),
                            subTypeName.c_str());
    }

    void DataFactoryImpl::setPropertySubstitute(
            const Type& containertype,
            const char* propname,
            const char* subname,
            const Type& subtype)
    {
        setPropertySubstitute(
            containertype.getURI(),
            containertype.getName(),
            propname,subname,
            subtype.getURI(),subtype.getName());
    }

    void DataFactoryImpl::setPropertySubstitute(
            const Type& containertype,
            const SDOString& propname,
            const SDOString& subname,
            const Type& subtype)
    {
      setPropertySubstitute(containertype, propname.c_str(), subname.c_str(), subtype);
    }
// ===================================================================
// setDefault - sets the default value for a property of a type
// ===================================================================

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname, bool b ) 
    {
        setDefault(t.getURI(), t.getName(), propname, b);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname, bool b ) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), b);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , char c) 
        
    {
        setDefault(t.getURI(), t.getName(), propname, c);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , char c) 
        
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), c);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , wchar_t c) 
    {
        setDefault(t.getURI(), t.getName(), propname, c);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , wchar_t c) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), c);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , char* c) 
    {
        setDefault(t.getURI(), t.getName(), propname, c);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , SDOString& outstr)
    {
        setDefault(t.getURI(), t.getName(), propname, outstr);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , short s) 
    {
        setDefault(t.getURI(), t.getName(), propname, s);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , short s) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), s);
    }

#if __WORDSIZE !=64
    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , long l) 
    {
        setDefault(t.getURI(), t.getName(), propname, l);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , long l) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), l);
    }

#endif

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , int64_t i) 
    {
        setDefault(t.getURI(), t.getName(), propname, i);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , int64_t i) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), i);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , float f) 
    {
        setDefault(t.getURI(), t.getName(), propname, f);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , float f) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), f);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , long double d) 
    {
        setDefault(t.getURI(), t.getName(), propname, d);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , long double d) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), d);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , const SDODate d) 
    {
        setDefault(t.getURI(), t.getName(), propname, d);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , const SDODate d) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), d);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , const wchar_t* c, unsigned int len) 
    {
        setDefault(t.getURI(), t.getName(), propname, c, len);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , const wchar_t* c, unsigned int len) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), c, len);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const char* propname , const char* c, unsigned int len) 
    {
        setDefault(t.getURI(), t.getName(), propname, c, len);
    }

    void DataFactoryImpl::setDefault(
        const Type& t, const SDOString& propname , const SDOString& c, unsigned int len) 
    {
        setDefault(t.getURI(), t.getName(), propname.c_str(), c.c_str(), len);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname, bool b ) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(b);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname, bool b ) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), b);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , char c) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(c);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , char c) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), c);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , wchar_t c) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(c);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , wchar_t c) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), c);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , char* c) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(c);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , SDOString& c) 
    {
        const TypeImpl* ti = findTypeImpl(typuri, typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(c);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , short s) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(s);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , short s) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), s);
    }

#if __WORDSIZE !=64
    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , long l) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(l);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , long l) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), l);
    }

#endif

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , int64_t i) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(i);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , int64_t i) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), i);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , float f) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(f);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , float f) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), f);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , long double d) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(d);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , long double d) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), d);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , const SDODate d) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(d);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , const SDODate d) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), d);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , const wchar_t* c, unsigned int len) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(c,len);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , const wchar_t* c, unsigned int len) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), c, len);
    }

    void DataFactoryImpl::setDefault(
        const char* typuri, const char* typnam, 
        const char* propname , const char* c, unsigned int len) 
    {
        const TypeImpl* ti = findTypeImpl(typuri,typnam);
        PropertyImpl* pi = ti->getPropertyImpl(propname);
        if (pi != 0)pi->setDefault(c,len);
    }

    void DataFactoryImpl::setDefault(
        const SDOString& typuri, const SDOString& typnam, 
        const SDOString& propname , const SDOString& c, unsigned int len) 
    {
      setDefault(typuri.c_str(), typnam.c_str(), propname.c_str(), c.c_str(), len);
    }

    void DataFactoryImpl::setOpposite(
        const Type& typ, 
        const char* propnam, 
        const Type& opptyp,
        const char* opppropnam) 
    {
        throw SDOUnsupportedOperationException(TUSCANY_SDO_EINFO,
                                               "Not implemented");
    }

    void DataFactoryImpl::setOpposite(
        const Type& typ, 
        const SDOString& propnam, 
        const Type& opptyp,
        const SDOString& opppropnam) 
    {
      setOpposite(typ, propnam.c_str(), opptyp, opppropnam.c_str());
    }

// ===================================================================
// getTypeImpl - return a pointer to the required TypeImpl
// ===================================================================
const TypeImpl& DataFactoryImpl::getTypeImpl(const SDOString& uri, const SDOString& inTypeName) const
{
    const TypeImpl* type = findTypeImpl(uri, inTypeName);

    if (type == 0)
    {
        string msg("Type not found :");
        msg += uri + " " + inTypeName;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());
    }
    
    return *type;;
}

// ===================================================================
// findType
// ===================================================================
const Type* DataFactoryImpl::findType(const SDOString uri, const SDOString inTypeName) const
{
    return (Type*) findTypeImpl(uri, inTypeName);
}

// ===================================================================
// findTypeImpl
// ===================================================================

const TypeImpl* DataFactoryImpl::findTypeImpl(const SDOString& uri, const SDOString& inTypeName) const
{
    SDOString fullTypeName;
	getFullTypeName(fullTypeName, uri, inTypeName);
    TYPES_MAP::const_iterator typeIter;
    typeIter = types.find(fullTypeName);
    if(typeIter != types.end())
    {
        return typeIter->second;
    }
    else
    {
        // try alias names
        getAliasTypeName(fullTypeName, uri, inTypeName);
        typeIter = types.find(fullTypeName);
        if(typeIter != types.end())
        {
            return typeIter->second;
        }
    }
    return 0;
}

// ===================================================================
// setAlias - sets a new alias for this type
// ===================================================================

void DataFactoryImpl::setAlias(const char* typeuri,
                              const char* typenam,
                              const char* alias)
{

    SDOString fullTypeName;
	getFullTypeName(fullTypeName, typeuri, typenam);
    TYPES_MAP::iterator typeIter;
    typeIter = types.find(fullTypeName);
    if(typeIter != types.end())
    {
        (typeIter->second)->setAlias(alias);
        getAliasTypeName(fullTypeName, typeuri, alias);
        types[fullTypeName] = typeIter->second;
    }

}

void DataFactoryImpl::setAlias(const SDOString& typeuri,
                              const SDOString& typenam,
                              const SDOString& alias)
{
    setAlias(typeuri.c_str(), typenam.c_str(), alias.c_str());
}

// ===================================================================
// setAlias - sets a new alias for this type
// ===================================================================

void DataFactoryImpl::setAlias(const char* typeuri, 
                              const char* typenam, 
                              const char* propname,
                              const char* alias)
{
    const TypeImpl&  t = getTypeImpl(typeuri, typenam);
    PropertyImpl* p  = t.getPropertyImpl(propname); 
    if (p != 0)p->setAlias(alias);

}

void DataFactoryImpl::setAlias(const SDOString& typeuri, 
                              const SDOString& typenam, 
                              const SDOString& propname,
                              const SDOString& alias)
{
    setAlias(typeuri.c_str(), typenam.c_str(), propname.c_str(), alias.c_str());
}

// ===================================================================
//  getTypes - gets the full list of types for this factory
// ===================================================================

TypeList DataFactoryImpl::getTypes() const
{
    TYPES_MAP::const_iterator typeIter;
    

    std::vector<const Type*> typeVector;

    for (typeIter = types.begin() ; typeIter != types.end();
    ++typeIter) {
        if (strncmp((typeIter->first).c_str(),"ALIAS::", 7)) {
            typeVector.insert(typeVector.end(),typeIter->second);
        }
    }


    return typeVector;
}


// ===================================================================
//  resolve - resolves the type and includes all the properties from
// the supertype. After this has been called, no further changes
// to the type hierarchy are allowed.
// ===================================================================

void DataFactoryImpl::resolve()
{

    TYPES_MAP::iterator typeIter;
    for (typeIter = resolvePending.begin() ; typeIter != resolvePending.end();
    ++typeIter) 
    {
        (typeIter->second)->initCompoundProperties();
        (typeIter->second)->validateChangeSummary();
    }
    // Need to empty the resolvePending set.
    resolvePending.clear();

}

// ===================================================================
//  create - creates a data object from the types available.
//  This first resolves the type hierarchy, and thus no further changes
//  to the type hierarchy are allowed.
// ===================================================================


RefCountingPointer<DataObject> DataFactoryImpl::create(const char* uri, const char* typeName) 
{

// New types can always be added now, so if there are any that haven't been
// resolved, do them now. The isResolved boolean is superseded by the
// resolvePending set being non-empty.

   if (!resolvePending.empty())
    {
        // Allow creation of types and properties before resolve.
        if (uri != 0 && !strcmp(uri,SDOUtils::sdoURI)) {
            if (!strcmp(typeName,"Type") || !strcmp(typeName,"Property"))
            {
                DataObject* dob = (DataObject*)(new DataObjectImpl(this, getTypeImpl(uri, typeName)));
                return dob;
            }
        }
        resolve();
    }

    const TypeImpl* ti = findTypeImpl(uri,typeName);
    if (ti == 0)
    {
        string msg("Instantiation of unknown type :");
        if (uri != 0) msg += uri;
        msg += " ";
        if (typeName != 0)msg += typeName;
        throw SDOTypeNotFoundException(TUSCANY_SDO_EINFO,
                                       msg.c_str());
    }

    if (ti->isAbstractType())
    {
        string msg("Instantiation of abstract type :");
        if (uri != 0)msg += uri;
        msg += " ";
        if (typeName != 0)msg += typeName;
        throw SDOUnsupportedOperationException(TUSCANY_SDO_EINFO,
                                               msg.c_str());
    }

    DataObject* dob = (DataObject*)(new DataObjectImpl(this, getTypeImpl(uri, typeName)));
    return dob;
}

// ===================================================================
//  create - creates a data object from the types available.
//  This first resolves the type hierarchy, and thus no further changes
//  to the type hierarchy are allowed.
// ===================================================================


RefCountingPointer<DataObject> DataFactoryImpl::create(const SDOString& uri, const SDOString& typeName) 
{
    return create(uri.c_str(), typeName.c_str());
}

// ===================================================================
// The openProperties map is a list of the curently present open
// properties as used by this factory. It will cause the 
// open properties to be written out as attributes and elements
// of the root data object when a graph is serialized.
// ===================================================================
    const propertyMap& DataFactoryImpl::getOpenProperties()
    {
        return openProperties;
    }

    void DataFactoryImpl::addOpenProperty(const PropertyImpl& prop)
    {
        propertyMap::iterator i;
        while ((i = openProperties.find(prop.getName())) !=
               openProperties.end())
        {
            openProperties.erase(i);
        }
        openProperties.insert(make_pair(prop.getName(),prop));
    }

    void DataFactoryImpl::removeOpenProperty(const SDOString& name)
    {
        propertyMap::iterator i = 
            openProperties.find(name.c_str());
        if (i != openProperties.end())
        {
            openProperties.erase(i);
        }
    }


// ===================================================================
//  create - creates a data object from the types available.
//  This first resolves the type hierarchy, and thus no further changes
//  to the type hierarchy are allowed.
// ===================================================================

RefCountingPointer<DataObject>    DataFactoryImpl::create(const Type& type) 
{
    return create( type.getURI(), type.getName());
}


// ===================================================================
//  setDASValue - Set a value on a Type
// ===================================================================
void DataFactoryImpl::setDASValue(const Type& type,
                                        const char* name, 
                                        DASValue* value)
{
    setDASValue(type.getURI(), type.getName(), name, value);
}

void DataFactoryImpl::setDASValue(const Type& type,
                                        const SDOString& name, 
                                        DASValue* value)
{
    setDASValue(type.getURI(), type.getName(), name.c_str(), value);
}

void DataFactoryImpl::setDASValue(const char* typeuri,
                                        const char* typenam, 
                                        const char* name, 
                                        DASValue* value)
{
    TypeImpl* type = (TypeImpl*)findTypeImpl(typeuri, typenam);
    if (type != NULL)
    {
        type->setDASValue(name, value);
    }
}

void DataFactoryImpl::setDASValue(const SDOString& typeuri,
                                        const SDOString& typenam, 
                                        const SDOString& name, 
                                        DASValue* value)
{
    setDASValue(typeuri.c_str(), typenam.c_str(), name.c_str(), value);
}

// ===================================================================
//  getDASValue - retrieve a value from a Type
// ===================================================================

DASValue* DataFactoryImpl::getDASValue(const Type& type,
                                                const char* name) const
{
    return getDASValue(type.getURI(), type.getName(), name);
}

DASValue* DataFactoryImpl::getDASValue(const Type& type,
                                       const SDOString& name) const
{
    return getDASValue(type.getURI(), type.getName(), name.c_str());
}

DASValue* DataFactoryImpl::getDASValue(const char* typeuri,
                                                const char* typenam,
                                                const char* name) const
{
    TypeImpl* type = (TypeImpl*)findTypeImpl(typeuri, typenam);
    if (type != NULL)
    {
        return type->getDASValue(name);
    }

    return NULL;    
}

DASValue* DataFactoryImpl::getDASValue(const SDOString& typeuri,
                                       const SDOString& typenam,
                                       const SDOString& name) const
{
    return getDASValue(typeuri.c_str(), typenam.c_str(), name.c_str());
}

// ===================================================================
//  setDASValue - Set a value on a Property
// ===================================================================
void DataFactoryImpl::setDASValue( 
                const Type& type,
                const char* propertyName,
                const char* name,
                DASValue* value)
{
    setDASValue(type.getURI(), type.getName(), propertyName, name, value);
}

void DataFactoryImpl::setDASValue( 
                const Type& type,
                const SDOString& propertyName,
                const SDOString& name,
                DASValue* value)
{
    setDASValue(type.getURI(), type.getName(), propertyName.c_str(), name.c_str(), value);
}

void DataFactoryImpl::setDASValue( 
                const char* typeuri,
                const char* typenam,
                const char* propertyName,
                const char* name,
                DASValue* value)
{
    const TypeImpl* type = findTypeImpl(typeuri, typenam);
    if (type != NULL)
    {
        PropertyImpl* prop = type->getPropertyImplPure(propertyName);
        if (prop != 0)prop->setDASValue(name, value);
    }
}

void DataFactoryImpl::setDASValue( 
                const SDOString& typeuri,
                const SDOString& typenam,
                const SDOString& propertyName,
                const SDOString& name,
                DASValue* value)
{
    setDASValue(typeuri.c_str(), typenam.c_str(), propertyName.c_str(), name.c_str(), value);
}

// ===================================================================
//  getDASValue - retrieve a value from a Property
// ===================================================================
DASValue* DataFactoryImpl::getDASValue( 
                const Type& type,
                const char* propertyName,
                const char* name) const
{
    return getDASValue(type.getURI(), type.getName(), propertyName, name);
}

DASValue* DataFactoryImpl::getDASValue( 
                const Type& type,
                const SDOString& propertyName,
                const SDOString& name) const
{
    return getDASValue(type.getURI(), type.getName(), propertyName.c_str(), name.c_str());
}

DASValue* DataFactoryImpl::getDASValue(
                const char* typeuri,
                const char* typenam,
                const char* propertyName, 
                const char* name) const
{
    const TypeImpl* type = findTypeImpl(typeuri, typenam);
    if (type != NULL)
    {
        try
        {
            PropertyImpl* prop = type->getPropertyImpl(propertyName);
            if (prop != 0)return prop->getDASValue(name);
        }
        catch (const SDOPropertyNotFoundException&)
        {
            // Ignore - return null
        }
    }

    return NULL;    
}

DASValue* DataFactoryImpl::getDASValue(
                const SDOString& typeuri,
                const SDOString& typenam,
                const SDOString& propertyName, 
                const SDOString& name) const
{
    return getDASValue(typeuri.c_str(), typenam.c_str(), propertyName.c_str(), name.c_str());
}


    std::ostream& DataFactoryImpl::printSelf(std::ostream &os)
    {
        SDOUtils::printTypes(os, this);
        return os;
    }

};
};

