#if not $generate_options.startswith('hb')
#!/usr/bin/env python2
#end if
# -*- coding: utf-8 -*-
########################################################
##Cheetah template - gnuradio_python
##
##@param imports the import statements
##@param flow_graph the flow_graph
##@param variables the variable blocks
##@param parameters the parameter blocks
##@param blocks the signal blocks
##@param connections the connections
##@param msgs the msg type connections
##@param generate_options the type of flow graph
##@param callbacks variable id map to callback strings
########################################################
#def indent($code)
#set $code = '\n        '.join(str($code).splitlines())
$code#slurp
#end def
#import time
#set $DIVIDER = '#'*50
$DIVIDER
# GNU Radio Python Flow Graph
# Title: $title
#if $flow_graph.get_option('author')
# Author: $flow_graph.get_option('author')
#end if
#if $flow_graph.get_option('description')
# Description: $flow_graph.get_option('description')
#end if
# Generated: $time.ctime()
$DIVIDER
#if $flow_graph.get_option('thread_safe_setters')
import threading
#end if

## Call XInitThreads as the _very_ first thing.
## After some Qt import, it's too late
#if $generate_options in ('wx_gui', 'qt_gui', 'bokeh_gui')
if __name__ == '__main__':
    import ctypes
    import sys
    if sys.platform.startswith('linux'):
        try:
            x11 = ctypes.cdll.LoadLibrary('libX11.so')
            x11.XInitThreads()
        except:
            print "Warning: failed to XInitThreads()"

#end if
#
########################################################
##Create Imports
########################################################
#if $flow_graph.get_option('qt_qss_theme')
#set imports = $sorted(set($imports + ["import os", "import sys"]))
#end if
#if any(imp.endswith("# grc-generated hier_block") for imp in $imports)
import os
import sys
#set imports = $filter(lambda i: i not in ("import os", "import sys"), $imports)
sys.path.append(os.environ.get('GRC_HIER_PATH', os.path.expanduser('~/.grc_gnuradio')))

#end if
#for $imp in $imports
##$(imp.replace("  # grc-generated hier_block", ""))
$imp
#end for
########################################################
##Create Class
##  Write the class declaration for a top or hier block.
##  The parameter names are the arguments to __init__.
##  Determine the absolute icon path (wx gui only).
##  Setup the IO signature (hier block only).
########################################################
#set $class_name = $flow_graph.get_option('id')
#set $param_str = ', '.join(['self'] + ['%s=%s'%(param.get_id(), param.get_make()) for param in $parameters])
#if $generate_options == 'wx_gui'
    #import gtk
    #set $icon = gtk.IconTheme().lookup_icon('gnuradio-grc', 32, 0)


class $(class_name)(grc_wxgui.top_block_gui):

    def __init__($param_str):
        grc_wxgui.top_block_gui.__init__(self, title="$title")
    #if $icon
        _icon_path = "$icon.get_filename()"
        self.SetIcon(wx.Icon(_icon_path, wx.BITMAP_TYPE_ANY))
    #end if
#elif $generate_options == 'qt_gui'
from gnuradio import qtgui


class $(class_name)(gr.top_block, Qt.QWidget):

    def __init__($param_str):
        gr.top_block.__init__(self, "$title")
        Qt.QWidget.__init__(self)
        self.setWindowTitle("$title")
        qtgui.util.check_set_qss()
        try:
            self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
        except:
            pass
        self.top_scroll_layout = Qt.QVBoxLayout()
        self.setLayout(self.top_scroll_layout)
        self.top_scroll = Qt.QScrollArea()
        self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
        self.top_scroll_layout.addWidget(self.top_scroll)
        self.top_scroll.setWidgetResizable(True)
        self.top_widget = Qt.QWidget()
        self.top_scroll.setWidget(self.top_widget)
        self.top_layout = Qt.QVBoxLayout(self.top_widget)
        self.top_grid_layout = Qt.QGridLayout()
        self.top_layout.addLayout(self.top_grid_layout)

        self.settings = Qt.QSettings("GNU Radio", "$class_name")
        self.restoreGeometry(self.settings.value("geometry").toByteArray())

#elif $generate_options == 'bokeh_gui'

class $(class_name)(gr.top_block):
    def __init__(self, doc):
        gr.top_block.__init__(self, "$title")
        self.doc = doc
        self.plot_lst = []
        self.widget_lst = []
#elif $generate_options == 'no_gui'


class $(class_name)(gr.top_block):

    def __init__($param_str):
        gr.top_block.__init__(self, "$title")
#elif $generate_options.startswith('hb')
    #set $in_sigs = $flow_graph.get_hier_block_stream_io('in')
    #set $out_sigs = $flow_graph.get_hier_block_stream_io('out')


#if $generate_options == 'hb_qt_gui'
class $(class_name)(gr.hier_block2, Qt.QWidget):
#else
class $(class_name)(gr.hier_block2):
#end if
#def make_io_sig($io_sigs)
    #set $size_strs = ['%s*%s'%(io_sig['size'], io_sig['vlen']) for io_sig in $io_sigs]
    #if len($io_sigs) == 0
gr.io_signature(0, 0, 0)#slurp
    #elif len($io_sigs) == 1
gr.io_signature(1, 1, $size_strs[0])#slurp
    #else
gr.io_signaturev($(len($io_sigs)), $(len($io_sigs)), [$(', '.join($size_strs))])#slurp
    #end if
#end def

    def __init__($param_str):
        gr.hier_block2.__init__(
            self, "$title",
            $make_io_sig($in_sigs),
            $make_io_sig($out_sigs),
        )
    #for $pad in $flow_graph.get_hier_block_message_io('in')
        self.message_port_register_hier_in("$pad['label']")
    #end for
    #for $pad in $flow_graph.get_hier_block_message_io('out')
        self.message_port_register_hier_out("$pad['label']")
    #end for
    #if $generate_options == 'hb_qt_gui'

        Qt.QWidget.__init__(self)
        self.top_layout = Qt.QVBoxLayout()
        self.top_grid_layout = Qt.QGridLayout()
        self.top_layout.addLayout(self.top_grid_layout)
        self.setLayout(self.top_layout)
    #end if
#end if
#if $flow_graph.get_option('thread_safe_setters')

        self._lock = threading.RLock()
#end if
########################################################
##Create Parameters
##  Set the parameter to a property of self.
########################################################
#if $parameters

        $DIVIDER
        # Parameters
        $DIVIDER
#end if
#for $param in $parameters
        $indent($param.get_var_make())
#end for
########################################################
##Create Variables
########################################################
#if $variables

        $DIVIDER
        # Variables
        $DIVIDER
#end if
#for $var in $variables
        $indent($var.get_var_make())
#end for
########################################################
##Create Message Queues
########################################################
#if $msgs

        $DIVIDER
        # Message Queues
        $DIVIDER
#end if
#for $msg in $msgs
        $(msg.get_source().get_parent().get_id())_msgq_out = $(msg.get_sink().get_parent().get_id())_msgq_in = gr.msg_queue(2)
#end for
########################################################
##Create Blocks
########################################################
#if $blocks

        $DIVIDER
        # Blocks
        $DIVIDER
#end if
#for $blk in filter(lambda b: b.get_make(), $blocks)
    #if $blk in $variables
        $indent($blk.get_make())
    #else
        self.$blk.get_id() = $indent($blk.get_make())
        #if $blk.has_param('alias') and $blk.get_param('alias').get_evaluated()
        (self.$blk.get_id()).set_block_alias("$blk.get_param('alias').get_evaluated()")
        #end if
        #if $blk.has_param('affinity') and $blk.get_param('affinity').get_evaluated()
        (self.$blk.get_id()).set_processor_affinity($blk.get_param('affinity').get_evaluated())
        #end if
        #if (len($blk.get_sources())>0) and $blk.has_param('minoutbuf') and (int($blk.get_param('minoutbuf').get_evaluated()) > 0)
        (self.$blk.get_id()).set_min_output_buffer($blk.get_param('minoutbuf').get_evaluated())
        #end if
        #if (len($blk.get_sources())>0) and $blk.has_param('maxoutbuf') and (int($blk.get_param('maxoutbuf').get_evaluated()) > 0)
        (self.$blk.get_id()).set_max_output_buffer($blk.get_param('maxoutbuf').get_evaluated())
        #end if
    #end if
#end for

##########################################################
## Create a layout entry if not manually done for BokehGUI
##########################################################
#if $generate_options == 'bokeh_gui'
        if self.widget_lst:
            input_t = bokehgui.BokehLayout.widgetbox(self.widget_lst)
            widgetbox = bokehgui.BokehLayout.WidgetLayout(input_t)
            widgetbox.set_layout(*($flow_graph.get_option('placement')))
            list_obj = [widgetbox] + self.plot_lst
        else:
            list_obj = self.plot_lst
        layout_t = bokehgui.BokehLayout.create_layout(list_obj, "$flow_graph.get_option('sizing_mode')")
        self.doc.add_root(layout_t)
#end if

########################################################
##Create Connections
##  The port name should be the id of the parent block.
##  However, port names for IO pads should be self.
########################################################
#def make_port_sig($port)
    #if $port.get_parent().get_key() in ('pad_source', 'pad_sink')
        #set block = 'self'
        #set key = $flow_graph.get_pad_port_global_key($port)
    #else
        #set block = 'self.' + $port.get_parent().get_id()
        #set key = $port.get_key()
    #end if
    #if not $key.isdigit()
        #set key = repr($key)
    #end if
($block, $key)#slurp
#end def
#if $connections

        $DIVIDER
        # Connections
        $DIVIDER
#end if
#for $con in $connections
    #set global $source = $con.get_source()
    #set global $sink = $con.get_sink()
    #include source=$connection_templates[($source.get_domain(), $sink.get_domain())]

#end for
########################################################
## QT sink close method reimplementation
########################################################
#if $generate_options == 'qt_gui'

    def closeEvent(self, event):
        self.settings = Qt.QSettings("GNU Radio", "$class_name")
        self.settings.setValue("geometry", self.saveGeometry())
        event.accept()
    #if $flow_graph.get_option('qt_qss_theme')

    def setStyleSheetFromFile(self, filename):
        try:
            if not os.path.exists(filename):
                filename = os.path.join(
                    gr.prefix(), "share", "gnuradio", "themes", filename)
            with open(filename) as ss:
                self.setStyleSheet(ss.read())
        except Exception as e:
            print >> sys.stderr, e
    #end if
#end if
########################################################
##Create Callbacks
##  Write a set method for this variable that calls the callbacks
########################################################
#for $var in $parameters + $variables

    #set $id = $var.get_id()
    def get_$(id)(self):
        return self.$id

    def set_$(id)(self, $id):
    #if $flow_graph.get_option('thread_safe_setters')
        with self._lock:
            self.$id = $id
        #for $callback in $callbacks[$id]
            $indent($callback)
        #end for
    #else
        self.$id = $id
        #for $callback in $callbacks[$id]
        $indent($callback)
        #end for
    #end if
#end for
########################################################
##Create Main
##  For top block code, generate a main routine.
##  Instantiate the top block and run as gui or cli.
########################################################
#def make_default($type, $param)
    #if $type == 'eng_float'
eng_notation.num_to_str($param.get_make())#slurp
    #else
$param.get_make()#slurp
    #end if
#end def
#def make_short_id($param)
    #set $short_id = $param.get_param('short_id').get_evaluated()
    #if $short_id
        #set $short_id = '-' + $short_id
    #end if
$short_id#slurp
#end def
#if not $generate_options.startswith('hb')
#set $params_eq_list = list()
#if $parameters


def argument_parser():
    #set $desc_args = 'usage="%prog: [options]", option_class=eng_option'
    #if $flow_graph.get_option('description')
        #set $desc_args += ', description=description'
    description = $repr($flow_graph.get_option('description'))
    #end if
    parser = OptionParser($desc_args)
    #for $param in $parameters
        #set $type = $param.get_param('type').get_value()
        #if $type
            #silent $params_eq_list.append('%s=options.%s'%($param.get_id(), $param.get_id()))
    parser.add_option(
        "$make_short_id($param)", "--$param.get_id().replace('_', '-')", dest="$param.get_id()", type="$type", default=$make_default($type, $param),
        help="Set $($param.get_param('label').get_evaluated() or $param.get_id()) [default=%default]")
        #end if
    #end for
    return parser
#end if


def main(top_block_cls=$(class_name), options=None):
    #if $parameters
    if options is None:
        options, _ = argument_parser().parse_args()
    #end if
    #if $flow_graph.get_option('realtime_scheduling')
    if gr.enable_realtime_scheduling() != gr.RT_OK:
        print "Error: failed to enable real-time scheduling."
    #end if

    #if $generate_options == 'wx_gui'
    tb = top_block_cls($(', '.join($params_eq_list)))
        #if $flow_graph.get_option('max_nouts')
    tb.Run($flow_graph.get_option('run'), $flow_graph.get_option('max_nouts'))
        #else
    tb.Start($flow_graph.get_option('run'))
        #for $m in $monitors
    (tb.$m.get_id()).start()
        #end for
    tb.Wait()
        #end if
    #elif $generate_options == 'bokeh_gui'
    serverProc, port = bokehgui.utils.create_server()
    def killProc(signum, frame, tb):
        tb.stop()
        tb.wait()
        serverProc.terminate()
        serverProc.kill()
    time.sleep(1)
    try:
        \# Define the document instance
        doc = curdoc()
        #if $flow_graph.get_option('author')
        doc.title = "$title - $flow_graph.get_option('author')"
        #else
        doc.title = "$title"
        #end if
        session = push_session(doc, session_id="$flow_graph.get_option('id')",
                               url = "http://localhost:" + port + "/bokehgui")
        \# Create Top Block instance
        tb = top_block_cls(doc)
        try:
            tb.start()
            signal.signal(signal.SIGTERM, functools.partial(killProc, tb=tb))
            session.loop_until_closed()
        finally:
            print "Exiting the simulation. Stopping Bokeh Server"
            tb.stop()
            tb.wait()
    finally:
        serverProc.terminate()
        serverProc.kill()
    #elif $generate_options == 'qt_gui'
    from distutils.version import StrictVersion
    if StrictVersion(Qt.qVersion()) >= StrictVersion("4.5.0"):
        style = gr.prefs().get_string('qtgui', 'style', 'raster')
        Qt.QApplication.setGraphicsSystem(style)
    qapp = Qt.QApplication(sys.argv)

    tb = top_block_cls($(', '.join($params_eq_list)))
    #if $flow_graph.get_option('run')
        #if $flow_graph.get_option('max_nouts')
    tb.start($flow_graph.get_option('max_nouts'))
        #else
    tb.start()
        #end if
    #end if
    #if $flow_graph.get_option('qt_qss_theme')
    tb.setStyleSheetFromFile($repr($flow_graph.get_option('qt_qss_theme')))
    #end if
    tb.show()

    def quitting():
        tb.stop()
        tb.wait()
    qapp.connect(qapp, Qt.SIGNAL("aboutToQuit()"), quitting)
        #for $m in $monitors
    if $m.has_param('en'):
        if $m.get_param('en').get_value():
            (tb.$m.get_id()).start()
    else:
        sys.stderr.write("Monitor '{0}' does not have an enable ('en') parameter.".format("tb.$m.get_id()"))
        #end for
    qapp.exec_()
    #elif $generate_options == 'no_gui'
    tb = top_block_cls($(', '.join($params_eq_list)))
        #set $run_options = $flow_graph.get_option('run_options')
        #if $run_options == 'prompt'
            #if $flow_graph.get_option('max_nouts')
    tb.start($flow_graph.get_option('max_nouts'))
            #else
    tb.start()
            #end if
        #for $m in $monitors
    (tb.$m.get_id()).start()
        #end for
    try:
        raw_input('Press Enter to quit: ')
    except EOFError:
        pass
    tb.stop()
        #elif $run_options == 'run'
            #if $flow_graph.get_option('max_nouts')
    tb.start($flow_graph.get_option('max_nouts'))
            #else
    tb.start()
            #end if
        #end if
        #for $m in $monitors
    (tb.$m.get_id()).start()
        #end for
    tb.wait()
    #end if


if __name__ == '__main__':
    main()
#end if
