#!/usr/bin/env python

#
# Licensed to the Apache Software Foundation (ASF) 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 os
import getopt
import sys
from qpid import qmfconsole

_recursive    = False
_host         = "localhost"
_durable      = False
_fileCount    = 8
_fileSize     = 24
_maxQueueSize = None
_maxQueueCount= None


FILECOUNT = "qpid.file_count"
FILESIZE  = "qpid.file_size"
MAX_QUEUE_SIZE  = "qpid.max_size"
MAX_QUEUE_COUNT  = "qpid.max_count"

def Usage ():
    print "Usage:  qpid-config [OPTIONS]"
    print "        qpid-config [OPTIONS] exchanges [filter-string]"
    print "        qpid-config [OPTIONS] queues    [filter-string]"
    print "        qpid-config [OPTIONS] add exchange <type> <name> [AddExchangeOptions]"
    print "        qpid-config [OPTIONS] del exchange <name>"
    print "        qpid-config [OPTIONS] add queue <name> [AddQueueOptions]"
    print "        qpid-config [OPTIONS] del queue <name>"
    print "        qpid-config [OPTIONS] bind   <exchange-name> <queue-name> [binding-key]"
    print "        qpid-config [OPTIONS] unbind <exchange-name> <queue-name> [binding-key]"
    print
    print "Options:"
    print "    -b [ --bindings ]                         Show bindings in queue or exchange list"
    print "    -a [ --broker-addr ] Address (localhost)  Address of qpidd broker"
    print "         broker-addr is in the form:   [username/password@] hostname | ip-address [:<port>]"
    print "         ex:  localhost, 10.1.1.7:10000, broker-host:10000, guest/guest@localhost"
    print
    print "Add Queue Options:"
    print "    --durable           Queue is durable"
    print "    --file-count N (8)  Number of files in queue's persistence journal"
    print "    --file-size  N (24) File size in pages (64Kib/page)"
    print "    --max-queue-size N  Maximum in-memory queue size as bytes"
    print "    --max-queue-count N Maximum in-memory queue size as a number of messages"
    print
    print "Add Exchange Options:"
    print "    --durable           Exchange is durable"
    print
    sys.exit (1)

class BrokerManager:
    def __init__ (self):
        self.brokerName = None
        self.qmf        = None
        self.broker     = None

    def SetBroker (self, brokerUrl):
        self.url = brokerUrl
        self.qmf = qmfconsole.Session()
        self.broker = self.qmf.addBroker(brokerUrl)

    def Disconnect(self):
        self.qmf.delBroker(self.broker)

    def Overview (self):
        exchanges = self.qmf.getObjects(name="exchange")
        queues    = self.qmf.getObjects(name="queue")
        print "Total Exchanges: %d" % len (exchanges)
        etype = {}
        for ex in exchanges:
            if ex.type not in etype:
                etype[ex.type] = 1
            else:
                etype[ex.type] = etype[ex.type] + 1
        for typ in etype:
            print "%15s: %d" % (typ, etype[typ])

        print
        print "   Total Queues: %d" % len (queues)
        _durable = 0
        for queue in queues:
            if queue.durable:
                _durable = _durable + 1
        print "        durable: %d" % _durable
        print "    non-durable: %d" % (len (queues) - _durable)

    def ExchangeList (self, filter):
        exchanges = self.qmf.getObjects(name="exchange")
        print "Durable   Type      Bindings  Exchange Name"
        print "======================================================="
        for ex in exchanges:
            if self.match (ex.name, filter):
                print "%4c      %-10s%5d     %s" % (YN (ex.durable), ex.type, ex.bindingCount, ex.name)

    def ExchangeListRecurse (self, filter):
        exchanges = self.qmf.getObjects(name="exchange")
        bindings  = self.qmf.getObjects(name="binding")
        queues    = self.qmf.getObjects(name="queue")
        for ex in exchanges:
            if self.match (ex.name, filter):
                print "Exchange '%s' (%s)" % (ex.name, ex.type)
                for bind in bindings:
                    if bind.exchangeRef == ex.getObjectId():
                        qname = "<unknown>"
                        queue = self.findById (queues, bind.queueRef)
                        if queue != None:
                            qname = queue.name
                        print "    bind [%s] => %s" % (bind.bindingKey, qname)
            

    def QueueList (self, filter):
        queues   = self.qmf.getObjects(name="queue")
        journals = self.qmf.getObjects(name="journal")
        print "                                      Store Size"
        print "Durable  AutoDel  Excl  Bindings  (files x file pages)  Queue Name"
        print "==========================================================================================="
        for q in queues:
            if self.match (q.name, filter):
                args = q.arguments
                if q.durable and FILESIZE in args and FILECOUNT in args:
                    fs = int (args[FILESIZE])
                    fc = int (args[FILECOUNT])
                    print "%4c%9c%7c%10d%11dx%-14d%s" % \
                        (YN (q.durable), YN (q.autoDelete),
                         YN (q.exclusive), q.bindingCount, fc, fs, q.name)
                else:
                    if not _durable:
                        print "%4c%9c%7c%10d                          %s" % \
                            (YN (q.durable), YN (q.autoDelete),
                             YN (q.exclusive), q.bindingCount, q.name)

    def QueueListRecurse (self, filter):
        exchanges = self.qmf.getObjects(name="exchange")
        bindings  = self.qmf.getObjects(name="binding")
        queues    = self.qmf.getObjects(name="queue")
        for queue in queues:
            if self.match (queue.name, filter):
                print "Queue '%s'" % queue.name
                for bind in bindings:
                    if bind.queueRef == queue.getObjectId():
                        ename = "<unknown>"
                        ex    = self.findById (exchanges, bind.exchangeRef)
                        if ex != None:
                            ename = ex.name
                            if ename == "":
                                ename = "''"
                        print "    bind [%s] => %s" % (bind.bindingKey, ename)

    def AddExchange (self, args):
        if len (args) < 2:
            Usage ()
        etype = args[0]
        ename = args[1]
        self.broker.getAmqpSession().exchange_declare (exchange=ename, type=etype, durable=_durable)

    def DelExchange (self, args):
        if len (args) < 1:
            Usage ()
        ename = args[0]
        self.broker.getAmqpSession().exchange_delete (exchange=ename)

    def AddQueue (self, args):
        if len (args) < 1:
            Usage ()
        qname    = args[0]
        declArgs = {}
        if _durable:
            declArgs[FILECOUNT] = _fileCount
            declArgs[FILESIZE]  = _fileSize

        if _maxQueueSize:
            declArgs[MAX_QUEUE_SIZE]  = _maxQueueSize
        if _maxQueueCount:
            declArgs[MAX_QUEUE_COUNT]  = _maxQueueCount

        self.broker.getAmqpSession().queue_declare (queue=qname, durable=_durable, arguments=declArgs)

    def DelQueue (self, args):
        if len (args) < 1:
            Usage ()
        qname = args[0]
        self.broker.getAmqpSession().queue_delete (queue=qname)

    def Bind (self, args):
        if len (args) < 2:
            Usage ()
        ename = args[0]
        qname = args[1]
        key   = ""
        if len (args) > 2:
            key = args[2]
        self.broker.getAmqpSession().exchange_bind (queue=qname, exchange=ename, binding_key=key)

    def Unbind (self, args):
        if len (args) < 2:
            Usage ()
        ename = args[0]
        qname = args[1]
        key   = ""
        if len (args) > 2:
            key = args[2]
        self.broker.getAmqpSession().exchange_unbind (queue=qname, exchange=ename, binding_key=key)

    def findById (self, items, id):
        for item in items:
            if item.getObjectId() == id:
                return item
        return None

    def match (self, name, filter):
        if filter == "":
            return True
        if name.find (filter) == -1:
            return False
        return True

def YN (bool):
    if bool:
        return 'Y'
    return 'N'

##
## Main Program
##

try:
    longOpts = ("durable", "bindings", "broker-addr=", "file-count=", "file-size=", "max-queue-size=", "max-queue-count=")
    (optlist, cargs) = getopt.gnu_getopt (sys.argv[1:], "a:b", longOpts)
except:
    Usage ()

for opt in optlist:
    if opt[0] == "-b" or opt[0] == "--bindings":
        _recursive = True
    if opt[0] == "-a" or opt[0] == "--broker-addr":
        _host = opt[1]
    if opt[0] == "--durable":
        _durable = True
    if opt[0] == "--file-count":
        _fileCount = int (opt[1])
    if opt[0] == "--file-size":
        _fileSize = int (opt[1])
    if opt[0] == "--max-queue-size":
        _maxQueueSize = int (opt[1])
    if opt[0] == "--max-queue-count":
        _maxQueueCount = int (opt[1])

nargs = len (cargs)
bm    = BrokerManager ()

try:
    bm.SetBroker(_host)
    if nargs == 0:
        bm.Overview ()
    else:
        cmd = cargs[0]
        modifier = ""
        if nargs > 1:
            modifier = cargs[1]
        if cmd[0] == 'e':
            if _recursive:
                bm.ExchangeListRecurse (modifier)
            else:
                bm.ExchangeList (modifier)
        elif cmd[0] == 'q':
            if _recursive:
                bm.QueueListRecurse (modifier)
            else:
                bm.QueueList (modifier)
        elif cmd == "add":
            if modifier == "exchange":
                bm.AddExchange (cargs[2:])
            elif modifier == "queue":
                bm.AddQueue (cargs[2:])
            else:
                Usage ()
        elif cmd == "del":
            if modifier == "exchange":
                bm.DelExchange (cargs[2:])
            elif modifier == "queue":
                bm.DelQueue (cargs[2:])
            else:
                Usage ()
        elif cmd == "bind":
            bm.Bind (cargs[1:])
        elif cmd == "unbind":
            bm.Unbind (cargs[1:])
        else:
            Usage ()
except Exception,e:
    raise
    print "Failed:", e.message
    sys.exit(1)

bm.Disconnect()
