text: # Licensed to the StackStorm, Inc ('StackStorm') under one or more
  # contributor license agreements.  See the NOTICE file distributed with
  # this work for additional information regarding copyright ownership.
  # The ASF licenses this file to You under the Apache License, Version 2.0
  # (the "License"); you may not use this file except in compliance with
  # the License.  You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  import six
  import string
  
  from st2common.util import schema as util_schema
  from st2common.models.api.notification import NotificationSubSchemaAPI
  
  
  class Node(object):
  
      schema = {
          "title": "Node",
          "description": "Node of an ActionChain.",
          "type": "object",
          "properties": {
              "name": {
                  "description": "The name of this node.",
                  "type": "string",
                  "required": True
              },
              "ref": {
                  "type": "string",
                  "description": "Ref of the action to be executed.",
                  "required": True
              },
              "params": {
                  "type": "object",
                  "description": ("Parameter for the execution (old name, here for backward "
                                  "compatibility reasons)."),
                  "default": {}
              },
              "parameters": {
                  "type": "object",
                  "description": "Parameter for the execution.",
                  "default": {}
              },
              "on-success": {
                  "type": "string",
                  "description": "Name of the node to invoke on successful completion of action"
                                 " executed for this node.",
                  "default": ""
              },
              "on-failure": {
                  "type": "string",
                  "description": "Name of the node to invoke on failure of action executed for this"
                                 " node.",
                  "default": ""
              },
              "publish": {
                  "description": "The variables to publish from the result. Should be of the form"
                                 " name.foo. o1: {{node_name.foo}} will result in creation of a"
                                 " variable o1 which is now available for reference through"
                                 " remainder of the chain as a global variable.",
                  "type": "object",
                  "patternProperties": {
                      "^\w+$": {}
                  }
              },
              "notify": {
                  "description": "Notification settings for action.",
                  "type": "object",
                  "properties": {
                      "on-complete": NotificationSubSchemaAPI,
                      "on-failure": NotificationSubSchemaAPI,
                      "on-success": NotificationSubSchemaAPI
                  },
                  "additionalProperties": False
              }
          },
          "additionalProperties": False
      }
  
      def __init__(self, **kw):
          for prop in six.iterkeys(self.schema.get('properties', [])):
              value = kw.get(prop, None)
              # having '-' in the property name lead to challenges in referencing the property.
              # At hindsight the schema property should've been on_success rather than on-success.
              prop = string.replace(prop, '-', '_')
              setattr(self, prop, value)
  
      def validate(self):
          params = getattr(self, 'params', {})
          parameters = getattr(self, 'parameters', {})
  
          if params and parameters:
              msg = ('Either "params" or "parameters" attribute needs to be provided, but not '
                     'both')
              raise ValueError(msg)
  
          return self
  
      def get_parameters(self):
          # Note: "params" is old deprecated attribute which will be removed in a future release
          params = getattr(self, 'params', {})
          parameters = getattr(self, 'parameters', {})
  
          return parameters or params
  
      def __repr__(self):
          return ('<Node name=%s, ref=%s, on-success=%s, on-failure=%s>' %
                  (self.name, self.ref, self.on_success, self.on_failure))
  
  
  class ActionChain(object):
  
      schema = {
          "title": "ActionChain",
          "description": "A chain of sequentially executed actions.",
          "type": "object",
          "properties": {
              "chain": {
                  "description": "The chain.",
                  "type": "array",
                  "items": [Node.schema],
                  "required": True
              },
              "default": {
                  "type": "string",
                  "description": "name of the action to be executed."
              },
              "vars": {
                  "description": "",
                  "type": "object",
                  "patternProperties": {
                      "^\w+$": {}
                  }
              }
          },
          "additionalProperties": False
      }
  
      def __init__(self, **kw):
          util_schema.validate(instance=kw, schema=self.schema, cls=util_schema.CustomValidator,
                               use_default=False, allow_default_none=True)
  
          for prop in six.iterkeys(self.schema.get('properties', [])):
              value = kw.get(prop, None)
              # special handling for chain property to create the Node object
              if prop == 'chain':
                  nodes = []
                  for node in value:
                      ac_node = Node(**node)
                      ac_node.validate()
                      nodes.append(ac_node)
                  value = nodes
              setattr(self, prop, value)
  