PLCControler.py
author etisserant
Wed, 31 Jan 2007 16:31:39 +0100
changeset 0 b622defdfd98
child 2 93bc4c2cf376
permissions -rw-r--r--
PLCOpenEditor initial commit. 31/01/07.
#!/usr/bin/env python
# -*- coding: utf-8 -*-

#This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
#based on the plcopen standard. 
#
#Copyright (C): Edouard TISSERANT and Laurent BESSARD
#
#See COPYING file for copyrights details.
#
#This library is free software; you can redistribute it and/or
#modify it under the terms of the GNU Lesser General Public
#License as published by the Free Software Foundation; either
#version 2.1 of the License, or (at your option) any later version.
#
#This library is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#Lesser General Public License for more details.
#
#You should have received a copy of the GNU Lesser General Public
#License along with this library; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

from minixsv import pyxsval
import cPickle
import os,sys,re

from plcopen import plcopen
from plcopen.structures import *
from graphics.GraphicCommons import *
from PLCGenerator import *

[ITEM_UNEDITABLE, ITEM_PROJECT, ITEM_POU, ITEM_CLASS, ITEM_VARIABLE,
 ITEM_TRANSITION, ITEM_ACTION, ITEM_CONFIGURATION, ITEM_RESOURCE] = range(9)

#-------------------------------------------------------------------------------
#                         Undo Buffer for PLCOpenEditor
#-------------------------------------------------------------------------------

# Length of the buffer
UNDO_BUFFER_LENGTH = 20

"""
Class implementing a buffer of changes made on the current editing Object Dictionary
"""
class UndoBuffer:

    # Constructor initialising buffer
    def __init__(self, currentstate, issaved = False):
        self.Buffer = []
        self.CurrentIndex = -1
        self.MinIndex = -1
        self.MaxIndex = -1
        # if current state is defined
        if currentstate:
            self.CurrentIndex = 0
            self.MinIndex = 0
            self.MaxIndex = 0
        # Initialising buffer with currentstate at the first place
        for i in xrange(UNDO_BUFFER_LENGTH):
            if i == 0:
                self.Buffer.append(currentstate)
            else:
                self.Buffer.append(None)
        # Initialising index of state saved
        if issaved:
            self.LastSave = 0
        else:
            self.LastSave = -1
    
    # Add a new state in buffer
    def Buffering(self, currentstate):
        self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
        self.Buffer[self.CurrentIndex] = currentstate
        # Actualising buffer limits
        self.MaxIndex = self.CurrentIndex
        if self.MinIndex == self.CurrentIndex:
            # If the removed state was the state saved, there is no state saved in the buffer
            if self.LastSave == self.MinIndex:
                self.LastSave = -1
            self.MinIndex = (self.MinIndex + 1) % UNDO_BUFFER_LENGTH
        self.MinIndex = max(self.MinIndex, 0)
    
    # Return current state of buffer
    def Current(self):
        return self.Buffer[self.CurrentIndex]
    
    # Change current state to previous in buffer and return new current state
    def Previous(self):
        if self.CurrentIndex != self.MinIndex:
            self.CurrentIndex = (self.CurrentIndex - 1) % UNDO_BUFFER_LENGTH
            return self.Buffer[self.CurrentIndex]
        return None
    
    # Change current state to next in buffer and return new current state
    def Next(self):
        if self.CurrentIndex != self.MaxIndex:
            self.CurrentIndex = (self.CurrentIndex + 1) % UNDO_BUFFER_LENGTH
            return self.Buffer[self.CurrentIndex]
        return None
    
    # Return True if current state is the first in buffer
    def IsFirst(self):
        return self.CurrentIndex == self.MinIndex
    
    # Return True if current state is the last in buffer
    def IsLast(self):
        return self.CurrentIndex == self.MaxIndex

    # Note that current state is saved
    def CurrentSaved(self):
        self.LastSave = self.CurrentIndex
        
    # Return True if current state is saved
    def IsCurrentSaved(self):
        return self.LastSave == self.CurrentIndex


#-------------------------------------------------------------------------------
#                           Controler for PLCOpenEditor
#-------------------------------------------------------------------------------

"""
Class which controls the operations made on the plcopen model and answers to view requests
"""
class PLCControler:
    
    # Create a new PLCControler
    def __init__(self):
        self.LastNewIndex = 0
        self.Reset()
    
    # Reset PLCControler internal variables
    def Reset(self):
        self.Project = None
        self.ProjectBuffer = None
        self.FilePath = ""
        self.FileName = ""
        self.ElementsOpened = []
        self.CurrentElementEditing = None
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()

    def GetQualifierTypes(self):
        return plcopen.QualifierList


#-------------------------------------------------------------------------------
#                         Project management functions
#-------------------------------------------------------------------------------

    # Return if a project is opened
    def HasOpenedProject(self):
        return self.Project != None

    # Create a new project by replacing the current one
    def CreateNewProject(self, name):
        # Create the project
        self.Project = plcopen.project()
        self.Project.setName(name)
        # Initialize the project buffer
        self.ProjectBuffer = UndoBuffer(self.Copy(self.Project))
    
    # Change project name
    def SetProjectName(self, name):
        self.Project.setName(name)
    
    # Return project name
    def GetProjectName(self):
        return self.Project.getName()
    
    # Return project pou names
    def GetProjectPouNames(self):
        return [pou.getName() for pou in self.Project.getPous()]
    
    # Return project pou names
    def GetProjectConfigNames(self):
        return [config.getName() for config in self.Project.getConfigurations()]
    
    # Return file path if project is an open file
    def GetFilePath(self):
        return self.FilePath
    
    # Return file name and point out if file is up to date
    def GetFilename(self):
        if self.ProjectBuffer.IsCurrentSaved():
            return self.FileName
        else:
            return "~%s~"%self.FileName
    
    # Change file path and save file name or create a default one if file path not defined
    def SetFilePath(self, filepath):
        self.FilePath = filepath
        if filepath == "":
            self.LastNewIndex += 1
            self.FileName = "Unnamed%d"%self.LastNewIndex
        else:
            self.FileName = os.path.splitext(os.path.basename(filepath))[0]
    
    # Change project properties
    def SetProjectProperties(self, values):
        self.Project.setFileHeader(values)
    
    # Return project properties
    def GetProjectProperties(self):
        return self.Project.getFileHeader()
    
    # Return project informations
    def GetProjectInfos(self):
        if self.Project:
            infos = {"name": self.Project.getName(), "type": ITEM_PROJECT}
            pou_types = {"function": {"name": "Functions", "type": ITEM_UNEDITABLE, "values":[]},
                         "functionBlock": {"name": "Function Blocks", "type": ITEM_UNEDITABLE, "values":[]},
                         "program": {"name": "Programs", "type": ITEM_UNEDITABLE, "values":[]}}
            for pou in self.Project.getPous():
                pou_type = pou.getPouType().getValue()
                pou_infos = {"name": pou.getName(), "type": ITEM_POU}
                var_types = {"Input": {"name": "Input", "type": ITEM_CLASS, "values": []},
                         "Output": {"name": "Output", "type": ITEM_CLASS, "values": []},
                         "InOut": {"name": "InOut", "type": ITEM_CLASS, "values": []},
                         "External": {"name": "External", "type": ITEM_CLASS, "values": []},
                         "Local": {"name": "Local", "type": ITEM_CLASS, "values": []},
                         "Temp": {"name": "Temp", "type": ITEM_CLASS, "values": []},
                         "Global": {"name": "Global", "type": ITEM_CLASS, "values": []}}
                for var in self.GetPouInterfaceVars(pou):
                    var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
                    if var["Class"] in var_types.keys():
                        var_types[var["Class"]]["values"].append(var_values)
                pou_values = []
                pou_values.append({"name": "Interface", "type": ITEM_CLASS, 
                    "values": [var_types["Input"], var_types["Output"], var_types["InOut"], var_types["External"]]})
                pou_values.append({"name": "Variables", "type": ITEM_CLASS, 
                    "values": [var_types["Local"], var_types["Temp"]]})
                if pou_type == "program":
                    pou_values.append(var_types["Global"])
                if pou.getBodyType() == "SFC":
                    transitions = []
                    for transition in pou.getTransitionList():
                        transitions.append({"name": transition.getName(), "type": ITEM_TRANSITION, "values": []})
                    pou_values.append({"name": "Transitions", "type": ITEM_UNEDITABLE, "values": transitions})
                    actions = []
                    for action in pou.getActionList():
                        actions.append({"name": action.getName(), "type": ITEM_ACTION, "values": []})
                    pou_values.append({"name": "Actions", "type": ITEM_UNEDITABLE, "values": actions})
                if pou_type in pou_types:
                    pou_infos["values"] = pou_values
                    pou_types[pou_type]["values"].append(pou_infos)
            configurations = {"name": "Configurations", "type": ITEM_UNEDITABLE, "values": []}
            for config in self.Project.getConfigurations():
                config_name = config.getName()
                config_infos = {"name": config_name, "type": ITEM_CONFIGURATION, "values": []}
                config_vars = {"name": "Global", "type": ITEM_CLASS, "values": []}
                for var in self.GetConfigurationGlobalVars(config_name):
                    var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
                    config_vars["values"].append(var_values)
                resources = {"name": "Resources", "type": ITEM_UNEDITABLE, "values": []}
                for resource in config.getResource():
                    resource_name = resource.getName()
                    resource_infos = {"name": resource_name, "type": ITEM_RESOURCE, "values": []}
                    resource_vars = {"name": "Global", "type": ITEM_CLASS, "values": []}
                    for var in self.GetConfigurationResourceGlobalVars(config_name, resource_name):
                        var_values = {"name": var["Name"], "type": ITEM_VARIABLE, "values": []}
                        resource_vars["values"].append(var_values)
                    resource_infos["values"].append(resource_vars)
                    resources["values"].append(resource_infos)
                config_infos["values"] = [config_vars, resources]
                configurations["values"].append(config_infos)
            infos["values"] = [{"name": "Properties", "type": ITEM_UNEDITABLE, "values": []},
                               pou_types["function"], pou_types["functionBlock"], 
                               pou_types["program"], configurations]
            return infos
        return None

    # Refresh the tree of user-defined pou cross-use
    def RefreshPouUsingTree(self):
        # Reset the tree of user-defined pou cross-use
        self.PouUsingTree = {}
        if self.Project:
            pous = self.Project.getPous()
            # Reference all the user-defined pou names and initialize the tree of 
            # user-defined pou cross-use
            pounames = [pou.getName() for pou in pous]
            for name in pounames:
                self.PouUsingTree[name] = []
            # Analyze each pou 
            for pou in pous:
                name = pou.getName()
                bodytype = pou.getBodyType()
                # If pou is written in a graphical language
                if bodytype in ["FBD","LD","SFC"]:
                    # Analyze each instance of the pou
                    for instance in pou.getInstances():
                        if isinstance(instance, plcopen.block):
                            typename = instance.getTypeName()
                            # Update tree if there is a cross-use
                            if typename in pounames and name not in self.PouUsingTree[typename]:
                                 self.PouUsingTree[typename].append(name)
                # If pou is written in a textual language
                elif bodytype in ["IL", "ST"]:
                    text = pou.getText()
                    # Search if each pou is mentioned in the pou text
                    for typename in pounames:
                        typename_model = re.compile("[ \t\n]%s[ \t\n]"%typename)
                        # Update tree if there is a cross-use
                        if typename != name and typename_model.search(text):
                            self.PouUsingTree[typename].append(name)

    # Return if pou given by name is used by another pou
    def PouIsUsed(self, name):
        if name in self.PouUsingTree:
            return len(self.PouUsingTree[name]) > 0
        return False

    # Return if pou given by name is directly or undirectly used by the reference pou
    def PouIsUsedBy(self, name, reference):
        if name in self.PouUsingTree:
            list = self.PouUsingTree[name]
            # Test if pou is directly used by reference
            if reference in list:
                return True
            else:
                # Test if pou is undirectly used by reference, by testing if pous 
                # that directly use pou is directly or undirectly used by reference
                used = False
                for element in list:
                    used |= self.PouIsUsedBy(element, reference)
                return used
        return False

    def GenerateProgram(self):
        if self.Project:
            program = GenerateCurrentProgram(self.Project)
            programfile = open("test.st", "w")
            programfile.write(program)
            programfile.close()

#-------------------------------------------------------------------------------
#                        Project Pous management functions
#-------------------------------------------------------------------------------
    
    # Add a Pou to Project
    def ProjectAddPou(self, name, pou_type, body_type):
        # Add the pou to project
        self.Project.appendPou(name, pou_type, body_type)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Remove a pou from project
    def ProjectRemovePou(self, name):
        removed = None
        # Search if the pou removed is currently opened
        for i, pou in enumerate(self.ElementsOpened):
            if pou == name:
                removed = i
        # If found, remove pou from list of opened pous and actualize current edited
        if removed != None:
            self.ElementsOpened.pop(removed)
            if self.CurrentElementEditing > removed:
                self.CurrentElementEditing -= 1
            if len(self.ElementsOpened) > 0:
                self.CurrentElementEditing = max(0, min(self.CurrentElementEditing, len(self.ElementsOpened) - 1))
            else:
                self.CurrentElementEditing = None
        # Remove pou from project
        self.Project.removePou(name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Add a configuration to Project
    def ProjectAddConfiguration(self, name):
        self.Project.addConfiguration(name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Remove a configuration from project
    def ProjectRemoveConfiguration(self, name):
        self.Project.removeConfiguration(name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Add a resource to a configuration of the Project
    def ProjectAddConfigurationResource(self, config, name):
        self.Project.addConfigurationResource(config, name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Remove a resource from a configuration of the project
    def ProjectRemoveConfigurationResource(self, config, name):
        self.Project.removeConfigurationResource(config, name)
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Add a Transition to a Project Pou
    def ProjectAddPouTransition(self, pou_name, transition_name, transition_type):
        pou = self.Project.getPou(pou_name)
        pou.addTransition(transition_name, transition_type)
    
    # Add a Transition to a Project Pou
    def ProjectAddPouAction(self, pou_name, action_name, action_type):
        pou = self.Project.getPou(pou_name)
        pou.addAction(action_name, action_type)
        
    # Change the name of a pou
    def ChangePouName(self, old_name, new_name):
        # Found the pou corresponding to old name and change its name to new name
        pou = self.Project.getPou(old_name)
        pou.setName(new_name)
        # If pou is currently opened, change its name in the list of opened pous
        if old_name in self.ElementsOpened:
            idx = self.ElementsOpened.index(old_name)
            self.ElementsOpened[idx] = new_name
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()
    
    # Change the name of a pou transition
    def ChangePouTransitionName(self, pou_name, old_name, new_name):
        # Found the pou transition corresponding to old name and change its name to new name
        pou = self.Project.getPou(pou_name)
        transition = pou.getTransition(old_name)
        transition.setName(new_name)
        # If pou transition is currently opened, change its name in the list of opened elements
        old_computedname = self.ComputePouTransitionName(pou_name, old_name)
        new_computedname = self.ComputePouTransitionName(pou_name, new_name)
        if old_computedname in self.ElementsOpened:
            idx = self.ElementsOpened.index(old_computedname)
            self.ElementsOpened[idx] = new_computedname
    
    # Change the name of a pou action
    def ChangePouActionName(self, pou_name, old_name, new_name):
        # Found the pou action corresponding to old name and change its name to new name
        pou = self.Project.getPou(pou_name)
        action = pou.getAction(old_name)
        action.setName(new_name)
        # If pou action is currently opened, change its name in the list of opened elements
        old_computedname = self.ComputePouActionName(pou_name, old_name)
        new_computedname = self.ComputePouActionName(pou_name, new_name)
        if old_computedname in self.ElementsOpened:
            idx = self.ElementsOpened.index(old_computedname)
            self.ElementsOpened[idx] = new_computedname

    # Change the name of a configuration
    def ChangeConfigurationName(self, old_name, new_name):
        # Found the configuration corresponding to old name and change its name to new name
        configuration = self.Project.getConfiguration(old_name)
        configuration.setName(new_name)
        # If configuration is currently opened, change its name in the list of opened elements
        for idx, element in enumerate(self.ElementsOpened):
            self.ElementsOpened[idx] = element.replace(old_name, new_name)

    # Change the name of a configuration resource
    def ChangeConfigurationResourceName(self, config_name, old_name, new_name):
        # Found the resource corresponding to old name and change its name to new name
        resource = self.Project.getConfigurationResource(config_name)
        resource.setName(new_name)
        # If resource is currently opened, change its name in the list of opened elements
        old_computedname = self.ComputeConfigurationResourceName(config_name, old_name)
        new_computedname = self.ComputeConfigurationResourceName(config_name, new_name)
        if old_computedname in self.ElementsOpened:
            idx = self.ElementsOpened.index(old_computedname)
            self.ElementsOpened[idx] = new_computedname
    
    # Return the type of the pou given by its name
    def GetPouType(self, name):
        # Found the pou correponding to name and return its type
        pou = self.Project.getPou(name)
        return pou.pouType.getValue()
    
    # Return pous with SFC language
    def GetSFCPous(self):
        list = []
        if self.Project:
            for pou in self.Project.getPous():
                if pou.getBodyType() == "SFC":
                    list.append(pou.getName())
        return list
    
    # Return the body language of the pou given by its name
    def GetPouBodyType(self, name):
        # Found the pou correponding to name and return its body language
        pou = self.Project.getPou(name)
        return pou.getBodyType()
    
    # Return the body language of the transition given by its name
    def GetTransitionBodyType(self, pou_name, pou_transition):
        # Found the pou correponding to name and return its body language
        pou = self.Project.getPou(pou_name)
        transition = pou.getTransition(pou_transition)
        return transition.getBodyType()
    
    # Return the body language of the pou given by its name
    def GetActionBodyType(self, pou_name, pou_action):
        # Found the pou correponding to name and return its body language
        pou = self.Project.getPou(pou_name)
        action = pou.getAction(pou_action)
        return action.getBodyType()
    
    # Extract varlists from a list of vars
    def ExtractVarLists(self, vars):
        varlist_list = []
        current_varlist = None
        current_type = None
        for var in vars:
            if current_type != (var["Class"], var["Retain"], var["Constant"]):
                current_type = (var["Class"], var["Retain"], var["Constant"])
                current_varlist = plcopen.varList()
                varlist_list.append((var["Class"], current_varlist))
                if var["Retain"] == "Yes":
                    varlist.setRetain(True)
                if var["Constant"] == "Yes":
                    varlist.setConstant(True)
            # Create variable and change its properties
            tempvar = plcopen.varListPlain_variable()
            tempvar.setName(var["Name"])
            var_type = plcopen.dataType()
            var_type.setValue(var["Type"])
            tempvar.setType(var_type)
            if var["Initial Value"] != "":
                value = plcopen.value()
                value.setValue(var["Initial Value"])
                tempvar.setInitialValue(value)
            if var["Location"] != "":
                tempvar.setAddress(var["Location"])
            # Add variable to varList
            current_varlist.appendVariable(tempvar)
        return varlist_list

    # Replace the configuration globalvars by those given
    def SetConfigurationGlobalVars(self, name, vars):
        # Found the configuration corresponding to name
        configuration = self.Project.getConfiguration(name)
        if configuration:
            # Set configuration global vars
            configuration.setGlobalVars([])
            for vartype, varlist in self.ExtractVarLists(vars):
                configuration.globalVars.append(varlist)
        self.RefreshBlockTypes()

    # Return the configuration globalvars
    def GetConfigurationGlobalVars(self, name):
        vars = []
        # Found the configuration corresponding to name
        configuration = self.Project.getConfiguration(name)
        if configuration:
            # Extract variables from every varLists
            for varlist in configuration.getGlobalVars():
                for var in varlist.getVariable():
                    tempvar = {"Name":var.getName(),"Class":"Global","Type":var.getType().getValue(),
                        "Location":var.getAddress()}
                    initial = var.getInitialValue()
                    if initial:
                        tempvar["Initial Value"] = initial.getValue()
                    else:
                        tempvar["Initial Value"] = ""
                    if varlist.getRetain():
                        tempvar["Retain"] = "Yes"
                    else:
                        tempvar["Retain"] = "No"
                    if varlist.getConstant():
                        tempvar["Constant"] = "Yes"
                    else:
                        tempvar["Constant"] = "No"
                    vars.append(tempvar)
        return vars

    # Replace the resource globalvars by those given
    def SetConfigurationResourceGlobalVars(self, config_name, name, vars):
        # Found the resource corresponding to name
        resource = self.Project.getConfigurationResource(config_name, name)
        # Set resource global vars
        if resource:
            resource.setGlobalVars([])
            for vartype, varlist in self.ExtractVarLists(vars):
                resource.globalVars.append(varlist)
        self.RefreshBlockTypes()

    # Return the resource globalvars
    def GetConfigurationResourceGlobalVars(self, config_name, name):
        vars = []
        # Found the resource corresponding to name
        resource = self.Project.getConfigurationResource(config_name, name)
        if resource:
            # Extract variables from every varLists
            for varlist in resource.getGlobalVars():
                for var in varlist.getVariable():
                    tempvar = {"Name":var.getName(),"Class":"Global","Type":var.getType().getValue(),
                        "Location":var.getAddress()}
                    initial = var.getInitialValue()
                    if initial:
                        tempvar["Initial Value"] = initial.getValue()
                    else:
                        tempvar["Initial Value"] = ""
                    if varlist.getRetain():
                        tempvar["Retain"] = "Yes"
                    else:
                        tempvar["Retain"] = "No"
                    if varlist.getConstant():
                        tempvar["Constant"] = "Yes"
                    else:
                        tempvar["Constant"] = "No"
                    vars.append(tempvar)
        return vars
    
    # Return the interface of the pou given by its name
    def GetPouInterfaceVarsByName(self, name):
        # Found the pou correponding to name and return the interface
        return self.GetPouInterfaceVars(self.Project.getPou(name))
    
    # Return the interface for the given pou
    def GetPouInterfaceVars(self, pou):
        vars = []
        # Verify that the pou has an interface
        if pou.interface:
            # Extract variables from every varLists
            for type, varlist in pou.getVars():
                for var in varlist.getVariable():
                    tempvar = {"Name":var.getName(),"Class":type,"Type":var.getType().getValue(),
                        "Location":var.getAddress()}
                    initial = var.getInitialValue()
                    if initial:
                        tempvar["Initial Value"] = initial.getValue()
                    else:
                        tempvar["Initial Value"] = ""
                    if varlist.getRetain():
                        tempvar["Retain"] = "Yes"
                    else:
                        tempvar["Retain"] = "No"
                    if varlist.getConstant():
                        tempvar["Constant"] = "Yes"
                    else:
                        tempvar["Constant"] = "No"
                    vars.append(tempvar)
        return vars

    # Replace the Pou interface by the one given
    def SetPouInterfaceVars(self, name, vars):
        # Found the pou corresponding to name and add interface if there isn't one yet
        pou = self.Project.getPou(name)
        if not pou.interface:
            pou.interface = plcopen.pou_interface()
        # Set Pou interface
        pou.setVars(self.ExtractVarLists(vars))
        self.RefreshBlockTypes()

    # Replace the return type of the pou given by its name (only for functions)
    def SetPouInterfaceReturnType(self, name, type):
        pou = self.Project.getPou(name)
        if not pou.interface:
            pou.interface = plcopen.pou_interface()
        # If there isn't any return type yet, add it
        return_type = pou.interface.getReturnType()
        if not return_type:
            return_type = plcopen.dataType()
            pou.interface.setReturnType(return_type)
        # Change return type
        return_type.setValue(type)
        self.RefreshBlockTypes()
    
    # Return the return type of the pou given by its name
    def GetPouInterfaceReturnTypeByName(self, name):
        # Found the pou correponding to name and return the return type
        return self.GetPouInterfaceReturnType(self.Project.getPou(name))
    
    # Return the return type of the given pou
    def GetPouInterfaceReturnType(self, pou):
        # Verify that the pou has an interface
        if pou.interface:
            # Return the return type if there is one
            return_type = pou.interface.getReturnType()
            if return_type:
                return return_type.getValue()
        return None

    # Update Block types with user-defined pou added
    def RefreshBlockTypes(self):
        if BlockTypes[-1]["name"] == "User-defined POUs":
            BlockTypes[-1]["list"] = []
        else:
            BlockTypes.append({"name" : "User-defined POUs", "list": []})
        if self.Project:
            for pou in self.Project.getPous():
                pou_name = pou.getName()
                pou_type = pou.pouType.getValue()
                if pou_type != "program":
                    block_infos = {"name" : pou_name, "type" : pou_type, "extensible" : False,
                                   "inputs" : [], "outputs" : [], "comment" : ""}
                    if pou.getInterface():
                        for type, varlist in pou.getVars():
                            if type == "InOut":
                                for var in varlist.getVariable():
                                    block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none"))
                                    block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none"))
                            elif type == "Input":
                                for var in varlist.getVariable():
                                    block_infos["inputs"].append((var.getName(),var.getType().getValue(),"none"))
                            elif type == "Output":
                                for var in varlist.getVariable():
                                    block_infos["outputs"].append((var.getName(),var.getType().getValue(),"none"))
                        return_type = pou.interface.getReturnType()
                        if return_type:
                            block_infos["outputs"].append(("",return_type.getValue(),"none"))
                    if pou.getBodyType() in ["FBD","LD","SFC"]:
                        for instance in pou.getInstances():
                            if isinstance(instance, plcopen.comment):
                                block_infos["comment"] = instance.getContentText()
                    BlockTypes[-1]["list"].append(block_infos)

    # Return Block types checking for recursion
    def GetBlockTypes(self):
        if self.CurrentElementEditing != None:
            current_name = self.ElementsOpened[self.CurrentElementEditing]
            words = current_name.split("::")
            if len(words) == 1:
                name = current_name
            else:
                name = words[1]
            blocktypes = [category for category in BlockTypes[:-1]]
            blocktypes.append({"name" : "User-defined POUs", "list": []})
            if self.Project:
                pou = self.Project.getPou(name)
                name = pou.getName()
                type = pou.pouType.getValue()
                for blocktype in BlockTypes[-1]["list"]:
                    if blocktype["name"] != name and not self.PouIsUsedBy(name, blocktype["name"]) and not (type == "function" and blocktype["type"] == "functionBlock"):
                        blocktypes[-1]["list"].append(blocktype)
            return blocktypes
        return []

    # Return Block types checking for recursion
    def GetBlockResource(self):
        blocktypes = []
        for category in BlockTypes[:-1]:
            for blocktype in category["list"]:
                if blocktype["type"] != "function":
                    blocktypes.append(blocktype["name"])
        if self.Project:
            for pou in self.Project.getPous():
                if pou.pouType.getValue() != "function":
                    blocktypes.append(pou.getName())
        return blocktypes

#-------------------------------------------------------------------------------
#                       Project opened Pous management functions
#-------------------------------------------------------------------------------
    
    # Return the list of pou names
    def GetElementsOpenedNames(self):
        names = []
        for pou_name in self.ElementsOpened:
            words = pou_name.split("::")
            if len(words) == 1:
                names.append(pou_name)
            else:
                names.append("%s-%s"%(words[1],words[2]))
        return names
    
    # Compute a pou transition name
    def ComputePouTransitionName(self, pou, transition):
        return "T::%s::%s" % (pou, transition)
    
    # Compute a pou action name
    def ComputePouActionName(self, pou, action):
        return "A::%s::%s" % (pou, action)

    # Compute a pou  name
    def ComputeConfigurationResourceName(self, config, resource):
        return "R::%s::%s" % (config, resource)
    
    # Open a pou by giving its name
    def OpenElementEditing(self, name):
        # If pou not opened yet
        if name not in self.ElementsOpened:
            # Add pou name to list of pou opened and make it current editing
            self.ElementsOpened.append(name)
            self.CurrentElementEditing = len(self.ElementsOpened) - 1
            return self.CurrentElementEditing
        return None

    # Open a pou transition by giving pou and transition names
    def OpenPouTransitionEditing(self, pou, transition):
        return self.OpenElementEditing(self.ComputePouTransitionName(pou, transition))

    # Open a pou action by giving pou and action names
    def OpenPouActionEditing(self, pou, action):
        return self.OpenElementEditing(self.ComputePouActionName(pou, action))

    # Open a configuration resource by giving configuration and resource names
    def OpenConfigurationResourceEditing(self, config, resource):
        return self.OpenElementEditing(self.ComputeConfigurationResourceName(config, resource))

    # Return if pou given by name is opened
    def IsElementEditing(self, name):
        return name in self.ElementsOpened

    # Return if pou transition given by pou and transition names is opened
    def IsPouTransitionEditing(self, pou, transition):
        return self.ComputePouTransitionName(pou, transition) in self.ElementsOpened

    # Return if pou action given by pou and action names is opened
    def IsPouActionEditing(self, pou, action):
        return self.ComputePouActionName(pou, action) in self.ElementsOpened

    # Return if pou action given by pou and action names is opened
    def IsConfigurationResourceEditing(self, pou, action):
        return self.ComputeConfigurationResourceName(config, resource) in self.ElementsOpened

    # Close current pou editing
    def CloseElementEditing(self):
        # Remove pou from list of pou opened
        self.ElementsOpened.pop(self.CurrentElementEditing)
        # Update index of current pou editing
        if len(self.ElementsOpened) > 0:
            self.CurrentElementEditing = min(self.CurrentElementEditing, len(self.ElementsOpened) - 1)
        else:
            self.CurrentElementEditing = None

    # Change current pou editing for pou given by name
    def ChangeElementEditing(self, name):
        # Verify that pou is opened
        if name in self.ElementsOpened:
            # Change current pou editing
            self.CurrentElementEditing = self.ElementsOpened.index(name)
            return self.CurrentElementEditing
        return None

    # Change current pou editing for transition given by pou and transition names
    def ChangePouTransitionEditing(self, pou, transition):
        return self.ChangeElementEditing(self.ComputePouTransitionName(pou, transition))

    # Change current pou editing for action given by pou and action names
    def ChangePouActionEditing(self, pou, action):
        return self.ChangeElementEditing(self.ComputePouActionName(pou, action))

    # Change current pou editing for action given by configuration and resource names
    def ChangeConfigurationResourceEditing(self, config, resource):
        return self.ChangeElementEditing(self.ComputeConfigurationResourceName(config, resource))

#-------------------------------------------------------------------------------
#                       Project opened Pous management functions
#-------------------------------------------------------------------------------

    # Return current pou editing
    def GetCurrentElementEditing(self):
        # Verify that there's one editing and return it
        if self.CurrentElementEditing != None:
            name = self.ElementsOpened[self.CurrentElementEditing]
            words = name.split("::")
            if len(words) == 1:
                return self.Project.getPou(name)
            else:
                if words[0] in ['T', 'A']:
                    pou = self.Project.getPou(words[1])
                    if words[0] == 'T':
                        return pou.getTransition(words[2])
                    elif words[0] == 'A':
                        return pou.getAction(words[2])
                elif words[0] == 'R':
                    result = self.Project.getConfigurationResource(words[1], words[2])
                    return result
        return None
    
    # Return current pou editing name
    def GetCurrentElementEditingName(self):
        # Verify that there's one editing and return its name
        if self.CurrentElementEditing != None:
            name = self.ElementsOpened[self.CurrentElementEditing]
            words = name.split("::")
            if len(words) == 1:
                return name
            else:
                return words[2]
        return None
    
    # Replace the index of current pou editing by the one given
    def RefreshCurrentElementEditing(self, index):
        self.CurrentElementEditing = index

    # Return language in which current pou editing is written
    def GetCurrentElementEditingBodyType(self):
        if self.CurrentElementEditing != None:
            name = self.ElementsOpened[self.CurrentElementEditing]
            words = name.split("::")
            if len(words) == 1:
                return self.GetPouBodyType(name)
            else:
                if words[0] == 'T':
                    return self.GetTransitionBodyType(words[1], words[2])
                elif words[0] == 'A':
                    return self.GetActionBodyType(words[1], words[2])
        return None

    # Return the variables of the current pou editing
    def GetCurrentElementEditingInterfaceVars(self):
        if self.CurrentElementEditing != None:
            current_name = self.ElementsOpened[self.CurrentElementEditing]
            words = current_name.split("::")
            if len(words) == 1:
                pou = self.Project.getPou(current_name)
                return self.GetPouInterfaceVars(pou)
            else:
                pou = self.Project.getPou(words[1])
                return self.GetPouInterfaceVars(pou)
        return []

    # Return the return type of the current pou editing
    def GetCurrentElementEditingInterfaceReturnType(self):
        if self.CurrentElementEditing != None:
            current_name = self.ElementsOpened[self.CurrentElementEditing]
            words = current_name.split("::")
            if len(words) == 1:
                pou = self.Project.getPou(current_name)
                return self.GetPouInterfaceReturnType(pou)
            elif words[0] == 'T':
                return "BOOL"
        return None
    
    # Change the text of the current pou editing
    def SetCurrentElementEditingText(self, text):
        if self.CurrentElementEditing != None:
            self.GetCurrentElementEditing().setText(text)
            self.RefreshPouUsingTree()
    
    # Return the current pou editing text
    def GetCurrentElementEditingText(self):
        if self.CurrentElementEditing != None:
            return self.GetCurrentElementEditing().getText()
        return ""

    # Return the current pou editing transitions
    def GetCurrentElementEditingTransitions(self):
        if self.CurrentElementEditing != None:
            pou = self.GetCurrentElementEditing()
            if pou.getBodyType() == "SFC":
                transitions = []
                for transition in pou.getTransitionList():
                    transitions.append(transition.getName())
                return transitions
        return []

    # Return the current pou editing transitions
    def GetCurrentElementEditingActions(self):
        if self.CurrentElementEditing != None:
            pou = self.GetCurrentElementEditing()
            if pou.getBodyType() == "SFC":
                actions = []
                for action in pou.getActionList():
                    actions.append(action.getName())
                return actions
        return []

    # Return the current pou editing informations
    def GetCurrentElementEditingInstanceInfos(self, id = None, exclude = []):
        infos = {}
        # if id is defined
        if id != None:
            instance = self.GetCurrentElementEditing().getInstance(id)
        else:
            instance = self.GetCurrentElementEditing().getRandomInstance(exclude)
        if instance:
            if id != None:
                infos["id"] = id
            else:
                infos["id"] = instance.getLocalId() 
            infos["x"] = instance.getX()
            infos["y"] = instance.getY()
            infos["height"] = instance.getHeight()
            infos["width"] = instance.getWidth()
            if isinstance(instance, plcopen.block):
                infos["name"] = instance.getInstanceName()
                infos["type"] = instance.getTypeName()
                infos["connectors"] = {"inputs":[],"outputs":[]}
                for variable in instance.inputVariables.getVariable():
                    connector = {}
                    connector["position"] = variable.connectionPointIn.getRelPosition()
                    connector["negated"] = variable.getNegated()
                    connector["edge"] = variable.getConnectorEdge()
                    connector["links"] = []
                    connections = variable.connectionPointIn.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                            connector["links"].append(dic)
                    infos["connectors"]["inputs"].append(connector)
                for variable in instance.outputVariables.getVariable():
                    connector = {}
                    connector["position"] = variable.connectionPointOut.getRelPosition()
                    connector["negated"] = variable.getNegated()
                    connector["edge"] = variable.getConnectorEdge()
                    infos["connectors"]["outputs"].append(connector)
            elif isinstance(instance, plcopen.inVariable):
                infos["name"] = instance.getExpression()
                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
                infos["type"] = "input"
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointOut.getRelPosition()
                infos["connector"]["negated"] = instance.getNegated()
                infos["connector"]["edge"] = instance.getConnectorEdge()
            elif isinstance(instance, plcopen.outVariable):
                infos["name"] = instance.getExpression()
                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
                infos["type"] = "output"
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["negated"] = instance.getNegated()
                infos["connector"]["edge"] = instance.getConnectorEdge()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connector"]["links"].append(dic)
            elif isinstance(instance, plcopen.inOutVariable):
                infos["name"] = instance.getExpression()
                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
                infos["type"] = "inout"
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
                infos["connectors"]["output"]["negated"] = instance.getNegatedOut()
                infos["connectors"]["output"]["edge"] = instance.getOutputEdge()
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["negated"] = instance.getNegatedIn()
                infos["connectors"]["input"]["edge"] = instance.getInputEdge()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connectors"]["input"]["links"].append(dic)
            elif isinstance(instance, plcopen.continuation):
                infos["name"] = instance.getName()
                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
                infos["type"] = "continuation"
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, plcopen.connector):
                infos["name"] = instance.getName()
                infos["value_type"] = self.GetPouVarValueType(self.GetCurrentElementEditing(), infos["name"])
                infos["type"] = "connection"
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connector"]["links"].append(dic)
            elif isinstance(instance, plcopen.comment):
                infos["type"] = "comment"
                infos["content"] = instance.getContentText()
            elif isinstance(instance, plcopen.leftPowerRail):
                infos["type"] = "leftPowerRail"
                infos["connectors"] = []
                for connection in instance.getConnectionPointOut():
                    connector = {}
                    connector["position"] = connection.getRelPosition()
                    infos["connectors"].append(connector)
            elif isinstance(instance, plcopen.rightPowerRail):
                infos["type"] = "rightPowerRail"
                infos["connectors"] = []
                for connection in instance.getConnectionPointIn():
                    connector = {}
                    connector["position"] = connection.getRelPosition()
                    connector["links"] = []
                    for link in connection.getConnections():
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        connector["links"].append(dic)
                    infos["connectors"].append(connector)
            elif isinstance(instance, plcopen.contact):
                infos["type"] = "contact"
                infos["name"] = instance.getVariable()
                infos["negated"] = instance.getNegated()
                infos["edge"] = instance.getContactEdge()
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connectors"]["input"]["links"].append(dic)
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, plcopen.coil):
                infos["type"] = "coil"
                infos["name"] = instance.getVariable()
                infos["negated"] = instance.getNegated()
                infos["storage"] = instance.getCoilStorage()
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connectors"]["input"]["links"].append(dic)
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, plcopen.step):
                infos["type"] = "step"
                infos["name"] = instance.getName()
                infos["initial"] = instance.getInitialStep()
                infos["connectors"] = {}
                if instance.connectionPointIn:
                    infos["connectors"]["input"] = {}
                    infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                    infos["connectors"]["input"]["links"] = []
                    connections = instance.connectionPointIn.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                            infos["connectors"]["input"]["links"].append(dic)
                if instance.connectionPointOut:
                    infos["connectors"]["output"] = {"position" : instance.connectionPointOut.getRelPosition()}
                if instance.connectionPointOutAction:
                    infos["connectors"]["action"] = {"position" : instance.connectionPointOutAction.getRelPosition()}
            elif isinstance(instance, plcopen.transition):
                infos["type"] = "transition"
                condition = instance.getConditionContent()
                infos["condition_type"] = condition["type"]
                infos["condition"] = condition["value"]
                infos["connectors"] = {"input":{},"output":{}}
                infos["connectors"]["input"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connectors"]["input"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connectors"]["input"]["links"].append(dic)
                infos["connectors"]["output"]["position"] = instance.connectionPointOut.getRelPosition()
            elif isinstance(instance, (plcopen.selectionDivergence, plcopen.simultaneousDivergence)):
                if isinstance(instance, plcopen.selectionDivergence):
                    infos["type"] = "selectionDivergence"
                else:
                    infos["type"] = "simultaneousDivergence"
                infos["connectors"] = {"inputs":[],"outputs":[]}
                connector = {}
                connector["position"] = instance.connectionPointIn.getRelPosition()
                connector["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        connector["links"].append(dic)
                infos["connectors"]["inputs"].append(connector)
                for sequence in instance.getConnectionPointOut():
                    connector = {}
                    connector["position"] = sequence.getRelPosition()
                    infos["connectors"]["outputs"].append(connector)
            elif isinstance(instance, (plcopen.selectionConvergence, plcopen.simultaneousConvergence)):
                if isinstance(instance, plcopen.selectionConvergence):
                    infos["type"] = "selectionConvergence"
                else:
                    infos["type"] = "simultaneousConvergence"
                infos["connectors"] = {"inputs":[],"outputs":[]}
                for sequence in instance.getConnectionPointIn():
                    connector = {}
                    connector["position"] = sequence.getRelPosition()
                    connector["links"] = []
                    connections = sequence.getConnections()
                    if connections:
                        for link in connections:
                            dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                            connector["links"].append(dic)
                    infos["connectors"]["inputs"].append(connector)
                connector = {}
                connector["position"] = instance.connectionPointOut.getRelPosition()
                infos["connectors"]["outputs"].append(connector)
            elif isinstance(instance, plcopen.jumpStep):
                infos["type"] = "jump"
                infos["target"] = instance.getTargetName()
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connector"]["links"].append(dic)
            elif isinstance(instance, plcopen.actionBlock):
                infos["type"] = "actionBlock"
                infos["actions"] = instance.getActions()
                infos["connector"] = {}
                infos["connector"]["position"] = instance.connectionPointIn.getRelPosition()
                infos["connector"]["links"] = []
                connections = instance.connectionPointIn.getConnections()
                if connections:
                    for link in connections:
                        dic = {"refLocalId":link.getRefLocalId(),"points":link.getPoints()}
                        infos["connector"]["links"].append(dic)
            return infos
        return False
    
    # Return the variable type of the given pou
    def GetPouVarValueType(self, pou, varname):
        for type, varlist in pou.getVars():
            for var in varlist.getVariable():
                if var.getName() == varname:
                    return var.getType()
        return ""
    
    def SetConnectionWires(self, connection, connector):
        wires = connector.GetWires()
        idx = 0
        for wire, handle in wires:
            points = wire.GetPoints(handle != 0)
            if handle == 0:
                refLocalId = wire.GetConnectedId(-1)
            else:
                refLocalId = wire.GetConnectedId(0)
            if refLocalId != None:
                connection.addConnection()
                connection.setConnectionId(idx, refLocalId)
                connection.setConnectionPoints(idx, points)
                idx += 1
    
    def AddCurrentElementEditingBlock(self, id):
        block = plcopen.block()
        block.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("block", block)
        self.RefreshPouUsingTree()
    
    def SetCurrentElementEditingBlockInfos(self, id, infos):
        block = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "name":
                block.setInstanceName(value)
            elif param == "type":
                block.setTypeName(value)
            elif param == "height":
                block.setHeight(value)
            elif param == "width":
                block.setWidth(value)
            elif param == "x":
                block.setX(value)
            elif param == "y":
                block.setY(value)
            elif param == "connectors":
                block.inputVariables.setVariable([])
                block.outputVariables.setVariable([])
                for connector in value["inputs"]:
                    variable = plcopen.inputVariables_variable()
                    variable.setFormalParameter(connector.GetName())
                    if connector.IsNegated():
                        variable.setNegated(True)
                    if connector.GetEdge() != "none":
                        variable.setConnectorEdge(connector.GetEdge())
                    position = connector.GetRelPosition()
                    variable.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(variable.connectionPointIn, connector)
                    block.inputVariables.appendVariable(variable)
                for connector in value["outputs"]:
                    variable = plcopen.outputVariables_variable()
                    variable.setFormalParameter(connector.GetName())
                    if connector.IsNegated():
                        variable.setNegated(True)
                    if connector.GetEdge() != "none":
                        variable.setConnectorEdge(connector.GetEdge())
                    position = connector.GetRelPosition()
                    variable.addConnectionPointOut()
                    variable.connectionPointOut.setRelPosition(position.x, position.y)
                    block.outputVariables.appendVariable(variable)
        self.RefreshPouUsingTree()
        
    def AddCurrentElementEditingVariable(self, id, type):
        if type == INPUT:
            name = "inVariable"
            variable = plcopen.inVariable()
        elif type == OUTPUT:
            name = "outVariable"
            variable = plcopen.outVariable()
        elif type == INOUT:
            name = "inOutVariable"
            variable = plcopen.inOutVariable()
        variable.setLocalId(id)
        self.GetCurrentElementEditing().addInstance(name, variable)
        
    def SetCurrentElementEditingVariableInfos(self, id, infos):
        variable = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "name":
                variable.setExpression(value)    
            elif param == "height":
                variable.setHeight(value)
            elif param == "width":
                variable.setWidth(value)
            elif param == "x":
                variable.setX(value)
            elif param == "y":
                variable.setY(value)
            elif param == "connectors":
                if isinstance(variable, plcopen.inVariable):
                    if value["output"].IsNegated():
                        variable.setNegated(True)
                    if value["output"].GetEdge() != "none":
                        variable.setConnectorEdge(value["output"].GetEdge())
                    position = value["output"].GetRelPosition()
                    variable.addConnectionPointOut()
                    variable.connectionPointOut.setRelPosition(position.x, position.y)
                elif isinstance(variable, plcopen.outVariable):
                    if value["input"].IsNegated():
                        variable.setNegated(True)
                    if value["input"].GetEdge() != "none":
                        variable.setConnectorEdge(value["input"].GetEdge())
                    position = value["input"].GetRelPosition()
                    variable.addConnectionPointIn()
                    variable.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(variable.connectionPointIn, value["input"])
                elif isinstance(variable, plcopen.inOutVariable):
                    if value["input"].IsNegated():
                        variable.setNegatedIn(True)
                    if value["input"].GetEdge() != "none":
                        variable.setInputEdge(value["input"].GetEdge())
                    if value["output"].IsNegated():
                        variable.setNegatedOut(True)
                    if value["output"].GetEdge() != "none":
                        variable.setOutputEdge(value["output"].GetEdge())
                    position = value["output"].GetRelPosition()
                    variable.addConnectionPointOut()
                    variable.connectionPointOut.setRelPosition(position.x, position.y)
                    position = value["input"].GetRelPosition()
                    variable.addConnectionPointIn()
                    variable.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(variable.connectionPointIn, value["input"])


    def AddCurrentElementEditingConnection(self, id, type):
        if type == CONNECTOR:
            name = "connector"
            connection = plcopen.connector()
        elif type == CONTINUATION:
            name = "continuation"
            connection = plcopen.continuation()
        connection.setLocalId(id)
        self.GetCurrentElementEditing().addInstance(name, connection)
        
    def SetCurrentElementEditingConnectionInfos(self, id, infos):
        connection = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "name":
                connection.setName(value)    
            elif param == "height":
                connection.setHeight(value)
            elif param == "width":
                connection.setWidth(value)
            elif param == "x":
                connection.setX(value)
            elif param == "y":
                connection.setY(value)
            elif param == "connector":
                position = value.GetRelPosition()
                if isinstance(connection, plcopen.continuation):
                    connection.addConnectionPointOut()
                    connection.connectionPointOut.setRelPosition(position.x, position.y)
                elif isinstance(connection, plcopen.connector):
                    connection.addConnectionPointIn()
                    connection.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(connection.connectionPointIn, value)

    def AddCurrentElementEditingComment(self, id):
        comment = plcopen.comment()
        comment.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("comment", comment)
    
    def SetCurrentElementEditingCommentInfos(self, id, infos):
        comment = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "content":
                comment.setContentText(value)
            elif param == "height":
                comment.setHeight(value)
            elif param == "width":
                comment.setWidth(value)
            elif param == "x":
                comment.setX(value)
            elif param == "y":
                comment.setY(value)

    def AddCurrentElementEditingPowerRail(self, id, type):
        if type == LEFTRAIL:
            name = "leftPowerRail"
            powerrail = plcopen.leftPowerRail()
        elif type == RIGHTRAIL:
            name = "rightPowerRail"
            powerrail = plcopen.rightPowerRail()
        powerrail.setLocalId(id)
        self.GetCurrentElementEditing().addInstance(name, powerrail)
    
    def SetCurrentElementEditingPowerRailInfos(self, id, infos):
        powerrail = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "height":
                powerrail.setHeight(value)
            elif param == "width":
                powerrail.setWidth(value)
            elif param == "x":
                powerrail.setX(value)
            elif param == "y":
                powerrail.setY(value)
            elif param == "connectors":
                if isinstance(powerrail, plcopen.leftPowerRail):
                    powerrail.setConnectionPointOut([])
                    for connector in value:
                        position = connector.GetRelPosition()
                        connection = plcopen.leftPowerRail_connectionPointOut()
                        connection.setRelPosition(position.x, position.y)
                        powerrail.connectionPointOut.append(connection)
                elif isinstance(powerrail, plcopen.rightPowerRail):
                    powerrail.setConnectionPointIn([])
                    for connector in value:
                        position = connector.GetRelPosition()
                        connection = plcopen.connectionPointIn()
                        connection.setRelPosition(position.x, position.y)
                        self.SetConnectionWires(connection, connector)
                        powerrail.connectionPointIn.append(connection)

    def AddCurrentElementEditingContact(self, id):
        contact = plcopen.contact()
        contact.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("contact", contact)

    def SetCurrentElementEditingContactInfos(self, id, infos):
        contact = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "name":
                contact.setVariable(value)
            elif param == "type":
                if value == CONTACT_NORMAL:
                    contact.setNegated(False)
                    contact.setContactEdge("none")
                elif value == CONTACT_REVERSE:
                    contact.setNegated(True)
                    contact.setContactEdge("none")
                elif value == CONTACT_RISING:
                    contact.setNegated(False)
                    contact.setContactEdge("rising")
                elif value == CONTACT_FALLING:
                    contact.setNegated(False)
                    contact.setContactEdge("falling")
            elif param == "height":
                contact.setHeight(value)
            elif param == "width":
                contact.setWidth(value)
            elif param == "x":
                contact.setX(value)
            elif param == "y":
                contact.setY(value)
            elif param == "connectors":
                input_connector = value["input"]
                position = input_connector.GetRelPosition()
                contact.addConnectionPointIn()
                contact.connectionPointIn.setRelPosition(position.x, position.y)
                self.SetConnectionWires(contact.connectionPointIn, input_connector)
                output_connector = value["output"]
                position = output_connector.GetRelPosition()
                contact.addConnectionPointOut()
                contact.connectionPointOut.setRelPosition(position.x, position.y)

    def AddCurrentElementEditingCoil(self, id):
        coil = plcopen.coil()
        coil.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("coil", coil)

    def SetCurrentElementEditingCoilInfos(self, id, infos):
        coil = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "name":
                coil.setVariable(value)
            elif param == "type":
                if value == COIL_NORMAL:
                    coil.setNegated(False)
                    coil.setCoilStorage("none")
                elif value == COIL_REVERSE:
                    coil.setNegated(True)
                    coil.setCoilStorage("none")
                elif value == COIL_SET:
                    coil.setNegated(False)
                    coil.setCoilStorage("set")
                elif value == COIL_RESET:
                    coil.setNegated(False)
                    coil.setCoilStorage("reset")
            elif param == "height":
                coil.setHeight(value)
            elif param == "width":
                coil.setWidth(value)
            elif param == "x":
                coil.setX(value)
            elif param == "y":
                coil.setY(value)
            elif param == "connectors":
                input_connector = value["input"]
                position = input_connector.GetRelPosition()
                coil.addConnectionPointIn()
                coil.connectionPointIn.setRelPosition(position.x, position.y)
                self.SetConnectionWires(coil.connectionPointIn, input_connector)
                output_connector = value["output"]
                position = output_connector.GetRelPosition()
                coil.addConnectionPointOut()
                coil.connectionPointOut.setRelPosition(position.x, position.y)

    def AddCurrentElementEditingStep(self, id):
        step = plcopen.step()
        step.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("step", step)
    
    def SetCurrentElementEditingStepInfos(self, id, infos):
        step = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "name":
                step.setName(value)
            elif param == "initial":
                step.setInitialStep(value)
            elif param == "height":
                step.setHeight(value)
            elif param == "width":
                step.setWidth(value)
            elif param == "x":
                step.setX(value)
            elif param == "y":
                step.setY(value)
            elif param == "connectors":
                input_connector = value["input"]
                if input_connector:
                    position = input_connector.GetRelPosition()
                    step.addConnectionPointIn()
                    step.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(step.connectionPointIn, input_connector)
                else:
                    step.deleteConnectionPointIn()
                output_connector = value["output"]
                if output_connector:
                    position = output_connector.GetRelPosition()
                    step.addConnectionPointOut()
                    step.connectionPointOut.setRelPosition(position.x, position.y)
                else:
                    step.deleteConnectionPointOut()
                action_connector = value["action"]
                if action_connector:
                    position = action_connector.GetRelPosition()
                    step.addConnectionPointOutAction()
                    step.connectionPointOutAction.setRelPosition(position.x, position.y)
                else:
                    step.deleteConnectionPointOutAction()
    
    def AddCurrentElementEditingTransition(self, id):
        transition = plcopen.transition()
        transition.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("transition", transition)
    
    def SetCurrentElementEditingTransitionInfos(self, id, infos):
        transition = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "type" and "condition" in infos:
                transition.setConditionContent(value, infos["condition"])
            elif param == "height":
                transition.setHeight(value)
            elif param == "width":
                transition.setWidth(value)
            elif param == "x":
                transition.setX(value)
            elif param == "y":
                transition.setY(value)
            elif param == "connectors":
                input_connector = value["input"]
                position = input_connector.GetRelPosition()
                transition.addConnectionPointIn()
                transition.connectionPointIn.setRelPosition(position.x, position.y)
                self.SetConnectionWires(transition.connectionPointIn, input_connector)
                output_connector = value["output"]
                position = output_connector.GetRelPosition()
                transition.addConnectionPointOut()
                transition.connectionPointOut.setRelPosition(position.x, position.y)
    
    def AddCurrentElementEditingDivergence(self, id, type):
        if type == SELECTION_DIVERGENCE:
            name = "selectionDivergence"
            divergence = plcopen.selectionDivergence()
        elif type == SELECTION_CONVERGENCE:
            name = "selectionConvergence"
            divergence = plcopen.selectionConvergence()
        elif type == SIMULTANEOUS_DIVERGENCE:
            name = "simultaneousDivergence"
            divergence = plcopen.simultaneousDivergence()
        elif type == SIMULTANEOUS_CONVERGENCE:
            name = "simultaneousConvergence"
            divergence = plcopen.simultaneousConvergence()
        divergence.setLocalId(id)
        self.GetCurrentElementEditing().addInstance(name, divergence)
    
    def SetCurrentElementEditingDivergenceInfos(self, id, infos):
        divergence = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "height":
                divergence.setHeight(value)
            elif param == "width":
                divergence.setWidth(value)
            elif param == "x":
                divergence.setX(value)
            elif param == "y":
                divergence.setY(value)
            elif param == "connectors":
                input_connectors = value["inputs"]
                if isinstance(divergence, (plcopen.selectionDivergence, plcopen.simultaneousDivergence)):
                    position = input_connectors[0].GetRelPosition()
                    divergence.addConnectionPointIn()
                    divergence.connectionPointIn.setRelPosition(position.x, position.y)
                    self.SetConnectionWires(divergence.connectionPointIn, input_connectors[0])
                else:
                    divergence.setConnectionPointIn([])
                    for input_connector in input_connectors:
                        position = input_connector.GetRelPosition()
                        if isinstance(divergence, plcopen.selectionConvergence):
                            connection = plcopen.selectionConvergence_connectionPointIn()
                        else:
                            connection = plcopen.connectionPointIn()
                        connection.setRelPosition(position.x, position.y)
                        self.SetConnectionWires(connection, input_connector)
                        divergence.appendConnectionPointIn(connection)
                output_connectors = value["outputs"]
                if isinstance(divergence, (plcopen.selectionConvergence, plcopen.simultaneousConvergence)):
                    position = output_connectors[0].GetRelPosition()
                    divergence.addConnectionPointOut()
                    divergence.connectionPointOut.setRelPosition(position.x, position.y)
                else:
                    divergence.setConnectionPointOut([])
                    for output_connector in output_connectors:
                        position = output_connector.GetRelPosition()
                        if isinstance(divergence, plcopen.selectionDivergence):
                            connection = plcopen.selectionDivergence_connectionPointOut()
                        else:
                            connection = plcopen.simultaneousDivergence_connectionPointOut()
                        connection.setRelPosition(position.x, position.y)
                        divergence.appendConnectionPointOut(connection)
    
    def AddCurrentElementEditingJump(self, id):
        jump = plcopen.jumpStep()
        jump.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("jumpStep", jump)
    
    def SetCurrentElementEditingJumpInfos(self, id, infos):
        jump = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "target":
                jump.setTargetName(value)
            elif param == "height":
                jump.setHeight(value)
            elif param == "width":
                jump.setWidth(value)
            elif param == "x":
                jump.setX(value)
            elif param == "y":
                jump.setY(value)
            elif param == "connector":
                position = value.GetRelPosition()
                jump.addConnectionPointIn()
                jump.connectionPointIn.setRelPosition(position.x, position.y)
                self.SetConnectionWires(jump.connectionPointIn, value)
 
    def AddCurrentElementEditingActionBlock(self, id):
        actionBlock = plcopen.actionBlock()
        actionBlock.setLocalId(id)
        self.GetCurrentElementEditing().addInstance("actionBlock", actionBlock)
    
    def SetCurrentElementEditingActionBlockInfos(self, id, infos):
        actionBlock = self.GetCurrentElementEditing().getInstance(id)
        for param, value in infos.items():
            if param == "actions":
                actionBlock.setActions(value)
            elif param == "height":
                actionBlock.setHeight(value)
            elif param == "width":
                actionBlock.setWidth(value)
            elif param == "x":
                actionBlock.setX(value)
            elif param == "y":
                actionBlock.setY(value)
            elif param == "connector":
                position = value.GetRelPosition()
                actionBlock.addConnectionPointIn()
                actionBlock.connectionPointIn.setRelPosition(position.x, position.y)
                self.SetConnectionWires(actionBlock.connectionPointIn, value)
    
    def RemoveCurrentElementEditingInstance(self, id):
        self.GetCurrentElementEditing().removeInstance(id)
        self.RefreshPouUsingTree()

    def GetCurrentResourceEditingVariables(self):
        varlist = []
        name = self.ElementsOpened[self.CurrentElementEditing]
        words = name.split("::")
        for var in self.GetConfigurationGlobalVars(words[1]):
            if var["Type"] == "BOOL":
                varlist.append(var["Name"])
        for var in self.GetConfigurationResourceGlobalVars(words[1], words[2]):
            if var["Type"] == "BOOL":
                varlist.append(var["Name"])
        return varlist

    def SetCurrentResourceEditingInfos(self, tasks, instances):
        resource = self.GetCurrentElementEditing()
        resource.setTask([])
        resource.setPouInstance([])
        task_list = {}
        for task in tasks:
            new_task = plcopen.resource_task()
            new_task.setName(task["Name"])
            if task["Single"] != "":
                new_task.setSingle(task["Single"])
            if task["Interval"] != "":
                new_task.setInterval(task["Interval"])
            new_task.priority.setValue(int(task["Priority"]))
            if task["Name"] != "":
                task_list[task["Name"]] = new_task
            resource.appendTask(new_task)
        for instance in instances:
            new_instance = plcopen.pouInstance()
            new_instance.setName(instance["Name"])
            new_instance.setType(instance["Type"])
            if instance["Task"] != "":
                task_list[instance["Task"]].appendPouInstance(new_instance)
            else:
                resource.appendPouInstance(new_instance)

    def GetCurrentResourceEditingInfos(self):
        resource = self.GetCurrentElementEditing()
        tasks = resource.getTask()
        instances = resource.getPouInstance()
        tasks_data = []
        instances_data = []
        for task in tasks:
            new_task = {}
            new_task["Name"] = task.getName()
            single = task.getSingle()
            if single:
                new_task["Single"] = single
            else:
                new_task["Single"] = ""
            interval = task.getInterval()
            if interval:
                new_task["Interval"] = interval
            else:
                new_task["Interval"] = ""
            new_task["Priority"] = str(task.priority.getValue())
            tasks_data.append(new_task)
            for instance in task.getPouInstance():
                new_instance = {}
                new_instance["Name"] = instance.getName()
                new_instance["Type"] = instance.getType()
                new_instance["Task"] = task.getName()
                instances_data.append(new_instance)
        for instance in instances:
            new_instance = {}
            new_instance["Name"] = instance.getName()
            new_instance["Type"] = instance.getType()
            new_instance["Task"] = ""
            instances_data.append(new_instance)
        return tasks_data, instances_data

    def OpenXMLFile(self, filepath):
        if sys:
            sys.stdout = plcopen.HolePseudoFile()
        tree = pyxsval.parseAndValidate(filepath, "plcopen/TC6_XML_V10_B.xsd")
        if sys:
            sys.stdout = sys.__stdout__
        
        self.Project = plcopen.project()
        self.Project.loadXMLTree(tree.getTree().childNodes[0])
        self.UndoBuffer = UndoBuffer(self.Copy(self.Project), True)
        self.SetFilePath(filepath)
        self.ElementsOpened = []
        self.CurrentElementEditing = None
        self.RefreshPouUsingTree()
        self.RefreshBlockTypes()

    def SaveXMLFile(self, filepath = None):
        if not filepath and self.FilePath == "":
            return False
        else:
            text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
            extras = {"xmlns" : "http://www.plcopen.org/xml/tc6.xsd",
                      "xmlns:xhtml" : "http://www.w3.org/1999/xhtml",
                      "xmlns:xsi" : "http://www.w3.org/2001/XMLSchema-instance",
                      "xsi:schemaLocation" : "http://www.plcopen.org/xml/tc6.xsd http://www.plcopen.org/xml/tc6.xsd"}
            text += self.Project.generateXMLText("project", 0, extras)

            if sys:
                sys.stdout = plcopen.HolePseudoFile()
            pyxsval.parseAndValidateString(text, open("plcopen/TC6_XML_V10_B.xsd","r").read())
            if sys:
                sys.stdout = sys.__stdout__
            
            if filepath:
                xmlfile = open(filepath,"w")
            else:
                xmlfile = open(self.FilePath,"w")
            xmlfile.write(text)
            xmlfile.close()
            self.UndoBuffer.CurrentSaved()
            if filepath:
                self.SetFilePath(filepath)
            return True

#-------------------------------------------------------------------------------
#                      Current Buffering Management Functions
#-------------------------------------------------------------------------------

    """
    Return a copy of the project
    """
    def Copy(self, model):
        return cPickle.loads(cPickle.dumps(model))

    def BufferProject(self):
        self.UndoBuffer.Buffering(self.Copy(self))

    def ProjectIsSaved(self):
        return self.UndoBuffer.IsCurrentSaved()

    def LoadPrevious(self):
        self.Project = self.Copy(self.UndoBuffer.Previous())
        self.RefreshElementsOpened()
    
    def LoadNext(self):
        self.Project = self.Copy(self.UndoBuffer.Next())
        self.RefreshElementsOpened()
    
    def GetBufferState(self):
        first = self.UndoBuffer.IsFirst()
        last = self.UndoBuffer.IsLast()
        return not first, not last