import sys
import sre
import types
import xmlrpclib
from py_dag_config_api import *
from py_dag_cat_api import *

class Error(Exception):
    def __init__(self, msg):
        self.msg = msg



class ConfigAPIRedirect(object):
    #used to redirect config API function calls locally or to the remote server
    def __init__(self, host = "localhost", port = "1415"):
        self.__host = host
        self.__port = port
        self.__fullname = "http://" + host + ":" + port
    
    def open_card(self, path):
        if self.__host == "localhost":
            return dag_config_init(path)
        else:
            server = xmlrpclib.ServerProxy(self.__fullname)
            return server.open_card(path)

    def close_card(self, card_ref):
        if card_ref:
            if self.__host == "localhost":
                dag_config_dispose(card_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                server.close_card(card_ref)

    def get_card_type(self, card_ref):
        if card_ref:
            if self.__host == "localhost":
                return dag_config_get_card_type(card_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_card_type(card_ref)

    def get_attribute_valuetype(self, card_ref, attribute_ref):
        if card_ref and attribute_ref:
            if self.__host == "localhost":
                return dag_config_get_attribute_valuetype(card_ref, attribute_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_attribute_valuetype(card_ref, attribute_ref)

    def get_root_component(self, card_ref):
        if card_ref:
            if self.__host == "localhost":
                return dag_config_get_root_component(card_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_root_component(card_ref)

    def get_subcomponent_count(self, comp_ref):
        if comp_ref:
            if self.__host == "localhost":
                return dag_component_get_subcomponent_count(comp_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_subcomponent_count(comp_ref)
        return 0

    def get_indexed_subcomponent(self, comp_ref, index):
        if comp_ref:
            if self.__host == "localhost":
                return dag_component_get_indexed_subcomponent(comp_ref, index)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_indexed_subcomponent(comp_ref, index)
    
    def get_component_code(self, comp_ref):
        if comp_ref:
            if self.__host == "localhost":
                return dag_config_get_component_code(comp_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_component_code(comp_ref)

    def get_indexed_attribute(self, comp_ref, index):
        if comp_ref:
            if self.__host == "localhost":
                return dag_component_get_indexed_attribute_uuid(comp_ref, index)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_indexed_attribute(comp_ref, index)

    def get_attribute_name(self, attr_ref):
        if attr_ref:
            if self.__host == "localhost":
                return dag_config_get_attribute_name(attr_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_attribute_name(attr_ref)

    def get_attribute_description(self, attr_ref):
        if attr_ref:
            if self.__host == "localhost":
                return dag_config_get_attribute_description(attr_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_attribute_description(attr_ref)

    def get_component_description(self, comp_ref):
        if comp_ref:
            if self.__host == "localhost":
                return dag_config_get_component_description(comp_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_component_description(comp_ref)

    def get_component_name(self, comp_ref):
        if comp_ref:
            if self.__host == "localhost":
                return dag_config_get_component_name(comp_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_component_name(comp_ref)

    def get_subcomponent_count_of_type(self, comp_ref, code):
        if comp_ref:
            if self.__host == "localhost":
                return dag_component_get_subcomponent_count_of_type(comp_ref, code)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_subcomponent_count_of_type(comp_ref, code)

    def get_attribute_count(self, comp_ref):
        if comp_ref:
            if self.__host == "localhost":
                return dag_component_get_attribute_count(comp_ref)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_attribute_count(comp_ref)

    def set_string(self, attr, s):
        if attr:
            if self.__host == "localhost":
                return dag_config_set_attribute_from_string(attr.get_card_ref(), attr.get_ref(), s)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                server.set_attribute_string(attr, s)
#cat component start
    def cat_set_entry(self,component_t,interface,color,hlb,destination):
    	if component_t:
		if self.__host == "localhost":
			return cat_set_entry(component_t,interface,color,hlb,destination)
		else:
		        server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_set_entry(component_t,interface,color,hlb,destination)

    def cat_set_entry_verify(self,component_t,interface,color,hlb,destination):
    	if component_t:
		if self.__host == "localhost":
			return cat_set_entry_verify(component_t,interface,color,hlb,destination)
		else:
		        server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_set_entry_verify(component_t,interface,color,hlb,destination)



    def cat_set_raw_entry(self,component_t,address,destination):
    	if component_t:
		if self.__host == "localhost":
			return cat_set_raw_entry(component_t,address,destination)
		else:
		        server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_set_raw_entry(component_t,address,destination)

    def cat_set_raw_entry_verify(self,component_t,address,destination):
    	if component_t:
		if self.__host == "localhost":
			return cat_set_raw_entry_verify(component_t,address,destination)
		else:
		        server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_set_raw_entry_verify(component_t,address,destination)


    def cat_get_raw_entry(self,component_t,bank,destination):
    	if component_t:
		if self.__host == "localhost":
			return cat_get_raw_entry(component_t,bank,destination)
		else:
		        server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_raw_entry(component_t,bank,destination)


    def cat_get_entry(self,component_t,interface,color,hlb,bank):
    	if component_t:
		if self.__host == "localhost":
			return cat_get_entry(component_t,interface,color,hlb,bank)
		else:
		        server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_entry(component_t,interface,color,hlb,bank)


    def cat_get_current_bank(self,component_t):
    	if component_t:
		if self.__host == "localhost":
			return cat_get_current_bank(component_t)
		else:
			sever = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_current_bank(component_t)


    def cat_swap_banks(self,component_t):
	if component_t:
	    if self.__host == "localhost":
			return cat_swap_banks(component_t)
	    else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_swap_banks(component_t)
		

    def cat_get_no_of_output_bits(self,component_t):
	if component_t:
		if self.__host == "localhost":
		    return cat_get_no_of_output_bits(component_t)
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_no_of_output_bits(component_t)

  
    def cat_get_no_of_input_bits(self,component_t):
       if component_t:
		if self.__host == "localhost":
			return cat_get_no_of_input_bits(component_t)
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_no_of_input_bits(component_t)

    def cat_get_max_hlb_or_hash(self):
   		if self.__host == "localhost":
			return cat_get_max_hlb_or_hash()
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_max_hlb_or_hash()

    def cat_get_max_interface(self,component_t):
  	if component_t:	
		if self.__host == "localhost":
			return cat_get_max_interface(component_t)
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_max_interface(component_t)

    def cat_get_max_color(self,component_t):
 	if component_t:
		if self.__host == "localhost":
			return cat_get_max_color(component_t)
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_max_color(comoponent_t)

    def cat_get_entry_mode(self):
  		if self.__host == "localhost":
			return cat_get_entry_mode()
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_get_entry_mode()

    def cat_set_entry_mode(self,mode):
  		if self.__host == "localhost":
			return cat_set_entry_mode(mode)
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_set_entry_mode(mode)

    def cat_bypass(self,component_t):
 		if self.__host == "localhost":
			return cat_bypass(component_t)
		else:
			server = xmlrpclib.ServerProxy(self.__fullname)
			return server.cat_bypass(component_t)
 #cat end

    def set_value(self, attr, v):
        if attr:
            if self.__host == "localhost":
                if (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeBoolean):
                    dag_config_set_boolean_attribute(attr.get_card_ref(), attr.get_ref(), v)
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeUint32):
                    dag_config_set_uint32_attribute(attr.get_card_ref(), attr.get_ref(), v)
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeInt32):
                    dag_config_set_int32_attribute(attr.get_card_ref(), attr.get_ref(), v)
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeInt64):
                    dag_config_set_int64_attribute(attr.get_card_ref(), attr.get_ref(), v)
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeUint64):
                    dag_config_set_uint64_attribute(attr.get_card_ref(), attr.get_ref(), v)
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                server.set_attribute_value(attr.get_card_ref(), attr.get_ref(), v)

    def get_string(self, attr):
        if attr:
            if self.__host == "localhost":
                return dag_config_get_attribute_to_string(attr.get_card_ref(), attr.get_ref())
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_attribute_string(attr.get_card_ref(), attr.get_ref())

    def get_value(self, attr):
        if attr:
            if self.__host == "localhost":
                value = None
                if (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeBoolean):
                    value = dag_config_get_boolean_attribute(attr.get_card_ref(), attr.get_ref())
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeUint32):
                    value = dag_config_get_uint32_attribute(attr.get_card_ref(), attr.get_ref())
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeInt32):
                    value = dag_config_get_int32_attribute(attr.get_card_ref(), attr.get_ref())
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeInt64):
                    value = dag_config_get_int64_attribute(attr.get_card_ref(), attr.get_ref())
                elif (dag_config_get_attribute_valuetype(attr.get_card_ref(), attr.get_ref()) == kAttributeUint64):
                    value = dag_config_get_uint64_attribute(attr.get_card_ref(), attr.get_ref())
                return value
            else:
                server = xmlrpclib.ServerProxy(self.__fullname)
                return server.get_attribute_value(attr.get_card_ref(), attr.get_ref())
        return 0

#
# Speed optimized remote python API for ConfigAPI
#
# Bundles all the card component attribute info into one message, since
# XML RPC seems to be *very* slow.
#
#
# Future: provide a method to request values for a set of attributes via one message exchange.


#from endace.ConfigAPI import *
def comp_instance(comp_name):
    '''return the numeric order for the component'''
    pattern = sre.compile("[0-9]+$")
    match = pattern.search(comp_name)
    if match == None:
        return 0
    return int(comp_name[match.span()[0]:])

def add_components(self, card_ref, server, compinfo):
    comps = compinfo.keys()
    # Sort the component keys by instance number
    # this makes sure they correspond to the actual instances
    comps.sort(key=comp_instance)

    for comp_name in comps:
        comp = compinfo[comp_name]
        #Use a list to store these
        #strip the index number by finding the digits at the end of the name
        pattern = sre.compile("[0-9]*$")
        match = pattern.search(comp_name)
        component_name = comp_name[0:match.span()[0]]
        try:
            list_comp = getattr(self, component_name)
        except AttributeError:
            #The component list doesn't exisit - create it
            setattr(self, component_name, list())
            list_comp = getattr(self, component_name)

        list_comp.append(RemoteDag.Component(comp['ref'], card_ref, server, comp))

class RemoteDag(object):
    class Attribute(object):
        def __init__(self, ref, card_ref, server, lastvalue):
            self.__ref = ref
            self.__card_ref = card_ref
            self.__server = server
            self.lastvalue = lastvalue
            #self.description = self.__redirect.get_attribute_description(self.__ref)

        def __get_value__(self):
            self.lastvalue = self.__server.get_attribute_value(self.__card_ref, self.__ref)
            return self.lastvalue
        
        def __set_value__(self, value):
            self.__server.set_attribute_value(self.__card_ref, self.__ref, value)
            self.lastvalue = value

        def __get_string__(self):
            return self.__server.get_attribute_string(self.__card_ref, self.__ref)
        
        def __set_string__(self, string):
            self.__server.set_attribute_string(self.__card_ref, self.__ref, string)

        value = property(__get_value__, __set_value__)
        string = property(__get_string__, __set_string__)

    class Component(object):
        def __init__(self, ref, card_ref, server, compinfo):
            self.__ref = ref             # component reference
            self.__card_ref = card_ref
            self.__server = server

            #add subcomponents
            add_components(self, self.__card_ref, server, compinfo['comps'])

            #add attributes of this component
            for attr_name in compinfo['attrs'].keys():
                setattr(self, attr_name, RemoteDag.Attribute(compinfo['attrs'][attr_name][0], card_ref, server, compinfo['attrs'][attr_name][2]))


    # Dag class methods here

    def __init__(self, path = "/dev/dag0", host = "localhost", port = "60110"):
        #we prefix these variables with an underscore to reduce the chance of them conflicting with a component
        #name from the underlying Config API.
        self.__host = host
        self.__port = port
        self.__fullname = "http://" + host + ":" + port
        self.__server = xmlrpclib.ServerProxy(self.__fullname)

        # open the card and grab back the tree of all components and attributes
        opsys = sys.platform.lower()
        if opsys == 'microsoft' or opsys == 'cygwin' or opsys == 'win32':
            try: # path might be less than 5 char ('dagx' instead of '/dev/dagx')
                if path[0:5].lower() == '/dev/':
                    path = path[5:]
            except:
                    pass
        info = self.__server.open_card_info(path)

        if info == 0 :
            #we couldn't connect
            raise Error('Can\'t connect')

        self.info = info
        self.__ref = info['card_ref']
        setattr(self, 'type', info['card_type'])

        # add all components and attributes
        add_components(self, self.__ref, self.__server, info['comps'])

    def __del__(self):
        self.__server.close_card(self.__ref)
     
class Attribute(object):
    def __init__(self, ref, card_ref, host = "localhost", port = "1415"):
        self.__ref = ref
        self.__card_ref = card_ref
        self.__redirect = ConfigAPIRedirect(host, port)
        self.description = self.__redirect.get_attribute_description(self.__ref)

    def get_ref(self):
        return self.__ref

    def get_card_ref(self):
        return self.__card_ref

    def __get_value__(self):
        return self.__redirect.get_value(self)
    
    def __set_value__(self, value):
        self.__redirect.set_value(self, value)

    def __get_string__(self):
        return self.__redirect.get_string(self)
    
    def __set_string__(self, string):
        self.__redirect.set_string(self, string)

    value = property(__get_value__, __set_value__)
    string = property(__get_string__, __set_string__)


class Component(object):
    def __init__(self, ref, card_ref, host = "localhost", port = "1415"):
        self.__ref = ref
        self.__card_ref = card_ref
        self.__redirect = ConfigAPIRedirect(host, port)
        self.description = self.__redirect.get_component_description(self.__ref)
        #add subcomponents
        comp_count = self.__redirect.get_subcomponent_count(self.__ref)
	comp_code = self.__redirect.get_component_code(self.__ref)
        #if comp_code == kComponentCAT:
        for i in range(comp_count):
            component = self.__redirect.get_indexed_subcomponent(self.__ref, i)
            comp_code = self.__redirect.get_component_code(component)
            component_name = self.__redirect.get_component_name(component)
            #Use a list to store these
            #strip the index number by finding the digits at the end of the name
            pattern = sre.compile("[0-9]*$")
            match = pattern.search(component_name)
            component_name = component_name[0:match.span()[0]]
            try:
                list_comp = getattr(self, component_name)
            except AttributeError:
                setattr(self, component_name, list())
                list_comp = getattr(self, component_name)
                list_comp.append(Component(component, self.__card_ref, host, port))
            else:
                #The list already exists so just append this component
                list_comp.append(Component(component, self.__card_ref, host, port))
        attribute_count = self.__redirect.get_attribute_count(self.__ref)
        for i in range(attribute_count):
            attr = self.__redirect.get_indexed_attribute(self.__ref, i)
            setattr(self, self.__redirect.get_attribute_name(attr), Attribute(attr, self.__card_ref, host, port))
    def cat_set_raw_entry(self,address,destination):
    	return self.__redirect.cat_set_raw_entry(self.__ref,address,destination)
    def cat_set_raw_entry_verify(self,address,destination):
    	return self.__redirect.cat_set_raw_entry_verify(self.__ref,address,destination)
    def cat_get_raw_entry(self,bank,address):
    	return self.__redirect.cat_get_raw_entry(self.__ref,bank,address)
    def cat_set_entry(self,interface,color,hlb,destination):
    	return self.__redirect.cat_set_entry(self.__ref,interface,color,hlb,destination)
    def cat_set_entry_verify(self,interface,color,hlb,destination):
    	return self.__redirect.cat_set_entry_verify(self.__ref,interface,color,hlb,destination)
    def cat_get_entry(self,interface,color,hlb,bank):
	return self.__redirect.cat_get_entry(self.__ref,interface,color,hlb,bank)
    def cat_get_current_bank(self):
	return self.__redirect.cat_get_current_bank(self.__ref)
    def cat_swap_banks(self):
        return self.__redirect.cat_swap_banks(self.__ref)
    def cat_get_no_of_output_bits(self):
    	return self.__redirect.cat_get_no_of_output_bits(self.__ref)
    def cat_get_no_of_input_bits(self):
    	return self.__redirect.cat_get_no_of_input_bits(self.__ref)
    def cat_get_max_hlb_or_hash(self):
    	return self.__redirect.cat_get_max_hlb_or_hash()
    def cat_get_max_interface(self):
    	return self.__redirect.cat_get_max_interface(self.__ref)
    def cat_get_max_color(self):
    	return self.__redirect.cat_get_max_color(self.__ref)
    def cat_get_entry_mode(self):
    	return self.__redirect.cat_get_entry_mode()         
    def cat_set_entry_mode(self,mode):
    	return self.__redirect.cat_set_entry_mode(mode)
    def cat_bypass(self):
    	return self.__redirect.cat_bypass(self.__ref)

class DAGCard(RemoteDag):
    def __init__(self, path = "/dev/dag0", host = "localhost", port = "1415"):
        #we prefix these variables with an underscore to reduce the chance of them conflicting with a component
        #name from the underlying Config API.
        opsys = sys.platform.lower()
        if opsys == 'microsoft' or opsys == 'cygwin' or opsys == 'win32':
            try: # path might be less than 5 char ('dagx' instead of '/dev/dagx')
                if path[0:5].lower() == '/dev/':
                    path = path[5:]
            except:
                    pass
        self.__path = path
        self.__host = host

        if host != "localhost":
            super(DAGCard, self).__init__(path,host,port)
        else:
            self.__redirect = ConfigAPIRedirect(host, port)
            self.__ref = self.__redirect.open_card(path)
            if self.__ref == 0 :
                #we couldn't connect
                raise Error('Can\'t connect')
            root = self.__redirect.get_root_component(self.__ref)
            comp_count = self.__redirect.get_subcomponent_count(root)
            setattr(self, 'type', self.__redirect.get_card_type(self.__ref))
            for i in range(comp_count):
                component = self.__redirect.get_indexed_subcomponent(root, i)
                comp_code = self.__redirect.get_component_code(component)
                component_name = self.__redirect.get_component_name(component)
                #Use a list to store these
                #strip the index number by finding the digits at the end of the name
                pattern = sre.compile("[0-9]*$")
                match = pattern.search(component_name)
                component_name = component_name[0:match.span()[0]]
                try:
                    list_comp = getattr(self, component_name)
                except AttributeError:
                    setattr(self, component_name, list())
                    list_comp = getattr(self, component_name)
                    list_comp.append(Component(component, self.__ref, host, port))
                else:
                    #The list already exists so just append this component
                    list_comp.append(Component(component, self.__ref, host, port))

    def __del__(self):
        if self.__host == "localhost":
            self.__redirect.close_card(self.__ref)
        else:
            super(DAGCard, self).__del__()

