#!/usr/bin/env python
#encoding:utf-8
# Copyright (C) 2015, Alibaba Cloud Computing

#Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

#The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import os
import sys
import ConfigParser
from optparse import OptionParser
from mns.account import Account
from mns.queue import *
from mns.mns_exception import *

CONFIGFILE = "%s/.mnscredentials" % os.path.expanduser('~')
CONFIGSECTION = 'MNSCredentials'

CMD_RULES = {"config"             : "config --endpoint=http://$accountid.mns.cn-hangzhou.aliyuncs.com --accesskeyid=YOUR_ACCESSKEYID --accesskeysecret=YOUR_ACCESSKEYSECRET",
            "listqueue"           : "listqueue [--prefix=xxx] [--retnum=xxx] [--marker=xxx]",
            "createqueue"         : "createqueue --queuename=xxx [--vistimeout=xxx] [--maxmsgsize=xxx] [--retentionperiod=xxx] [--delaysec=xxx] [--waitsec=xxx]",
            "setqueueattr"        : "setqueueattr --queuename=xxx [--vistimeout=xxx] [--maxmsgsize=xxx] [--retentionperiod=xxx] [--delaysec=xxx] [--waitsec=xxx]",
            "getqueueattr"        : "getqueueattr --queuename=xxx",
            "deletequeue"         : "deletequeue --queuename=xxx",
            "sendmessage"         : "sendmessage --queuename=xxx --body=xxx [--delaysec=xxx --priority=xxx]",
            "receivemessage"      : "receivemessage --queuename=xxx [--waitsec=xxx]",
            "peekmessage"         : "peekmessage --queuename=xxx",
            "deletemessage"       : "deletemessage --queuename=xxx --handle=xxx",
            "changevisibility"    : "changevisibility --queuename=xxx --handle=xxx --vistimeout=xxx"}

class MNSCmd:
    def config(self, args, options):
        MNSCmd.miss_parameters((options.endpoint is None or \
                                options.accesskeyid is None or \
                                options.accesskeysecret is None), 
                                args)
        config = ConfigParser.RawConfigParser()
        config.add_section(CONFIGSECTION)
        config.set(CONFIGSECTION, "endpoint", options.endpoint)
        config.set(CONFIGSECTION, "accesskeyid", options.accesskeyid)
        config.set(CONFIGSECTION, "accesskeysecret", options.accesskeysecret)
        cfgfile = open(CONFIGFILE, "w+")
        config.write(cfgfile)
        print "Your configuration is saved into %s ." % CONFIGFILE
        cfgfile.close()
        import stat
        os.chmod(CONFIGFILE, stat.S_IREAD | stat.S_IWRITE)
    
    def setup_credentials(self):
        config = ConfigParser.ConfigParser()
        try:
            config.read(CONFIGFILE)
            if not config.has_option(CONFIGSECTION, "endpoint") or \
                not config.has_option(CONFIGSECTION, "accesskeyid") or \
                not config.has_option(CONFIGSECTION, "accesskeysecret"):
                print "Missing credentials in %s. \nmnscmd config to init credentials." % CONFIGFILE
            self.endpoint = config.get(CONFIGSECTION, "endpoint")
            self.accesskeyid = config.get(CONFIGSECTION, "accesskeyid")
            self.accesskeysecret = config.get(CONFIGSECTION, "accesskeysecret")
            self.account = Account(self.endpoint, self.accesskeyid, self.accesskeysecret)
            self.account.set_debug(True)
        except Exception:
            print "Can't get credentials.\nmnscmd config to init credentials."
        
    def listqueue(self, args, options):
        prefix = "" if options.prefix is None else options.prefix
        retnum = -1 if options.retnum is None else options.retnum
        marker = "" if options.marker is None else options.marker

        try:
            queueurl_list, nextmarker = self.account.list_queue(prefix, retnum, marker)
            MNSCmd.cmd_succeed(args[0])

            if len(queueurl_list) == 0:
                print "Queue not exist in this account."
            else:
                print "\n".join(["QueueURL:%s" % item for item in queueurl_list])
                print "\nListQueueNumber:%s" % len(queueurl_list)
            if nextmarker != "":
                print "NextMarker:%s" % nextmarker 
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def createqueue(self, args, options):
        MNSCmd.miss_parameters(options.queuename is None, args)
        queue = self.account.get_queue(options.queuename)
        queue_meta = MNSCmd.init_queuemeta(options)

        try:
            queue_url = queue.create(queue_meta)
            MNSCmd.cmd_succeed(args[0], "QueueURL:%s" % queue_url)
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def setqueueattr(self, args, options):
        MNSCmd.miss_parameters(options.queuename is None, args)
        queue = self.account.get_queue(options.queuename)
        queue_meta =  MNSCmd.init_queuemeta(options)

        try:
            queue_url = queue.set_attributes(queue_meta)
            MNSCmd.cmd_succeed(args[0])
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)
            
    def getqueueattr(self, args, options):
        MNSCmd.miss_parameters(options.queuename is None, args)
        queue = self.account.get_queue(options.queuename)

        try:
            queue_meta = queue.get_attributes()
            MNSCmd.cmd_succeed(args[0], "\nQueueMeta\n%s" % queue_meta)
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def deletequeue(self, args, options):
        MNSCmd.miss_parameters(options.queuename is None, args)
        queue = self.account.get_queue(options.queuename)

        try:
            queue.delete()
            MNSCmd.cmd_succeed(args[0])
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def sendmessage(self, args, options):
        MNSCmd.miss_parameters((options.queuename is None or options.body is None), args)
        queue = self.account.get_queue(options.queuename)

        message = Message(options.body)
        if options.delaysec is not None:
            message.set_delayseconds(options.delaysec)
        if options.priority is not None:
            message.set_priority(options.priority)

        try:
            rmsg = queue.send_message(message)
            MNSCmd.cmd_succeed(args[0])
            MNSCmd.print_attr({"MessageID"      : rmsg.message_id,
                               "MessageBodyMD5" : rmsg.message_body_md5})
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def receivemessage(self, args, options):
        MNSCmd.miss_parameters(options.queuename is None, args)
        queue = self.account.get_queue(options.queuename)
        wait_seconds = -1 if options.waitsec is None else options.waitsec

        try:
            rmsg = queue.receive_message(wait_seconds)
            MNSCmd.cmd_succeed(args[0])
            MNSCmd.print_attr({ "MessageBody"       : rmsg.message_body, 
                                "MessageID"         : rmsg.message_id,
                                "MessageBodyMD5"    : rmsg.message_body_md5,
                                "DequeueCount"      : rmsg.dequeue_count,
                                "EnqueueTime"       : rmsg.enqueue_time,
                                "FirstDequeueTime"  : rmsg.first_dequeue_time,
                                "Priority"          : rmsg.priority,
                                "ReceiptHandle"     : rmsg.receipt_handle,
                                "NextVisibleTime"   : rmsg.next_visible_time})
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def peekmessage(self, args, options):
        MNSCmd.miss_parameters(options.queuename is None, args)
        queue = self.account.get_queue(options.queuename)

        try:
            rmsg = queue.peek_message()
            MNSCmd.cmd_succeed(args[0])
            MNSCmd.print_attr({ "MessageBody"       : rmsg.message_body,
                                "MessageID"         : rmsg.message_id,
                                "MessageBodyMD5"    : rmsg.message_body_md5,
                                "DequeueCount"      : rmsg.dequeue_count,
                                "EnqueueTime"       : rmsg.enqueue_time,
                                "FirstDequeueTime"  : rmsg.first_dequeue_time,
                                "Priority"          : rmsg.priority})
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def deletemessage(self, args, options):
        MNSCmd.miss_parameters( (options.queuename is None or options.handle is None), args)
        queue = self.account.get_queue(options.queuename)

        try:
            queue.delete_message(options.handle)
            MNSCmd.cmd_succeed(args[0])
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    def changevisibility(self, args, options):
        MNSCmd.miss_parameters((options.queuename is None or \
                                options.handle is None or \
                                options.vistimeout is None), 
                               args)
        queue = self.account.get_queue(options.queuename)

        try:
            rmsg = queue.change_message_visibility(options.handle, options.vistimeout)
            MNSCmd.cmd_succeed(args[0])
            MNSCmd.print_attr({"ReceiptHandle"   : rmsg.receipt_handle,
                               "NextVisibleTime" : rmsg.next_visible_time})
        except MNSExceptionBase, e:
            MNSCmd.cmd_exception(args[0], e)

    @staticmethod
    def miss_parameters(condition, args):
        if condition:
            print "%s miss parameters." % args[0]
            print_help(args[0])

    @staticmethod
    def init_queuemeta(options):            
        queue_meta = QueueMeta()
        if options.vistimeout is not None:
            queue_meta.set_visibilitytimeout(options.vistimeout)
        if options.maxmsgsize is not None:
            queue_meta.set_maximum_message_size(options.maxmsgsize)
        if options.retentionperiod is not None:
            queue_meta.set_message_retention_period(options.retentionperiod)
        if options.delaysec is not None:
            queue_meta.set_delay_seconds(options.delaysec)
        if options.waitsec is not None:
            queue_meta.set_polling_wait_seconds(options.waitsec)
        return queue_meta

    @staticmethod
    def cmd_succeed(action, otherinfo=""):
        print "%s succeed!\n%s" % (action, otherinfo)

    @staticmethod
    def cmd_exception(action, e):
        print "%s fail!\nException:%s" % (action, e)

    @staticmethod
    def print_attr(attrMap):
        print "\n".join(["%s:%s" % (k.ljust(30),v) for k,v in attrMap.items()])

def print_help(key = None):
    print "==============================================="
    if key is None:
        print "mnscmd:\n"
        print "\n".join(["%s %s" % (k.ljust(20),v) for k,v in CMD_RULES.items()])
    else:
        print "%s helpinfo:\n%s" % (key, CMD_RULES[key])
    print "\n==============================================="
    sys.exit(1)

if __name__ == "__main__":
    parser = OptionParser('''%prog args [options]''')
    parser.add_option("-e", "--endpoint", dest="endpoint", help="specify mns endpoint, such as: mns.cn-hangzhou.aliyuncs.com")
    parser.add_option("-a", "--accesskeyid", dest="accesskeyid", help="specify your AccessKeyId")
    parser.add_option("-A", "--accesskeysecret", dest="accesskeysecret", help="specify your AccessKeySecret")
    parser.add_option("-p", "--prefix", dest="prefix", help="specify the prefix of queue name")
    parser.add_option("-r", "--retnum", type="int", dest="retnum", help="specify the retnum")
    parser.add_option("-m", "--marker", dest="marker", help="specify the marker")
    parser.add_option("-q", "--queuename", dest="queuename", help="specify queue name")
    parser.add_option("-v", "--vistimeout", type="int", dest="vistimeout", help="specify VisibilityTimeout")
    parser.add_option("-M", "--maxmsgsize", type="int", dest="maxmsgsize", help="specify MaximumMessageSize")
    parser.add_option("-R", "--retentionperiod", type="int", dest="retentionperiod", help="specify MessageRetentionPeriod")
    parser.add_option("-d", "--delaysec", type="int", dest="delaysec", help="specify DelaySeconds")
    parser.add_option("-b", "--body", dest="body", help="specify MessageBody")
    parser.add_option("-P", "--priority", type="int", dest="priority", help="specify Priority")
    parser.add_option("-w", "--waitsec", type="int", dest="waitsec", help="specify WaitSeconds")
    parser.add_option("-H", "--handle", dest="handle", help="specify ReceiptHandle")
    parser.add_option("-i", "--info", action="store_true", dest="info", help="get more information of an action")

    (options, args) = parser.parse_args()
    if (len(args)) < 1:
        print_help()

    mns_cmd = MNSCmd()
    if args[0] == "config":
        getattr(mns_cmd, args[0])(args, options)
        sys.exit(0)
    else:
        mns_cmd.setup_credentials()

    if args[0] not in CMD_RULES.keys():
        print "unsupported command : %s" % args[0]
        print "use --help for more information"
        sys.exit(1)

    if options.info:
        print_help(args[0])

    getattr(mns_cmd, args[0])(args, options)
