{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Command Pattern\n",
    "1. Behavioral Pattern\n",
    "1. Used In - Toolkits, CLI, GUI\n",
    "1. Also known as - Action Pattern, Transaction Pattern\n",
    "1. Combines Diverse Request Processing Objects into a common structure\n",
    "\n",
    "> **Purpose**\n",
    "> - Encapsulates request as an object\n",
    "> - Parameterize various objects\n",
    "> - Supports Queues and Logs\n",
    "> - Undoable Operations and Macros(Sequences of Commands)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Command Line Order Processing\n",
    "1. Parse the command line arguments\n",
    "1. Execute the command\n",
    "1. Notify the user and log them\n",
    "1. Encapsulate the commands\n",
    "1. Info is hidden\n",
    "\n",
    "> **Expandable Command Sets**\n",
    "> 1. Create Order\n",
    "> 1. Update Quantity\n",
    "> 1. Ship Order"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from abc import ABCMeta, abstractmethod, abstractproperty"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Interfaces"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ICommand(metaclass=ABCMeta):\n",
    "    @abstractmethod\n",
    "    def execute(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class IOrder(metaclass=ABCMeta):\n",
    "    @abstractproperty\n",
    "    def name(self):\n",
    "        pass\n",
    "    \n",
    "    @abstractproperty\n",
    "    def description(self):\n",
    "        pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Commands"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class CreateOrder(ICommand, IOrder):\n",
    "    name = '--create-order'\n",
    "    description = 'Create Order'\n",
    "    \n",
    "    def __init__(self, args):\n",
    "        pass\n",
    "        \n",
    "    def execute(self):\n",
    "        print(\"Created Order\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class UpdateOrder(ICommand, IOrder):\n",
    "    name = '--update-quantity'\n",
    "    description = 'Update Quantity <number>'\n",
    "    \n",
    "    def __init__(self, args):\n",
    "        self.newqty = args[1]\n",
    "        \n",
    "    def execute(self):\n",
    "        oldqty = 5\n",
    "        \n",
    "        print(\"Updated Database\")\n",
    "        \n",
    "        print(f\"Logging: Updated quantity from {oldqty} to {self.newqty}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class ShipOrder(ICommand, IOrder):\n",
    "    name = '--ship-order'\n",
    "    description = 'Ship Order'\n",
    "    \n",
    "    def __init__(self, args):\n",
    "        pass\n",
    "        \n",
    "    def execute(self):\n",
    "        print(\"Shipped Order\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Null Pattern"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "class NoCommand(ICommand):\n",
    "    def __init__(self, args):\n",
    "        self._command = args[0]\n",
    "        pass\n",
    "    \n",
    "    def execute(self):\n",
    "        print(f'No command named {self._command}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Driver Program"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def get_commands():\n",
    "    commands = (CreateOrder, UpdateOrder, ShipOrder)\n",
    "    return dict([cls.name, cls] for cls in commands)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def print_usage(commands):\n",
    "    print('Usage: python amazon --command-name [arguments]')\n",
    "    print('\\nCommands:')\n",
    "    \n",
    "    for command in commands.values():\n",
    "        print(f'{command.name}: {command.description}')\n",
    "        \n",
    "    print('\\n')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def parse_commands(commands, args):\n",
    "    command = commands.get(args[0], NoCommand)\n",
    "    return command(args)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "def executioner(argv):\n",
    "    if len(argv) < 2:\n",
    "        print_usage(commands)\n",
    "    else:\n",
    "        command = parse_commands(commands, argv[1:])\n",
    "        command.execute()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "argv = ['amazon']\n",
    "argvA = ['amazon', '--create-order']\n",
    "argvB = ['amazon', '--update-quantity', '3']\n",
    "argvC = ['amazon', '--ship-order']\n",
    "argvD = ['amazon', '--delete-order']"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Usage: python amazon --command-name [arguments]\n",
      "\n",
      "Commands:\n",
      "--create-order: Create Order\n",
      "--update-quantity: Update Quantity <number>\n",
      "--ship-order: Ship Order\n",
      "\n",
      "\n",
      "Created Order\n",
      "\n",
      "Updated Database\n",
      "Logging: Updated quantity from 5 to 3\n",
      "\n",
      "Shipped Order\n",
      "\n",
      "No command named --delete-order\n"
     ]
    }
   ],
   "source": [
    "commands = get_commands()\n",
    "\n",
    "executioner(argv)\n",
    "executioner(argvA)\n",
    "executioner(argvB)\n",
    "executioner(argvC)\n",
    "executioner(argvD)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}