import httplib, urllib, json

class FlowMod(object):
    
    attr_names = [
        'switch',
        'name',
        'priority',
        'active',
        'cookie',
        'wildcards',
        'ingress-port',
        'vlan-id',
        'vlan-priority',
        'src-mac',
        'dst-mac',
        'ether-type',
        'protocol',
        'tos-bits',
        'src-ip',
        'dst-ip',
        'src-port',
        'dst-port',
        'actions',
    ]

    def __init__(self, dpid, name):
        self.attr = {}
        self.attr['switch'] = dpid
        self.attr['name'] = name
        self.attr['active'] = "true"
        self.attr['priority'] = "32768"
        self.attr['wildcards'] = "0"
        self.attr['cookie'] = "0"

    def __getattr__(self, name):
        namep = name.replace('_','-')
        def fn(val=None):
            if val:
                if namep == 'actions' and namep in self.attr:
                    self.attr[namep] = self.attr[namep] + ',' + str(val)
                else:
                    self.attr[namep] = str(val)
                return self
            else:
                if namep in self.attr:
                    self.attr[namep]
                else:
                    return None

        if namep in self.attr_names:
            return fn
        raise AttributeError(name)

    def output(self, val=None):
        if val: val='output=' + str(val)
        return self.actions(val)

    def push(self, server='localhost', port=8080, path='/wm/staticflowentry/pushentry.do'):
        path = '%s' % (path, )
        headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
        body = urllib.urlencode({'postBody': json.dumps(self.attr)})
        return self._push(server, port, path, 'POST', headers, body)

    def _push(self, server, port, path, action, headers, body):
        conn = httplib.HTTPConnection(server, port)
        conn.request(action, path, body, headers)
        response = conn.getresponse()
        ret = (response.status, response.reason, response.read())
        conn.close()
        return ret

    def json(self):
        return json.dumps([self.attr])
        
    def __str__(self):
        names_inorder = filter(lambda x: x in self.attr, self.attr_names)    
        attr_inorder = zip(names_inorder,  map(self.attr.pop, names_inorder))
        return 'FlowMod: ' + ', '.join(map(lambda x: '='.join(map(str, x)), attr_inorder))

if __name__ == '__main__':
    fm = FlowMod('00:00:00:00:00:00:00:01', 'flow-mod-1')\
            .src_mac('0e:cd:01:12:ff:de')\
            .dst_mac('d6:45:5d:b9:bb:a6')\
            .active('false')

    print fm.json()
    print fm.push()
