import string
import time
import libxml2
import libxslt
import jon.cgi as cgi
import jon.modpy as modpy
import Handler
import os
from Handler import PATH_XML_DOCS
from Handler import PATH_XSL_DOCS
from Handler import PATH_ASI_PROC
from Handler import REFRESH_MESSAGE

AUTO_PID = '0'
DROP_PID = '1FFF'
MAKE_DIFF = False


def debug(req, msg):
    DEBUG = 0
    if DEBUG:
        req.error(msg)

class IptvHandler(Handler.Handler):

    _adminPage = 'ip_destinations.xsl'
    _roPage = 'roip_destinations.xsl'


    def updateRoute(self,req):
        """ Update route handler.  Really just deletes and then adds route. """
        if self.deleteRoute(req):
            if self.addRoute(req):
                return True
            else:
                return False 
        else:
            return False

    def deleteRoute(self, req):
        """ Delete route handler."""
        debug(req, "Deleting route")
        try:
            # get a list of matching nodes.
            nodes = self.getNodes(req.params['destipaddr'], req.params['destport'])
            for node in nodes:
                node.unlinkNode()
                node.freeNode()
                debug(req, "deleted node %s:%s" % (req.params['destipaddr'], req.params['destport']))
#            try:
#                self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
#                self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
#                return True
#            except:
#                debug(req, "save error")
#                return False
        except:
            debug(req,"Delete Node error")
            return False
        return True
        

    def getNodes(self, dest_ip, dest_port):
        """Returns a list of nodes that match the destination IP and port"""
        try:
            return self._muxconfig.xpathEval2("/configuration/iptv/iptv_destination[dest_ip_addr='%s' and dest_port='%s']" % (dest_ip, dest_port))
        except:
            return None
         

    def getFirstNode(self, dest_ip, dest_port):
        try:
            return self.getNodes(req, dest_ip, dest_port)[0]
            #if nodes != None:
            #    return self.getNodes(req, dest_ip, dest_port)[0]
            #else:
            #    return None
        except:
            return None


    def addNitSection(self, req, ipnode):
        """ Adds nit section to the node. """
        debug(req, "Handling Nit Section")
        try:
            nit = ipnode.newChild(None, "nit", None)
            if req.params.has_key("active_table"): 
                if req.params['active_table'] == 'MPEG':
                    nit.newChild(None, "enable", "No")
                    # should also set atsc enable to no
                elif req.params['active_table'] == 'DVB':
                    debug(req, "adding nit/enable yes")
                    nit.newChild(None, "enable", "Yes")
                elif req.params['active_table'] == 'ATSC':
                    nit.newChild(None, "enable", "No")
                    # eventually, set atsc/enable to yes
                elif req.params['active_table'] == 'All':
                    nit.newChild(None, "enable", "Yes")
                    # eventually, set atsc/enable to yes
                    
#            if req.params.has_key("nitenable"):
#                nit.newChild(None, "enable", "Yes")
#            else:
#                nit.newChild(None, "enable", "No")
                
            ts_id = 0
            nit_network_name = "Adtec Digital"
            symbol_rate = 5056900
            nit_network_id = 0
            nit_orig_network_id = 0
            rate = 0
            frequency = 261000000
                
            if req.params.has_key("tsid"):
                ts_id = req.params['tsid']
                debug(req, str(ts_id))
            if req.params.has_key("nit_network_name"):
                nit_network_name = req.params['nit_network_name']
            if req.params.has_key("symbol_rate"):
                symbol_rate = req.params['symbol_rate']
            if req.params.has_key("nit_network_id"):
                nit_network_id = req.params['nit_network_id']
            if req.params.has_key("nit_orig_network_id"):
                nit_orig_network_id = req.params['nit_orig_network_id']
            if req.params.has_key("rate"):
                rate = req.params['rate']
            if req.params.has_key("frequency"):
                frequency = req.params['frequency']
                                
            nRate = nit.newChild(None, "rate", rate)
            nRate.newProp("base", "10")
            nit.newChild(None, "network_name", nit_network_name)
            nit.newChild(None, "network_id", nit_network_id)
            nit.newChild(None, "original_network_id", nit_orig_network_id)
            nTs = nit.newChild(None, "transport_stream", None)
            nTs.newProp("index", "1")
            nTs.newProp("enabled", "Yes")
            nTs.newProp("id", str(ts_id))
            nFreq = nTs.newChild(None, "frequency", frequency)
            nFreq.newProp("base", "10")
            nSymRate = nTs.newChild(None, "symbol_rate", symbol_rate)
            nSymRate.newProp("base", "10")
            
            if req.params.has_key("delivery_descriptor"):
                nTs.newChild(None, "delivery_descriptor", req.params['delivery_descriptor'])
            if req.params.has_key("modulation_type"):
                nTs.newChild(None, "modulation_type", req.params['modulation_type'])
            if req.params.has_key("polarization"):
                nTs.newChild(None, "polarization", req.params['polarization'])
            if req.params.has_key("east_west"):
                nTs.newChild(None, "east_west", req.params['east_west'])
            if req.params.has_key("orbital_position"):
                norbital_position = nTs.newChild(None, "orbital_position", req.params['orbital_position'])
                norbital_position.newProp("base", "10")
            if req.params.has_key("center_frequency"):
                ncenter_frequency = nTs.newChild(None, "center_frequency", req.params['center_frequency'])
                ncenter_frequency.newProp("base", "10")
            if req.params.has_key("bandwidth"):
                nTs.newChild(None, "bandwidth", req.params['bandwidth'])
            if req.params.has_key("constellation"):
                nTs.newChild(None, "constellation", req.params['constellation'])
            if req.params.has_key("hierarchy_information"):
                nTs.newChild(None, "hierarchy_information", req.params['hierarchy_information'])
            if req.params.has_key("code_rate_HP_stream"):
                nTs.newChild(None, "code_rate_HP_stream", req.params['code_rate_HP_stream'])
            if req.params.has_key("code_rate_LP_stream"):
                nTs.newChild(None, "code_rate_LP_stream", req.params['code_rate_LP_stream'])
            if req.params.has_key("guard_interval"):
                nTs.newChild(None, "guard_interval", req.params['guard_interval'])
            if req.params.has_key("transmission_mode"):
                nTs.newChild(None, "transmission_mode", req.params['transmission_mode'])
            if req.params.has_key("other_frequency_flag"):
                nTs.newChild(None, "other_frequency_flag", req.params['other_frequency_flag'])
                
            
        except Exception, e:
            debug(req, "exception: " + str(e))
            return False
        return True        
    
    
    def addCommonSection(self, req, node):
        """ Handles the common section for an IPTV destination"""
        debug(req, "Common section")
        try:
            dest_ip_addr = req.params['dest_ip_addr']
            dest_port = req.params['dest_port']     
            src_port = req.params['src_port']     
            network_if = req.params['network_if']
            if req.params.has_key('opt_ip_ttl'):
                opt_ip_ttl = req.params['opt_ip_ttl'] 
            else:
                opt_ip_ttl = '1'
            
            
            if req.params.has_key("name"):
                name = req.params["name"]
            else:
                name = ""
            framing_mode = req.params['framing_mode']     
            modulation_target = req.params['modulation_target']
            constant_bit_rate = req.params['constant_bit_rate']
            pat_rate = req.params['pat_rate'] 
            enable_rtp = req.params['enable_rtp']
            ipd = node.newChild(None, "iptv_destination", None)
            if req.params.has_key("dest_enable"):
                ipd.newProp("state", req.params['dest_enable'])
#            if req.params.has_key("dest_enable"):
#                ipd.newProp("state", "Enabled")
#            else:
#                ipd.newProp("state", "Disabled")
        
            ipd.newChild(None, "dest_ip_addr", dest_ip_addr)
            ipd.newChild(None, "dest_port", dest_port)
            ipd.newChild(None, "src_port", src_port)
            ipd.newChild(None, "name", name)
            ipd.newChild(None, "opt_ip_ttl", opt_ip_ttl)
            ipd.newChild(None, "framing_mode", framing_mode)
            ipd.newChild(None, "modulation_target", modulation_target)
            ipd.newChild(None, "constant_bit_rate", constant_bit_rate)
            ipd.newChild(None, "network_if", network_if)
            ipd.newChild(None, "enable_rtp", enable_rtp)
            ipd.newChild(None, "pat_rate", pat_rate)
            debug(req, "Common params set")
        except:
            return None
        return ipd   
    
    
    def addProgramSection(self, req, node):
        """ Adds the Program section of an IPTV destination."""
        debug(req, "Handling Program Section")
        programs_node = node.newChild(None, "programs", None)
        try:
            if req.params.has_key("dest*"):
                debug(req, "Found dest section")
                dest = req.params["dest*"]
                for item in dest:
                    debug(req, "making new dest ")
                    pr_node = programs_node.newChild(None, "program_reference", None)
                    pr_node.newProp("enable", "true")
                    sp_node = pr_node.newChild(None, "source_port", item.split(",")[0])
                    sp_node.newProp("base", "10")
                    pn_node = pr_node.newChild(None, "source_program_number", item.split(",")[1])
                    pn_node.newProp("base", "10")
        except:
            return False
        return True
    
    
    def addRoute(self, req):
        """Adds new route """
        debug(req, "Adding route")
        # get all previously known programs
        for key in req.params:
            if key[:len('xpath:')] == 'xpath:':
                self.parseKnownPrograms(req, key)
        # test if it exists
        try:
            node = self._muxconfig.xpathEval2("/configuration/iptv")[0]
        except:
            debug(req, "unable to attain node")
            return None
        ipDestNode = self.addCommonSection(req, node)
        if ipDestNode == None:
            debug(req, "Unable to set common section")
            return None
        if not self.addProgramSection(req, ipDestNode):
            debug(req, "Problem adding program section")
            return None
        active_table = req.params['active_table']
        debug(req, active_table)
        if active_table=='DVB':
            debug(req, "Found DVB section")
        if not self.addNitSection(req, ipDestNode):
            debug(req, "Problem adding NIT section")
            return None
        else:
            debug(req, "Nit section set")
        # elif active_table=='next':
            #    do def        
        for key in req.params:
            if key[:len('xpath:')] == 'xpath:':
                self.setParam(req, key, ipDestNode)
       
        debug(req, "Active Table set")
        return True    
#        try:
#            debug (req, "saving cfg")
#            self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
#            self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
#            return None
#        except:
#            debug(req, "add error5")
#            return None

    def makeDiff(self, req, wefref, asi_file, diff_folder):
        """ makes a simple os exec call to dm to diff the files into a third diff file"""
        debug(req, "making diff")
        diff_name = diff_folder + 'webref.diff.' + str(int(time.time()))
        debug(req, diff_name)
        cmd = "/usr/local/bin/dm " + wefref + " " + asi_file + " > " + diff_name
        debug(req, cmd)
        os.system("/usr/local/bin/dm " + wefref + " " + asi_file + " > " + diff_name)

    def parseKnownPrograms(self, req, key):
        self.knownPrograms = {}
        debug(req, "parseKnownPrograms: key %s" % key)
        temp = key[len('xpath:'):].split('?')
        xpath = temp[0]
        if len(temp) == 2:
            args = temp[1].split('^')
            for nvstr in args:
                nv = nvstr.split('=')
                self.knownPrograms[(nv[0], nv[1])] = "known"

    # Copied from advca.py
    def setParam(self, req, key, ipd):
        nvDict = {}
        debug(req, "setParam: key %s" % key)
        temp = key[len('xpath:'):].split('?')
        xpath = temp[0]
        if len(temp) == 2:
            args = temp[1].split('^')
            for nvstr in args:
                nv = nvstr.split('=')
                nvDict[nv[0]] = nv[1]
            #for k, v in nvDict.items():
            #    self.htmlComment(req, 'arg %s has value %s' % (k, v))
        val = req.params[key]

        nodes = ipd.xpathEval2(xpath);
        debug(req, "setParam: xpath %s found %d nodes" % (xpath, len(nodes)))
        for n in nodes:
            debug(req, "setParam: trying %s" % n.content)
            if n.xpathEval2("../../../../source_program_number")[0].content == nvDict["source_program_number"] and n.xpathEval2("../../../../source_port")[0].content == nvDict["source_port"]:
                debug(req, "setParam: setting %s" % val)
                n.setContent(val)
        #if len(nodes) == 1:
        #    nodes[0].setContent(val)
        #elif nvDict.has_key('create') and nvDict['create'] == '1':
        #    #self.htmlComment(req, 'creating %s, %s (%g)' % (xpath, val, time.time() - ts))
        #    nodes = [self.xpathCreate(xpath)]
        #    if len(nodes) >= 1:
        #        nodes[0].setContent(val)
        ##elif create:
        ##    nodes = [self.createXpath(req, xpath)]
        ##    if len(nodes) >= 1:
        ##        nodes[0].setContent(req.params[key])
        #else:
        #    req.error('xpath does not exist: %s\n' % (xpath))
 
    # framework "virtual" method
    def apply(self, req):
        for (key, val) in req.params.items():
            debug(req, '%s=%s\n' % (key, val))
        if req.params['function'] == 'add':
            if len(self.getNodes(req.params['dest_ip_addr'], req.params['dest_port'])) >0:
                debug(req, "**conflict**")
                self._message = "Add failed.  Check for IP and port conflict."
                self.view(req)
                return None
            elif not self.addRoute(req):
                self._message = "Add failed. Unknown reason."
                self.view(req)
                return None    
        elif req.params['function'] == 'edit':
            # need to data validate the following
#            if req.params.has_key('destipaddr'):
#                if req.params.has_key('destport'): 
            if not self.updateRoute(req):
                self._message = "Update failed."
                self.view(req)
                return None
        elif req.params['function'] == 'delete':
            if not self.deleteRoute(req):
                self._message = "Delete failed."
                self.view(req)
                return None
        elif req.params['function'] == 'globaledit':
            for node in self._muxconfig.xpathEval2('/configuration/iptv/global_settings/base_dest_ip_addr'):
                node.setContent(req.params['basedestipaddr'])
        #self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
        #self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
            for node in self._muxconfig.xpathEval2('/configuration/iptv/global_settings/default_dest_port'):
                node.setContent(req.params['defaultdestport'])
            for node in self._muxconfig.xpathEval2('/configuration/iptv/global_settings/default_src_port'):
                node.setContent(req.params['defaultsrcport'])
        #self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
        #self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
            for node in self._muxconfig.xpathEval2('/configuration/iptv/global_settings/default_opt_ip_ttl'):
                node.setContent(req.params['defaultoptipttl'])
            self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
            self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
            self._message = REFRESH_MESSAGE
            self.view(req)
            return None
        else:
            debug(req, "malformed post3")  
            self._message = "Missing Add, Edit or Delete."
            self.view(req)
            return None

        try:
            self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
            if MAKE_DIFF:
                try:
                    self.makeDiff(req, PATH_XML_DOCS + self._configFile, PATH_XML_DOCS + 'webref.xml', PATH_XML_DOCS)
                except:
                    pass
            self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
        except:
            self._message = "Failed to save file."
            self.view(req)
            debug(req, "save error")
            return None
        debug(req, "Files saved")
        self._message = REFRESH_MESSAGE
        self.view(req)
        return None


def handler(modpy_request):
    return modpy.Request(IptvHandler).process(modpy_request)
