//------------------------------
	bool LibraryEffectsLoader::end__profile_COMMON()
	{
		// Calculate the opacity value.
		calculateOpacity ();

        // Fill the array of samplers of the current profile.
        if ( !fillSamplerArray() )
			return false;

        SidSamplerInfoMap::iterator samplerIt = mEffectProfileSidSamplerInfoMap.begin();
        for ( ; samplerIt != mEffectProfileSidSamplerInfoMap.end(); ++samplerIt)
        {
            SamplerInfo& samplerInfo = samplerIt->second;
            delete samplerInfo.sampler;
        }
        mEffectProfileSidSamplerInfoMap.clear();
        mEffectProfileSidSurfaceMap.clear();
        mEffectProfileSamplersMap.clear ();
		mNextSamplerIndex = 0;

		mTransparent.getColor ().set ( -1, -1, -1, -1 );
		mCurrentProfile = PROFILE_NONE;

		moveUpInSidTree();

        return true;
	}
	//------------------------------
	bool LibraryEffectsLoader::end__profile_COMMON()
	{
        // Store values original transparency and transparent values
        mCurrentEffect->getCommonEffects ().back ()->setTransparent (mTransparent);
        mCurrentEffect->getCommonEffects ().back ()->setTransparency(mTransparency);
        mCurrentEffect->getCommonEffects ().back ()->setOpaqueMode((COLLADAFW::EffectCommon::OpaqueMode)mOpaqueMode);

		// Calculate the opacity value.
		calculateOpacity ();

		const COLLADAFW::PointerArray<COLLADAFW::TextureAttributes>& effectTextures = mCurrentEffect->getExtraTextures();
		handleExtraEffectTextures( effectTextures );

        // Fill the array of samplers of the current profile.
        if ( !fillSamplerArray() )
			return false;

        SidSamplerInfoMap::iterator samplerIt = mEffectProfileSidSamplerInfoMap.begin();
        for ( ; samplerIt != mEffectProfileSidSamplerInfoMap.end(); ++samplerIt)
        {
            SamplerInfo& samplerInfo = samplerIt->second;
            delete samplerInfo.sampler;
        }
        mEffectProfileSidSamplerInfoMap.clear();
        mEffectProfileSidSurfaceMap.clear();
        mEffectProfileSamplersMap.clear ();
		mNextSamplerIndex = 0;

		mTransparent.getColor ().set ( -1, -1, -1, -1 );
		mCurrentProfile = PROFILE_NONE;

		moveUpInSidTree();

        return true;
	}
	//------------------------------
	bool LibraryEffectsLoader::end__profile_COMMON__technique()
	{
		moveUpInSidTree();
		
        mInProfileCommonTechnique = false;

        return true;
	}
	//------------------------------
	bool LibraryEffectsLoader::end__effect()
	{
		getFileLoader()->addEffect(mCurrentEffect);

        mCurrentEffect = 0;
        SidSamplerInfoMap::iterator samplerIt = mEffectSidSamplerInfoMap.begin();
        for ( ; samplerIt != mEffectSidSamplerInfoMap.end(); ++samplerIt)
        {
            SamplerInfo& samplerInfo = samplerIt->second;
            delete samplerInfo.sampler;
        }
        mEffectSidSamplerInfoMap.clear();
        mEffectSidSurfaceMap.clear();
        
        moveUpInSidTree();

		return true;
	}
    //------------------------------
	bool GeometryLoader::end__geometry()
	{
		bool success = true;
		COLLADAFW::Mesh * mesh = mMeshLoader ? mMeshLoader->getMesh() : 0;
		if ( ((getObjectFlags() & Loader::GEOMETRY_FLAG) != 0) && mesh )
		{
			success |= writer()->writeGeometry(mesh);
		}

        COLLADAFW::Spline * spline = mSplineLoader ? mSplineLoader->getSpline() : 0;
        if ( ((getObjectFlags() & Loader::GEOMETRY_FLAG) != 0) && spline )
        {
            success |= writer()->writeGeometry(spline);
        }

		finish();
		moveUpInSidTree();
		return success;
	}
 //------------------------------
 bool LibraryEffectsLoader::end__common_float_or_param_type____float ()
 {
     moveUpInSidTree();
     return true;
 }
	//------------------------------
	bool LibraryEffectsLoader::end__common_color_or_texture_type____color()
	{
		mCurrentColorValueIndex = 0;
		moveUpInSidTree();
		return true;
	}
	//------------------------------
	bool LibraryEffectsLoader::end__library_effects()
	{
		moveUpInSidTree();
		finish();
		return true;
	}
	//------------------------------
	bool LibraryControllersLoader::begin__input____InputLocal( const input____InputLocal__AttributeData& attributeData )
	{
		// we ignore inputs that don't have semantics or source
		if ( !attributeData.semantic || !attributeData.source  )
		{
			return true;
		}

		ControllerInputSemantics semantic = getControllerInputSemanticsBySemanticStr( attributeData.semantic );
		if ( semantic == SEMANTIC_UNKNOWN )
		{
			return true;
		}

		switch ( mCurrentControllerType )
		{
		case SKIN_CONTROLLER:
			{
				switch ( semantic )
				{
				case SEMANTIC_JOINT:
					{
						if ( !mCurrentSkinControllerData )
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);

						const StringList* nodeSidsOrIds = 0;
						bool isIdArray = false;
						StringListMap::const_iterator itSid = mJointSidsMap.find(sourceId);
						// check if the node sid array could be found
						if ( itSid != mJointSidsMap.end() )
						{
							nodeSidsOrIds = &itSid->second;
							isIdArray = false;
						}
						else
						{
							// check if it is an id_array
							StringListMap::const_iterator itId = mJointIdsMap.find(sourceId);
							if ( itId != mJointIdsMap.end() )
							{
								nodeSidsOrIds = &itId->second;
								isIdArray = true;
							}
							else
							{
								if ( !handleFWLError ( SaxFWLError::ERROR_SOURCE_NOT_FOUND, "Source with id \"" + sourceId + "\" in skin controller with  id \"" + mOriginalId + "\" used in input with semantic SEMANTIC_JOINT could not be found!" ))
									return false;
								break;
							}
						}

						const COLLADAFW::UniqueId& controllerUniqueId = mCurrentSkinControllerData->getUniqueId();
						addSkinDataJointSidsPair( controllerUniqueId, *nodeSidsOrIds, isIdArray);

						// try to write the SkinController here
						if ( ((getObjectFlags() & Loader::CONTROLLER_FLAG) != 0) && (mCurrentControllerSourceUniqueId.isValid()) )
						{
							Loader::InstanceControllerDataList& instanceControllerDataList = getInstanceControllerDataListByControllerUniqueId(controllerUniqueId);
							Loader::InstanceControllerDataList::iterator listIt = instanceControllerDataList.begin();

							while ( listIt != instanceControllerDataList.end() )
							{
								const Loader::InstanceControllerData& instanceControllerData = *listIt;
								bool success = getFileLoader()->createAndWriteSkinController( instanceControllerData, 
																					   		  controllerUniqueId, 
									                                                          mCurrentControllerSourceUniqueId,
									                                                          *nodeSidsOrIds,
																							  isIdArray);
								//on success we need to remove this controller instance
								if ( success )
								{
									listIt = instanceControllerDataList.erase( listIt );
								}
								else
								{
									listIt++;
								}
							}
						}
						mCurrentSkinControllerData->setJointsCount(nodeSidsOrIds->size());
					}
					break;
				case SEMANTIC_INV_BIND_MATRIX:
					{
						if ( !mCurrentSkinControllerData)
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);
						SourceBase* sourceBase = getSourceById ( sourceId );

						if ( !sourceBase || (sourceBase->getDataType() != SourceBase::DATA_TYPE_REAL) )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "SourceBase of skin controller with semantic SEMANTIC_INV_BIND_MATRIX not valid!" );
							break;
						}

						if ( sourceBase->getStride() != 16 )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Stride of sourceBase of skin controller with semantic SEMANTIC_INV_BIND_MATRIX not valid!" );
							break;
						}

						const RealSource *inverseBindMatricesSource = (const RealSource *)sourceBase;
						const RealArrayElement& inverseBindMatricesElement = inverseBindMatricesSource->getArrayElement();

						const RealArray& inverseBindMatricesArray = inverseBindMatricesElement.getValues();

						size_t matrixElementsCount = inverseBindMatricesArray.getCount();

						size_t matrixCount = matrixElementsCount / 16;


						COLLADAFW::Matrix4Array& inverseBindMatrices = mCurrentSkinControllerData->getInverseBindMatrices();
						inverseBindMatrices.allocMemory( matrixCount );
						inverseBindMatrices.setCount( matrixCount );

						size_t index = 0;
						for ( size_t i = 0; i < matrixCount; ++i)
						{
							// fill the matrix
							COLLADABU::Math::Matrix4 matrix;
							for ( size_t j = 0; j < 16; ++j,++index)
							{
								matrix.setElement( j, inverseBindMatricesArray[index]);
							}
							inverseBindMatrices[i] = matrix;
						}
					}
					break;
				}
			}
			break;
		case MORPH_CONTROLLER:
			{
				switch ( semantic )
				{
				case SEMANTIC_MORPH_TARGET:
					{
						if ( !mCurrentMorphController )
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);
						StringListMap::const_iterator it = mJointIdsMap.find(sourceId);

						// check if the node sid array could be found
						if ( it == mJointIdsMap.end() )
						{
							if ( !handleFWLError ( SaxFWLError::ERROR_SOURCE_NOT_FOUND, "Source with id \"" + sourceId + "\" in morph controller with  id \"" + mOriginalId + "\" used in input with semantic SEMANTIC_MORPH_TARGET could not be found!" ))
								return false;
							break;
						}

						const StringList& meshIds = it->second;
						size_t meshIdCount = meshIds.size();

						COLLADAFW::UniqueIdArray& morphTargets = mCurrentMorphController->getMorphTargets();
						morphTargets.allocMemory(meshIdCount);
						morphTargets.setCount(meshIdCount);
						StringList::const_iterator itTarget = meshIds.begin();
						for ( size_t i = 0 ; itTarget != meshIds.end(); ++itTarget, ++i)
						{
							morphTargets[i] = createUniqueIdFromId( itTarget->c_str(), COLLADAFW::Geometry::ID());
						}

					}
					break;
				case SEMANTIC_MORPH_WEIGHT:
					{
						if ( !mCurrentMorphController)
						{
							break;
						}

						String sourceId = getIdFromURIFragmentType(attributeData.source);
						SourceBase* sourceBase = getSourceById( sourceId );

						if ( !sourceBase || (sourceBase->getDataType() != SourceBase::DATA_TYPE_REAL) )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "SourceBase of skin controller with semantic SEMANTIC_MORPH_WEIGHT not valid!" );
							break;
						}


						unsigned long long stride = sourceBase->getStride();
						if( stride == 0 )
						{
							handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Stride of sourceBase of skin controller with semantic SEMANTIC_MORPH_WEIGHT not found! Assuming stride 1!" );
							stride = 1;
						}
						if ( stride != 1 )
						{
                            handleFWLError ( SaxFWLError::ERROR_DATA_NOT_VALID, "Stride of sourceBase of skin controller with semantic SEMANTIC_MORPH_WEIGHT not valid!" );
							break;
						}
						const RealSource *weightSource = (const RealSource *)sourceBase;
						COLLADAFW::FloatOrDoubleArray& morphWeights = mCurrentMorphController->getMorphWeights();
						addToSidTree( sourceId.c_str(), 0, &morphWeights );
						moveUpInSidTree();

						setRealValues( morphWeights, weightSource );
					}
					break;
				}
			}
			break;
		}

		return true;
	}
	//------------------------------
	bool LibraryControllersLoader::end__library_controllers()
	{
		moveUpInSidTree();
		finish();
		return true;
	}
    //------------------------------
	bool LibraryJointsLoader::end__library_joints()
	{
		moveUpInSidTree();
		finish();
		return true;
	}