text: # coding: utf-8
  
  import json
  from pycti.utils.constants import CustomProperties
  
  
  class Tool:
      def __init__(self, opencti):
          self.opencti = opencti
          self.properties = """
              id
              stix_id_key
              stix_label
              entity_type
              parent_types
              name
              alias
              description
              graph_data
              tool_version
              created
              modified            
              created_at
              updated_at
              createdByRef {
                  node {
                      id
                      entity_type
                      stix_id_key
                      stix_label
                      name
                      alias
                      description
                      created
                      modified
                      ... on Organization {
                          organization_class
                      }
                  }
                  relation {
                      id
                  }
              }            
              markingDefinitions {
                  edges {
                      node {
                          id
                          entity_type
                          stix_id_key
                          definition_type
                          definition
                          level
                          color
                          created
                          modified
                      }
                      relation {
                          id
                      }
                  }
              }
              tags {
                  edges {
                      node {
                          id
                          tag_type
                          value
                          color
                      }
                      relation {
                          id
                      }
                  }
              }
              externalReferences {
                  edges {
                      node {
                          id
                          entity_type
                          stix_id_key
                          source_name
                          description
                          url
                          hash
                          external_id
                          created
                          modified
                      }
                      relation {
                          id
                      }
                  }
              }     
          """
  
      """
          List Tool objects
  
          :param filters: the filters to apply
          :param search: the search keyword
          :param first: return the first n rows from the after ID (or the beginning if not set)
          :param after: ID of the first row for pagination
          :return List of Tool objects
      """
  
      def list(self, **kwargs):
          filters = kwargs.get("filters", None)
          search = kwargs.get("search", None)
          first = kwargs.get("first", 500)
          after = kwargs.get("after", None)
          order_by = kwargs.get("orderBy", None)
          order_mode = kwargs.get("orderMode", None)
          get_all = kwargs.get("getAll", False)
          if get_all:
              first = 500
  
          self.opencti.log(
              "info", "Listing Tools with filters " + json.dumps(filters) + "."
          )
          query = (
              """
              query Tools($filters: [ToolsFiltering], $search: String, $first: Int, $after: ID, $orderBy: ToolsOrdering, $orderMode: OrderingMode) {
                  tools(filters: $filters, search: $search, first: $first, after: $after, orderBy: $orderBy, orderMode: $orderMode) {
                      edges {
                          node {
                              """
              + self.properties
              + """
                          }
                      }
                      pageInfo {
                          startCursor
                          endCursor
                          hasNextPage
                          hasPreviousPage
                          globalCount
                      }
                  }
              }
          """
          )
          result = self.opencti.query(
              query,
              {
                  "filters": filters,
                  "search": search,
                  "first": first,
                  "after": after,
                  "orderBy": order_by,
                  "orderMode": order_mode,
              },
          )
          return self.opencti.process_multiple(result["data"]["tools"])
  
      """
          Read a Tool object
          
          :param id: the id of the Tool
          :param filters: the filters to apply if no id provided
          :return Tool object
      """
  
      def read(self, **kwargs):
          id = kwargs.get("id", None)
          filters = kwargs.get("filters", None)
          custom_attributes = kwargs.get("customAttributes", None)
          if id is not None:
              self.opencti.log("info", "Reading Tool {" + id + "}.")
              query = (
                  """
                  query Tool($id: String!) {
                      tool(id: $id) {
                          """
                  + (
                      custom_attributes
                      if custom_attributes is not None
                      else self.properties
                  )
                  + """
                      }
                  }
               """
              )
              result = self.opencti.query(query, {"id": id})
              return self.opencti.process_multiple_fields(result["data"]["tool"])
          elif filters is not None:
              result = self.list(filters=filters)
              if len(result) > 0:
                  return result[0]
              else:
                  return None
          else:
              self.opencti.log("error", "Missing parameters: id or filters")
              return None
  
      """
          Create a Tool object
  
          :param name: the name of the Tool
          :return Tool object
      """
  
      def create_raw(self, **kwargs):
          name = kwargs.get("name", None)
          description = kwargs.get("description", None)
          alias = kwargs.get("alias", None)
          id = kwargs.get("id", None)
          stix_id_key = kwargs.get("stix_id_key", None)
          created = kwargs.get("created", None)
          modified = kwargs.get("modified", None)
          created_by_ref = kwargs.get("createdByRef", None)
          marking_definitions = kwargs.get("markingDefinitions", None)
  
          if name is not None and description is not None:
              self.opencti.log("info", "Creating Tool {" + name + "}.")
              query = (
                  """
                  mutation ToolAdd($input: ToolAddInput) {
                      toolAdd(input: $input) {
                          """
                  + self.properties
                  + """
                      }
                  }
              """
              )
              result = self.opencti.query(
                  query,
                  {
                      "input": {
                          "name": name,
                          "description": description,
                          "alias": alias,
                          "internal_id_key": id,
                          "stix_id_key": stix_id_key,
                          "created": created,
                          "modified": modified,
                          "createdByRef": created_by_ref,
                          "markingDefinitions": marking_definitions,
                      }
                  },
              )
              return self.opencti.process_multiple_fields(result["data"]["toolAdd"])
          else:
              self.opencti.log(
                  "error", "[opencti_tool] Missing parameters: name and description"
              )
  
      """
          Create a Tool object only if it not exists, update it on request
  
          :param name: the name of the Tool
          :return Tool object
      """
  
      def create(self, **kwargs):
          name = kwargs.get("name", None)
          description = kwargs.get("description", None)
          alias = kwargs.get("alias", None)
          id = kwargs.get("id", None)
          stix_id_key = kwargs.get("stix_id_key", None)
          created = kwargs.get("created", None)
          modified = kwargs.get("modified", None)
          created_by_ref = kwargs.get("createdByRef", None)
          marking_definitions = kwargs.get("markingDefinitions", None)
          update = kwargs.get("update", False)
          custom_attributes = """
              id
              entity_type
              name
              description 
              alias
          """
          object_result = self.opencti.stix_domain_entity.get_by_stix_id_or_name(
              types=["Tool"],
              stix_id_key=stix_id_key,
              name=name,
              customAttributes=custom_attributes,
          )
          if object_result is not None:
              if update:
                  # name
                  if object_result["name"] != name:
                      self.opencti.stix_domain_entity.update_field(
                          id=object_result["id"], key="name", value=name
                      )
                      object_result["name"] = name
                  # description
                  if object_result["description"] != description:
                      self.opencti.stix_domain_entity.update_field(
                          id=object_result["id"], key="description", value=description
                      )
                      object_result["description"] = description
                  # alias
                  if alias is not None and object_result["alias"] != alias:
                      if "alias" in object_result:
                          new_aliases = object_result["alias"] + list(
                              set(alias) - set(object_result["alias"])
                          )
                      else:
                          new_aliases = alias
                      self.opencti.stix_domain_entity.update_field(
                          id=object_result["id"], key="alias", value=new_aliases
                      )
                      object_result["alias"] = new_aliases
              return object_result
          else:
              return self.create_raw(
                  name=name,
                  description=description,
                  alias=alias,
                  id=id,
                  stix_id_key=stix_id_key,
                  created=created,
                  modified=modified,
                  createdByRef=created_by_ref,
                  markingDefinitions=marking_definitions,
              )
  
      """
          Export an Tool object in STIX2
      
          :param id: the id of the Tool
          :return Tool object
      """
  
      def to_stix2(self, **kwargs):
          id = kwargs.get("id", None)
          mode = kwargs.get("mode", "simple")
          max_marking_definition_entity = kwargs.get(
              "max_marking_definition_entity", None
          )
          entity = kwargs.get("entity", None)
          if id is not None and entity is None:
              entity = self.read(id=id)
          if entity is not None:
              entity = self.read(id=id)
              tool = dict()
              tool["id"] = entity["stix_id_key"]
              tool["type"] = "tool"
              tool["name"] = entity["name"]
              if self.opencti.not_empty(entity["stix_label"]):
                  tool["labels"] = entity["stix_label"]
              else:
                  tool["labels"] = ["tool"]
              if self.opencti.not_empty(entity["description"]):
                  tool["description"] = entity["description"]
              if self.opencti.not_empty(entity["tool_version"]):
                  tool["tool_version"] = entity["tool_version"]
              tool["created"] = self.opencti.stix2.format_date(entity["created"])
              tool["modified"] = self.opencti.stix2.format_date(entity["modified"])
              if self.opencti.not_empty(entity["alias"]):
                  tool[CustomProperties.ALIASES] = entity["alias"]
              tool[CustomProperties.ID] = entity["id"]
              return self.opencti.stix2.prepare_export(
                  entity, tool, mode, max_marking_definition_entity
              )
          else:
              self.opencti.log("error", "Missing parameters: id or entity")
  