//-------------------------------------------------------------------------
void PUAffectorTranslator::translate(PUScriptCompiler* compiler, PUAbstractNode *node)
{
    PUObjectAbstractNode* obj = reinterpret_cast<PUObjectAbstractNode*>(node);
    PUObjectAbstractNode* parent = obj->parent ? reinterpret_cast<PUObjectAbstractNode*>(obj->parent) : 0;
    
    // The name of the obj is the type of the affector
    // Remark: This can be solved by using a listener, so that obj->values is filled with type + name. Something for later
    std::string type;
    if(!obj->name.empty())
    {
        type = obj->name;
    }
    
    //// Get the factory
    //ParticleAffectorFactory* particleAffectorFactory = ParticleSystemManager::getSingletonPtr()->getAffectorFactory(type);
    //if (!particleAffectorFactory)
    //{
    //    compiler->addError(ScriptCompiler::CE_INVALIDPARAMETERS, obj->file, obj->line);
    //    return;
    //}
    PUScriptTranslator *particleAffectorTranlator = PUAffectorManager::Instance()->getTranslator(type);
    if (!particleAffectorTranlator) return;
    //// Create the affector
    //mAffector = ParticleSystemManager::getSingletonPtr()->createAffector(type);
    //if (!mAffector)
    //{
    //    compiler->addError(ScriptCompiler::CE_INVALIDPARAMETERS, obj->file, obj->line);
    //    return;
    //}
    _affector = PUAffectorManager::Instance()->createAffector(type);
    if (!_affector) return;
    _affector->setAffectorType(type);

    if (parent && parent->context)
    {
        PUParticleSystem3D* system = static_cast<PUParticleSystem3D*>(parent->context);
        system->addAffector(_affector);
    }
    
    // The first value is the (optional) name
    std::string name;
    if(!obj->values.empty())
    {
        getString(*obj->values.front(), &name);
        _affector->setName(name);
    }
    
    // Set it in the context
    obj->context = _affector;
    
    // Run through properties
    for(PUAbstractNodeList::iterator i = obj->children.begin(); i != obj->children.end(); ++i)
    {
        if((*i)->type == ANT_PROPERTY)
        {
            PUPropertyAbstractNode* prop = reinterpret_cast<PUPropertyAbstractNode*>((*i));
            if (prop->name == token[TOKEN_ENABLED])
            {
                // Property: enabled
                if (passValidateProperty(compiler, prop, token[TOKEN_ENABLED], VAL_BOOL))
                {
                    bool val;
                    if(getBoolean(*prop->values.front(), &val))
                    {
                        _affector->setEnabled(val);
                    }
                }
            }
            else if (prop->name == token[TOKEN_POSITION])
            {
                // Property: position
                if (passValidateProperty(compiler, prop, token[TOKEN_POSITION], VAL_VECTOR3))
                {
                    Vec3 val;
                    if(getVector3(prop->values.begin(), prop->values.end(), &val))
                    {
                        //mAffector->position = val;
                        //mAffector->originalPosition = val;
                        _affector->setLocalPosition(val);
                    }
                }
            }
            else if (prop->name == token[TOKEN_AFFECTOR_MASS])
            {
                if (passValidateProperty(compiler, prop, token[TOKEN_AFFECTOR_MASS], VAL_REAL))
                {
                    float val = 0.0f;
                    if(getFloat(*prop->values.front(), &val))
                    {
                        _affector->setMass(val);
                    }
                }
            }
            else if (prop->name == token[TOKEN_AFFECTOR_SPECIALISATION])
            {
                if (passValidateProperty(compiler, prop, token[TOKEN_AFFECTOR_SPECIALISATION], VAL_STRING))
                {
                    std::string val;
                    if(getString(*prop->values.front(), &val))
                    {
                        if (val == token[TOKEN_AFFECTOR_SPEC_DEFAULT])
                        {
                            _affector->setAffectSpecialisation(PUAffector::AFSP_DEFAULT);
                        }
                        else if (val == token[TOKEN_AFFECTOR_SPEC_TTL_INCREASE])
                        {
                            _affector->setAffectSpecialisation(PUAffector::AFSP_TTL_INCREASE);
                        }
                        else if (val == token[TOKEN_AFFECTOR_SPEC_TTL_DECREASE])
                        {
                            _affector->setAffectSpecialisation(PUAffector::AFSP_TTL_DECREASE);
                        }
                    }
                }
            }
            else if (prop->name == token[TOKEN_AFFECTOR_EXCLUDE_EMITTER])
            {
                if (passValidatePropertyNoValues(compiler, prop, token[TOKEN_AFFECTOR_EXCLUDE_EMITTER]))
                {
                    for(PUAbstractNodeList::iterator j = prop->values.begin(); j != prop->values.end(); ++j)
                    {
                        std::string val;
                        if(getString(**j, &val))
                        {
                            _affector->addEmitterToExclude(val);
                        }
                    }
                }
            }
            else if (particleAffectorTranlator->translateChildProperty(compiler, *i))
            {
                // Parsed the property by another translator; do nothing
            }
            else
            {
                errorUnexpectedProperty(compiler, prop);
            }
        }
        else if((*i)->type == ANT_OBJECT)
        {
            if (particleAffectorTranlator->translateChildObject(compiler, *i))
            {
                // Parsed the object by another translator; do nothing
            }
            else
            {
                processNode(compiler, *i);
            }
        }
        else
        {
            errorUnexpectedToken(compiler, *i);
        }
    }
}
	//-------------------------------------------------------------------------
	bool ScriptTranslator::passValidateProperty(Ogre::ScriptCompiler* compiler, 
		Ogre::PropertyAbstractNode* prop, 
		const Ogre::String& token,
		ValidationType validationType)
	{
		if (!passValidatePropertyNoValues(compiler, prop, token))
		{
			return false;
		}

		bool ret = true;
		switch(validationType)
		{
			case VAL_BOOL:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 1) && passValidatePropertyValidBool(compiler, prop);
			}
			break;
			case VAL_COLOURVALUE:
			{
				ret = passValidatePropertyNumberOfValuesRange(compiler, prop, token, 3, 4);
			}
			break;
			case VAL_INT:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 1) && passValidatePropertyValidInt(compiler, prop);
			}
			break;
			case VAL_QUATERNION:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 4) && passValidatePropertyValidQuaternion(compiler, prop);
			}
			break;
			case VAL_REAL:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 1) && passValidatePropertyValidReal(compiler, prop);
			}
			break;
			case VAL_STRING:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 1);
			}
			break;
			case VAL_UINT:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 1) && passValidatePropertyValidUint(compiler, prop);
			}
			break;
			case VAL_VECTOR2:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 2) && passValidatePropertyValidVector2(compiler, prop);
			}
			break;
			case VAL_VECTOR3:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 3) && passValidatePropertyValidVector3(compiler, prop);
			}
			break;
			case VAL_VECTOR4:
			{
				ret = passValidatePropertyNumberOfValues(compiler, prop, token, 4) && passValidatePropertyValidVector4(compiler, prop);
			}
			break;
		}

		return ret;
	}
	//-------------------------------------------------------------------------
	void SystemTranslator::translate(ScriptCompiler* compiler, const AbstractNodePtr &node)
	{
		ObjectAbstractNode* obj = reinterpret_cast<ObjectAbstractNode*>(node.get());
		if(obj->name.empty())
		{
			compiler->addError(ScriptCompiler::CE_OBJECTNAMEEXPECTED, obj->file, obj->line);
			return;
		}

		// Create a particle system with the given name
		mSystem = ParticleSystemManager::getSingletonPtr()->createParticleSystemTemplate(obj->name, compiler->getResourceGroup());
		if (!mSystem)
		{
			compiler->addError(ScriptCompiler::CE_INVALIDPARAMETERS, obj->file, obj->line);
			return;
		}
		obj->context = Any(mSystem);

		for(AbstractNodeList::iterator i = obj->children.begin(); i != obj->children.end(); ++i)
		{
			if((*i)->type == ANT_PROPERTY)
			{
				PropertyAbstractNode* prop = reinterpret_cast<PropertyAbstractNode*>((*i).get());
				if (prop->name == token[TOKEN_PS_ITERATION_INTERVAL])
				{
					// Property: iteration_interval
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_ITERATION_INTERVAL], VAL_REAL))
					{
						Real val = 0.0f;
						if(getReal(prop->values.front(), &val))
						{
							mSystem->setIterationInterval(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_NONVIS_UPDATE_TIMEOUT])
				{
					// Property: nonvisible_update_timeout
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_NONVIS_UPDATE_TIMEOUT], VAL_REAL))
					{
						Real val = 0.0f;
						if(getReal(prop->values.front(), &val))
						{
							mSystem->setNonVisibleUpdateTimeout(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_FIXED_TIMEOUT])
				{
					// Property: fixed_timeout
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_FIXED_TIMEOUT], VAL_REAL))
					{
						Real val = 0.0f;
						if(getReal(prop->values.front(), &val))
						{
							mSystem->setFixedTimeout(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_LOD_DISTANCES])
				{
					// Property: lod_distances
					if (passValidatePropertyNoValues(compiler, prop, token[TOKEN_PS_LOD_DISTANCES]))
					{
						for(AbstractNodeList::iterator j = prop->values.begin(); j != prop->values.end(); ++j)
						{
							Real val = 0.0f;
							if(getReal(*j, &val))
							{
								mSystem->addLodDistance(val);
							}
							else
							{
								compiler->addError(ScriptCompiler::CE_NUMBEREXPECTED, prop->file, prop->line,
									"PU Compiler: lod_distances expects only numbers as arguments");
							}
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_MAIN_CAMERA_NAME])
				{
					// Property: main_camera_name
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_MAIN_CAMERA_NAME], VAL_STRING))
					{
						String val;
						if(getString(prop->values.front(), &val))
						{
							mSystem->setMainCameraName(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_SMOOTH_LOD])
				{
					// Property: smooth_lod
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_SMOOTH_LOD], VAL_BOOL))
					{
						bool val;
						if(getBoolean(prop->values.front(), &val))
						{
							mSystem->setSmoothLod(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_FAST_FORWARD])
				{
					// Property: fast_forward
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_SCALE], VAL_VECTOR2))
					{
						Vector2 val;
						if(getVector2(prop->values.begin(), prop->values.end(), &val))
						{
							mSystem->setFastForward(val.x, val.y);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_SCALE])
				{
					// Property: scale
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_SCALE], VAL_VECTOR3))
					{
						Vector3 val;
						if(getVector3(prop->values.begin(), prop->values.end(), &val))
						{
							mSystem->setScale(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_SCALE_VELOCITY])
				{
					// Property: scale_velocity
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_ITERATION_INTERVAL], VAL_REAL))
					{
						Real val = 0.0f;
						if(getReal(prop->values.front(), &val))
						{
							mSystem->setScaleVelocity(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_SCALE_TIME])
				{
					// Property: scale_time
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_SCALE_TIME], VAL_REAL))
					{
						Real val = 0.0f;
						if(getReal(prop->values.front(), &val))
						{
							mSystem->setScaleTime(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_KEEP_LOCAL])
				{
					// Property: keep_local
					if (passValidateProperty(compiler, prop, token[TOKEN_KEEP_LOCAL], VAL_BOOL))
					{
						bool val;
						if(getBoolean(prop->values.front(), &val))
						{
							mSystem->setKeepLocal(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_TIGHT_BOUNDING_BOX])
				{
					// Property: tight_bounding_box
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_TIGHT_BOUNDING_BOX], VAL_BOOL))
					{
						bool val;
						if(getBoolean(prop->values.front(), &val))
						{
							mSystem->setTightBoundingBox(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_PS_CATEGORY])
				{
					// Property: category
					if (passValidateProperty(compiler, prop, token[TOKEN_PS_CATEGORY], VAL_STRING))
					{
						String val;
						if(getString(prop->values.front(), &val))
						{
							mSystem->setCategory(val);
						}
					}
				}
				else if (prop->name == token[TOKEN_USE_ALIAS])
				{
					// Property: use_alias
					// The alias can only be a technique
					if (passValidateProperty(compiler, prop, token[TOKEN_USE_ALIAS], VAL_STRING))
					{
						String val;
						if(getString(prop->values.front(), &val))
						{
							IAlias* alias = ParticleSystemManager::getSingletonPtr()->getAlias(val);
							if (alias->getAliasType() == IAlias::AT_TECHNIQUE)
							{
								ParticleTechnique* technique = static_cast<ParticleTechnique*>(alias);
								ParticleTechnique* newTechnique = ParticleSystemManager::getSingletonPtr()->cloneTechnique(technique);
								mSystem->addTechnique(newTechnique);
							}
						}
					}
				}
				else
				{
					errorUnexpectedProperty(compiler, prop);
				}
			}
			else if((*i)->type == ANT_OBJECT)
			{
				processNode(compiler, *i);
			}
            else
			{
				errorUnexpectedToken(compiler, *i);
			}
		}
	}