# Path: vocto/composite_commands.py
# class CompositeCommand:
# 
#     def __init__(self, composite, A, B):
#         self.composite = composite
#         self.A = A
#         self.B = B
# 
#     def from_str(command):
#         A = None
#         B = None
#         # match case: c(A,B)
#         r = re.match(
#             r'^\s*([|+-]?\w[-_\w]*)\s*\(\s*([-_\w*]+)\s*,\s*([-_\w*]+)\)\s*$', command)
#         if r:
#             A = r.group(2)
#             B = r.group(3)
#         else:
#             # match case: c(A)
#             r = re.match(r'^\s*([|+-]?\w[-_\w]*)\s*\(\s*([-_\w*]+)\s*\)\s*$', command)
#             if r:
#                 A = r.group(2)
#             else:
#                 # match case: c
#                 r = re.match(r'^\s*([|+-]?\w[-_\w]*)\s*$', command)
#                 assert r
#         composite = r.group(1)
#         if composite == '*':
#             composite = None
#         if A == '*':
#             A = None
#         if B == '*':
#             B = None
#         return CompositeCommand(composite,A,B)
# 
#     def modify(self, mod, reverse=False):
#         # get command as string and process all replactions
#         command = original = str(self)
#         for r in mod.split(','):
#             what, _with = r.split('->')
#             if reverse:
#                 what, _with = _with, what
#             command = command.replace(what.strip(), _with.strip())
#         modified = original != command
#         # re-convert string to command and take the elements
#         command = CompositeCommand.from_str(command)
#         self.composite = command.composite
#         self.A = command.A
#         self.B = command.B
#         return modified
# 
#     def unmodify(self, mod):
#         return self.modify(mod, True)
# 
#     def __str__(self):
#         return "%s(%s,%s)" % (self.composite if self.composite else "*",
#                                self.A if self.A else "*",
#                                self.B if self.B else "*")
# 
#     def __eq__(self, other):
#         return ((self.composite == other.composite or not(self.composite and other.composite))
#                 and (self.A == other.A or not(self.A and other.A))
#                 and (self.B == other.B or not(self.B and other.B)))
# 
# Path: vocto/command_helpers.py
# def quote(str):
#     ''' encode spaces and comma '''
#     return None if not str else str.replace('\\', '\\\\').replace(' ','\\s').replace('|','\\v').replace(',','\\c').replace('\n','\\n')
# 
# def dequote(str):
#     ''' decode spaces and comma '''
#     return None if not str else str.replace('\\n','\n').replace('\\c', ',').replace('\\v', '|').replace('\\s', ' ').replace('\\\\', '\\')
# 
# def str2bool(str):
#     return str.lower() in [ 'true', 'yes', 'visible', 'show', '1' ]


import logging
import json
import inspect
import os
from lib.config import Config
from lib.response import NotifyResponse, OkResponse
from lib.sources import restart_source
from vocto.composite_commands import CompositeCommand
from vocto.command_helpers import quote, dequote, str2bool
            p.update()
        return OkResponse('port_report', json.dumps(self.pipeline.ports, default=lambda x: x.todict()))

    # only available when overlays are configured
    if Config.hasOverlay():

        def set_overlay(self, overlay):
            """set an overlay and show"""
            # decode parameter to filename
            filename = Config.getOverlayFilePath(dequote(overlay))
            # check if file exists
            if os.path.isfile(filename):
                # select overlay in mixing pipeline
                self.pipeline.vmix.setOverlay(filename)
            else:
                # tell log about file that could not be found
                self.log.error(
                    "Overlay file '{}' not found".format(filename))
            # respond with current overlay notification
            return self.get_overlay()

        def show_overlay(self, visible):
            """set an overlay and show"""
            # show or hide overlay in mixing pipeline
            self.pipeline.vmix.showOverlay(str2bool(visible))
            # respond with overlay visibility notification
            return self.get_overlay_visible()

        def get_overlay(self):
            """respond any visible overlay"""

# Path: vocto/composite_commands.py
# class CompositeCommand:
# 
#     def __init__(self, composite, A, B):
#         self.composite = composite
#         self.A = A
#         self.B = B
# 
#     def from_str(command):
#         A = None
#         B = None
#         # match case: c(A,B)
#         r = re.match(
#             r'^\s*([|+-]?\w[-_\w]*)\s*\(\s*([-_\w*]+)\s*,\s*([-_\w*]+)\)\s*$', command)
#         if r:
#             A = r.group(2)
#             B = r.group(3)
#         else:
#             # match case: c(A)
#             r = re.match(r'^\s*([|+-]?\w[-_\w]*)\s*\(\s*([-_\w*]+)\s*\)\s*$', command)
#             if r:
#                 A = r.group(2)
#             else:
#                 # match case: c
#                 r = re.match(r'^\s*([|+-]?\w[-_\w]*)\s*$', command)
#                 assert r
#         composite = r.group(1)
#         if composite == '*':
#             composite = None
#         if A == '*':
#             A = None
#         if B == '*':
#             B = None
#         return CompositeCommand(composite,A,B)
# 
#     def modify(self, mod, reverse=False):
#         # get command as string and process all replactions
#         command = original = str(self)
#         for r in mod.split(','):
#             what, _with = r.split('->')
#             if reverse:
#                 what, _with = _with, what
#             command = command.replace(what.strip(), _with.strip())
#         modified = original != command
#         # re-convert string to command and take the elements
#         command = CompositeCommand.from_str(command)
#         self.composite = command.composite
#         self.A = command.A
#         self.B = command.B
#         return modified
# 
#     def unmodify(self, mod):
#         return self.modify(mod, True)
# 
#     def __str__(self):
#         return "%s(%s,%s)" % (self.composite if self.composite else "*",
#                                self.A if self.A else "*",
#                                self.B if self.B else "*")
# 
#     def __eq__(self, other):
#         return ((self.composite == other.composite or not(self.composite and other.composite))
#                 and (self.A == other.A or not(self.A and other.A))
#                 and (self.B == other.B or not(self.B and other.B)))
# 
# Path: vocto/command_helpers.py
# def quote(str):
#     ''' encode spaces and comma '''
#     return None if not str else str.replace('\\', '\\\\').replace(' ','\\s').replace('|','\\v').replace(',','\\c').replace('\n','\\n')
# 
# def dequote(str):
#     ''' decode spaces and comma '''
#     return None if not str else str.replace('\\n','\n').replace('\\c', ',').replace('\\v', '|').replace('\\s', ' ').replace('\\\\', '\\')
# 
# def str2bool(str):
#     return str.lower() in [ 'true', 'yes', 'visible', 'show', '1' ]


# Path: voctocore/lib/commands.py
import logging
import json
import inspect
import os
from lib.config import Config
from lib.response import NotifyResponse, OkResponse
from lib.sources import restart_source
from vocto.composite_commands import CompositeCommand
from vocto.command_helpers import quote, dequote, str2bool

            p.update()
        return OkResponse('port_report', json.dumps(self.pipeline.ports, default=lambda x: x.todict()))

    # only available when overlays are configured
    if Config.hasOverlay():

        def set_overlay(self, overlay):
            """set an overlay and show"""
            # decode parameter to filename
            filename = Config.getOverlayFilePath(dequote(overlay))
            # check if file exists
            if os.path.isfile(filename):
                # select overlay in mixing pipeline
                self.pipeline.vmix.setOverlay(filename)
            else:
                # tell log about file that could not be found
                self.log.error(
                    "Overlay file '{}' not found".format(filename))
            # respond with current overlay notification
            return self.get_overlay()

        def show_overlay(self, visible):
            """set an overlay and show"""
            # show or hide overlay in mixing pipeline
            self.pipeline.vmix.showOverlay(str2bool(visible))
            # respond with overlay visibility notification
            return self.get_overlay_visible()

        def get_overlay(self):
            """respond any visible overlay"""

            return NotifyResponse('overlay', quote(Config.getOverlayNameFromFilePath(self.pipeline.vmix.getOverlay())))