void EventsListSerialization::UpdateInstructionsFromGD31x(gd::Project & project, gd::InstructionsList & list, bool instructionsAreActions)
{
    for (std::size_t i = 0;i<list.size();++i)
    {
        gd::Instruction & instr = list[i];

        if (instr.GetType() == "VarScene" ||
            instr.GetType() == "VarSceneTxt" ||
            instr.GetType() == "VarGlobal" ||
            instr.GetType() == "VarGlobalTxt" ||
            instr.GetType() == "ModVarScene" ||
            instr.GetType() == "ModVarSceneTxt" ||
            instr.GetType() == "ModVarGlobal" ||
            instr.GetType() == "ModVarGlobalTxt" )
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 1 ) parameters.erase(parameters.begin()+0);
            instr.SetParameters(parameters);
        }

        if (instr.GetType() == "VarSceneDef" ||
            instr.GetType() == "VarGlobalDef" ||
            instr.GetType() == "VarObjetDef" )
        {
            instr.SetParameter(1, gd::Expression("\""+instr.GetParameter(1).GetPlainString()+"\""));
        }

        //UpdateInstructionsFromGD31x(project, instr.GetSubInstructions(), instructionsAreActions);
    }
}
bool EventsEditorSelection::FindInInstructionsAndSubInstructions(gd::InstructionsList & list, const gd::Instruction * instrToSearch)
{
    for (unsigned int i = 0;i<list.size();++i)
    {
        if ( &list[i] == instrToSearch) return true;
        if ( FindInInstructionsAndSubInstructions(list[i].GetSubInstructions(), instrToSearch) )
            return true;
    }

    return false;
}
std::set < std::string > EventsVariablesFinder::FindArgumentsInInstructions(const gd::Platform & platform,
    const gd::Project & project, const gd::Layout & layout, const gd::InstructionsList & instructions,
    bool instructionsAreConditions, const std::string & parameterType, const std::string & objectName)
{
    std::set < std::string > results;

    for (unsigned int aId = 0;aId < instructions.size();++aId)
    {
        std::string lastObjectParameter = "";
        gd::InstructionMetadata instrInfos = instructionsAreConditions ? MetadataProvider::GetConditionMetadata(platform, instructions[aId].GetType()) :
                                                                         MetadataProvider::GetActionMetadata(platform, instructions[aId].GetType());
        for (unsigned int pNb = 0;pNb < instrInfos.parameters.size();++pNb)
        {
            //The parameter has the searched type...
            if ( instrInfos.parameters[pNb].type == parameterType )
            {
                //...remember the value of the parameter.
                if (objectName.empty() || lastObjectParameter == objectName)
                    results.insert(instructions[aId].GetParameter(pNb).GetPlainString());
            }
            //Search in expressions
            else if (instrInfos.parameters[pNb].type == "expression")
            {
                CallbacksForSearchingVariable callbacks(results, parameterType, objectName);

                gd::ExpressionParser parser(instructions[aId].GetParameter(pNb).GetPlainString());
                parser.ParseMathExpression(platform, project, layout, callbacks);
            }
            //Search in string expressions
            else if (instrInfos.parameters[pNb].type == "string"||instrInfos.parameters[pNb].type == "file" ||instrInfos.parameters[pNb].type == "joyaxis" ||instrInfos.parameters[pNb].type == "color"||instrInfos.parameters[pNb].type == "layer")
            {
                CallbacksForSearchingVariable callbacks(results, parameterType, objectName);

                gd::ExpressionParser parser(instructions[aId].GetParameter(pNb).GetPlainString());
                parser.ParseStringExpression(platform, project, layout, callbacks);
            }
            //Remember the value of the last "object" parameter.
            else if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type))
            {
                lastObjectParameter = instructions[aId].GetParameter(pNb).GetPlainString();
            }
        }

        if ( !instructions[aId].GetSubInstructions().empty() )
            FindArgumentsInInstructions(platform, project, layout, instructions[aId].GetSubInstructions(),
                instructionsAreConditions, parameterType);
    }

    return results;
}
void gd::EventsListSerialization::OpenConditions(gd::Project & project, gd::InstructionsList & conditions, const SerializerElement & elem)
{
    elem.ConsiderAsArrayOf("condition", "Condition");
    for(std::size_t i = 0; i<elem.GetChildrenCount(); ++i)
    {
        gd::Instruction instruction;
        const SerializerElement & conditionElem = elem.GetChild(i);

        instruction.SetType(conditionElem.GetChild("type", 0, "Type").GetStringAttribute("value")
                .FindAndReplace("Automatism", "Behavior")); //Compatibility with GD <= 4
        instruction.SetInverted(conditionElem.GetChild("type", 0, "Type").GetBoolAttribute("inverted", false, "Contraire"));

        //Read parameters
        vector < gd::Expression > parameters;

        //Compatibility with GD <= 3.3
        if (conditionElem.HasChild("Parametre")) {

            for (std::size_t j = 0;j<conditionElem.GetChildrenCount("Parametre");++j)
                parameters.push_back(gd::Expression(conditionElem.GetChild("Parametre", j).GetValue().GetString()));

        }
        //end of compatibility code
        else
        {
            const SerializerElement & parametersElem = conditionElem.GetChild("parameters");
            parametersElem.ConsiderAsArrayOf("parameter");
            for (std::size_t j = 0;j<parametersElem.GetChildrenCount();++j)
                parameters.push_back(gd::Expression(parametersElem.GetChild(j).GetValue().GetString()));
        }

        instruction.SetParameters( parameters );

        //Read sub conditions
        if ( conditionElem.HasChild("subConditions", "SubConditions") )
            OpenConditions(project, instruction.GetSubInstructions(), conditionElem.GetChild("subConditions", 0, "SubConditions" ));

        conditions.Insert( instruction );
    }

    if ( project.GetLastSaveGDMajorVersion() < 3 ||
         (project.GetLastSaveGDMajorVersion() == 3 && project.GetLastSaveGDMinorVersion() <= 1 ) )
        UpdateInstructionsFromGD31x(project, conditions, false);

    if ( project.GetLastSaveGDMajorVersion() < 3 )
        UpdateInstructionsFromGD2x(project, conditions, false);
}
void gd::EventsListSerialization::SaveConditions(const gd::InstructionsList & list, SerializerElement & conditions)
{
    conditions.ConsiderAsArrayOf("condition");
    for ( std::size_t k = 0;k < list.size();k++ )
    {
        SerializerElement & condition = conditions.AddChild("condition");
        condition.AddChild("type")
            .SetAttribute("value", list[k].GetType())
            .SetAttribute("inverted", list[k].IsInverted());

        //Parameters
        SerializerElement & parameters = condition.AddChild("parameters");
        parameters.ConsiderAsArrayOf("parameter");
        for ( std::size_t l = 0;l < list[k].GetParameters().size();l++ )
            parameters.AddChild("parameter").SetValue(list[k].GetParameter(l).GetPlainString());

        //Sub instructions
        SerializerElement & subConditions = condition.AddChild("subConditions");
        SaveConditions(list[k].GetSubInstructions(), subConditions);
    }
}
void EventsListSerialization::UpdateInstructionsFromGD2x(gd::Project & project, gd::InstructionsList & list, bool instructionsAreActions)
{
    for (std::size_t i = 0;i<list.size();++i)
    {
        gd::Instruction & instr = list[i];

        const gd::InstructionMetadata & metadata = instructionsAreActions ?
                                             MetadataProvider::GetActionMetadata(project.GetCurrentPlatform(), instr.GetType()) :
                                             MetadataProvider::GetConditionMetadata(project.GetCurrentPlatform(), instr.GetType());

        //Specific updates for some instructions
        if ( instr.GetType() == "LinkedObjects::LinkObjects" || instr.GetType() == "LinkedObjects::RemoveLinkBetween" )
        {
            instr.SetParameter(1, instr.GetParameter(3));
            instr.SetParameter(2, instr.GetParameter(4));
        }
        else if (instr.GetType() == "LinkedObjects::RemoveAllLinksOf")
        {
            instr.SetParameter(1, instr.GetParameter(2));
        }
        else if (instr.GetType() == "LinkedObjects::PickObjectsLinkedTo")
        {
            instr.SetParameter(1, instr.GetParameter(5));
            instr.SetParameter(2, instr.GetParameter(3));
        }
        else if (instr.GetType() == "PhysicsBehavior::AddRevoluteJointBetweenObjects")
        {
            instr.SetParameter(4, instr.GetParameter(5));
            instr.SetParameter(5, instr.GetParameter(6));
        }
        else if (instr.GetType() == "FixCamera" || instr.GetType() == "CentreCamera")
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 3 ) parameters.erase(parameters.begin()+2);
            instr.SetParameters(parameters);
        }
        else if (instr.GetType() == "AjoutObjConcern" || instr.GetType() == "AjoutHasard")
        {
            instr.SetParameter(1, instr.GetParameter(3));
        }
        else if (instr.GetType() == "SeDirige" || instr.GetType() == "EstTourne" )
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 3 ) parameters.erase(parameters.begin()+2);
            if ( parameters.size() >= 3 ) parameters.erase(parameters.begin()+2);
            instr.SetParameters(parameters);
        }
        else if (instr.GetType() == "Create")
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 2 ) parameters.erase(parameters.begin()+1);
            if ( parameters.size() >= 2 ) parameters.erase(parameters.begin()+1);
            instr.SetParameters(parameters);
        }
        else if (instr.GetType() == "CreateByName")
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 2 ) parameters.erase(parameters.begin()+1);
            instr.SetParameters(parameters);
        }
        else if (instr.GetType() == "NbObjet")
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 2 ) parameters.erase(parameters.begin()+1);
            instr.SetParameters(parameters);
        }
        else if (instr.GetType() == "Distance")
        {
            std::vector< gd::Expression > parameters = instr.GetParameters();
            if ( parameters.size() >= 3 ) parameters.erase(parameters.begin()+2);
            if ( parameters.size() >= 3 ) parameters.erase(parameters.begin()+2);
            if ( parameters.size() >= 4 && (parameters[3].GetPlainString() == ">=" || parameters[3].GetPlainString() == ">") )
            {
                instr.SetInverted(true);
            }
            else
            {
                instr.SetInverted(false);
            }
            instr.SetParameters(parameters);
        }

        //Common updates for some parameters
        const std::vector< gd::Expression > & parameters = instr.GetParameters();
        for (std::size_t j = 0;j<parameters.size() && j<metadata.parameters.size();++j)
        {
            if ( metadata.parameters[j].type == "relationalOperator" ||
                 metadata.parameters[j].type == "operator" )
            {
                if ( j == parameters.size()-1 )
                {
                    std::cout << "ERROR: No more parameters after a [relational]operator when trying to update an instruction from GD2.x";
                }
                else
                {
                    //Exchange parameters
                    gd::String op = parameters[j+1].GetPlainString();
                    instr.SetParameter(j+1, parameters[j] );
                    instr.SetParameter(j, gd::Expression(op));
                }
            }
        }

        //UpdateInstructionsFromGD2x(project, instr.GetSubInstructions(), instructionsAreActions);
    }
}