import sys
import libxml2
import libxslt

import jon.cgi as cgi
import jon.modpy as modpy

import Handler
from Handler import PATH_XML_DOCS
from Handler import REFRESH_MESSAGE

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

class InputXHandler(Handler.Handler):
    _adminPage = 'inputx.xsl'
    _roPage = 'roinputs.xsl'
    
    def apply(self, req):        
        self._session.setPMTTracking(req.params["pmt_tracking"])
        inputIndex = req.params.get('inputEditIndex')
        try:
            add_list = []
            ghost_list = []
            ghost_remove_list = []
            svc_remove_list = []
            portModeDisabled = False
            # parse new items for new adds: program number, provider, name
            #debug(req, 'Parsing options\n')
            if req.params.has_key('current_programs*'):
                options = req.params['current_programs*']
            else:
                options = []
            for opt in options:
                if len(opt) == 0:
                    continue
                elif (opt.find('ghost://') == 0):
                    # create tuples with (index, pid_in, service, provider, name, [stream_type])
                    fields = opt.split('^')
                    ghostIdx = fields[0].split('=')[1]
                    if ghostIdx == '0':
                        ghostPidIn = fields[1].split('=')[1]
                        ghostService = fields[2].split('=')[1]
                        ghostProvider = fields[3].split('=')[1]
                        ghostName = fields[4].split('=')[1]
                        ghostStreamType = fields[5].split('=')[1]
                        debug(req, str((ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType))+'\n')
                        ghost_list.append((ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType))
                elif (opt.find('service://') == 0):
                    # create tuples with (index, pid_in, service, provider, name, [stream_type])
                    fields = opt.split('^')
                    svcIdx = fields[0].split('=')[1]
                    if svcIdx == inputIndex:#'1':
                        svcService = ''
                        svcServiceType = ''
                        svcPids = []
                        svcPMT = 'Disable'
                        for nvPair in fields[1:]:
                            fieldName, fieldValue = nvPair.split('=')
                            if fieldName == 'service':
                                svcService = fieldValue
                            elif fieldName == 'stype':
                                svcServiceType = fieldValue
                            elif fieldName == 'pid':
                                svcPids.append(fieldValue)
                            elif fieldName == 'pmt_dynamic_tracking_state':
                                svcPMT = fieldValue
                        #ghostPidIn = fields[1].split('=')[1]
                        svcService = fields[1].split('=')[1]
                        #svcProvider = fields[2].split('=')[1]
                        #svcName = fields[3].split('=')[1]
                        svcServiceType = fields[4].split('=')[1]
                        #svcStreamType = fields[5].split('=')[1]
                        #debug(req, str((svcIdx, svcService, svcProvider, svcName))+'\n')
                        debug(req, str((svcIdx, svcService, svcServiceType, svcPMT))+'\n')
                        add_list.append((svcIdx, svcService, svcServiceType, svcPids, svcPMT))
                else:
                    req.error('unregcognized option: %s' % (opt))
                #else:
                #    idx1 = opt.find(',')
                #    idx2 = opt.find(',', idx1+1)
                #    program_number = opt[:idx1]
                #    #print 'program_number =', program_number, '<br>'
                #    provider = opt[idx1+1:idx2]
                #    #print 'provider =', provider, '<br>'
                #    name = opt[idx2+1:]
                #    #print 'name =', name, '<br>'
                #    #  store options as tuples
                #    add_list.append((program_number, provider, name))
            if req.params.has_key('ghost_add*'):
                options = req.params['ghost_add*']
            else:
                debug(req, 'No ghost_add\n')
                options = []
            for opt in options:
                if (opt.find('ghost://') == 0):
                    # create tuples with (index, pid_in, service, provider, name, [stream_type])
                    fields = opt.split('^')
                    ghostIdx = fields[0].split('=')[1]
                    if ghostIdx == '0':
                        ghostPidIn = fields[1].split('=')[1]
                        ghostService = fields[2].split('=')[1]
                        ghostProvider = fields[3].split('=')[1]
                        ghostName = fields[4].split('=')[1]
                        ghostStreamType = fields[5].split('=')[1]
                        debug(req, str((ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType))+'\n')
                        ghost_list.append((ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType))

            if req.params.has_key('removed_ghost_services*'):
                options = req.params['removed_ghost_services*']
            else:
                debug(req, 'No removed_ghost_services\n')
                options = []
            for opt in options:
                debug(req, opt + '\n')
                if (opt.find('ghost://') == 0):
                    # create tuples with (index, pid_in, service, provider, name, [stream_type])
                    fields = opt.split('^')
                    ghostIdx = fields[0].split('=')[1]
                    if ghostIdx != '0':
                        ghostPidIn = fields[1].split('=')[1]
                        ghostService = fields[2].split('=')[1]
                        ghostProvider = fields[3].split('=')[1]
                        ghostName = fields[4].split('=')[1]
                        ghostStreamType = ''#fields[5].split('=')[1]
                        debug(req, str((ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType))+'\n')
                        ghost_remove_list.append((ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType))
                
            if req.params.has_key('removed_services*'):
                options = req.params['removed_services*']
            else:
                debug(req, 'No removed_services\n')
                options = []
            for opt in options:
                debug(req, opt + '\n')
                if (opt.find('service://') == 0):
                    # create tuples with (index, pid_in, service, provider, name, [stream_type])
                    fields = opt.split('^')
                    svcIdx = fields[0].split('=')[1]
                    if svcIdx == inputIndex:#'1':
                        svcService = ''
                        svcServiceType = ''
                        #svcPids = []
                        svcStatus = ''
                        for nvPair in fields[1:]:
                            fieldName, fieldValue = nvPair.split('=')
                            if fieldName == 'service':
                                svcService = fieldValue
                            elif fieldName == 'stype':
                                svcServiceType = fieldValue
                            #elif fieldName == 'pid':
                            #    svcPids.append(fieldValue)
                            elif fieldName == 'status':
                                svcStatus = fieldValue
                        #debug(req, str((svcIdx, svcService, svcProvider, svcName, svcServiceType))+'\n')
                        svc_remove_list.append((svcIdx, svcService, svcServiceType, svcStatus))
            # Handle Manual Add/Drop
            # remove manual services
            for item in svc_remove_list:
                svcIdx, svcService, svcStreamType, svcStatus = item
                debug(req, 'removing service (%s, %s)\n'% (svcIdx, svcService))
                svcNode = self._muxconfig.xpathEval2("/configuration/port[@index='%s']/manual_programs/add[@program_number_in='%s']" % (svcIdx, svcService))
                if len(svcNode) > 0:
                    #debug(req, 'removing service %s\n'% (svcService))
                    svcNode[0].unlinkNode()
                    svcNode[0].freeNode()
                if svcStatus == 'inactive':
                    nodeset = self._muxconfig.xpathEval2("/configuration/port[@index='%s']/program_remap/program[@program_number_in='%s']" % (svcIdx, svcService))
                    if len(nodeset) > 0:
                        #debug(req, 'removing ghost %s\n'% (ghostIdx))
                        nodeset[0].unlinkNode()
                        nodeset[0].freeNode()
                #svcNode = None
                #debug(req, 'removing ghost %s (completed)\n'% (ghostIdx))

            # ignore current programs if port(@index==n)/mode == 'Auto' or 'Disabled'
            # set content of mode to req.params['mode'].value
            ignore_current_programs = 0
            for port in self._muxconfig.xpathEval2('configuration/port'):
                if (port.prop('index') == inputIndex):#'1'):#req.params['port_index']):
                    if req.params.has_key('opmode'):
                        opmode = port.xpathEval2('opmode')[0]
                        # strcasecmp() might be a good idea
                        ignore_current_programs = ((opmode.content == 'Auto') or (opmode.content == 'Pass'))
                        opmode.setContent(req.params['opmode'])
                    if req.params.has_key('lband_frequency'):
                        lband_frequency = port.xpathEval2('tuner/lband_frequency')[0]
                        lband_frequency.setContent(req.params['lband_frequency'])
                    if req.params.has_key('symbol_rate'):
                        symbol_rate = port.xpathEval2('tuner/symbol_rate')[0]
                        symbol_rate.setContent(req.params['symbol_rate'])
                    if req.params.has_key('viterbi'):
                        viterbi = port.xpathEval2('tuner/viterbi')[0]
                        viterbi.setContent(req.params['viterbi'])
                    if req.params.has_key('polarity'):
                        polarity = port.xpathEval2('tuner/polarity')[0]
                        polarity.setContent(req.params['polarity'])
                    if req.params.has_key('tone_22KHz'):
                        tone_22KHz = port.xpathEval2('tuner/tone_22KHz')[0]
                        tone_22KHz.setContent(req.params['tone_22KHz'])
                    #if req.params.has_key('channel'):
                    #	channel = port.xpathEval2('tuner/channel')[0]
                    #	channel.setContent(req.params['channel'])
                    #if req.params.has_key('modulation'):
                    #	modulation = port.xpathEval2('tuner/modulation')[0]
                    #	modulation.setContent(req.params['modulation'])
                    
                    #
                    # Added fields for tunertype Terrestrial
                    #
                    if req.params.has_key('separation'):
                        separation = port.xpathEval2('tuner/separation')[0]
                        separation.setContent(req.params['separation'])
                    if req.params.has_key('channel'):
                        channel = port.xpathEval2('tuner/channel')[0]
                        channel.setContent(req.params['channel'])
                    if req.params.has_key('modulation'):
                        modulation = port.xpathEval2('tuner/modulation')[0]
                        modulation.setContent(req.params['modulation'])
                    if req.params.has_key('coderate'):
                        coderate = port.xpathEval2('tuner/coderate')[0]
                        coderate.setContent(req.params['coderate'])
                    if req.params.has_key('hierarchy'):
                        hierarchy = port.xpathEval2('tuner/hierarchy')[0]
                        hierarchy.setContent(req.params['hierarchy'])
                    if req.params.has_key('guard_interval'):
                        guard_interval = port.xpathEval2('tuner/guard_interval')[0]
                        guard_interval.setContent(req.params['guard_interval'])
                    if req.params.has_key('fftsize'):
                        fftsize = port.xpathEval2('tuner/fftsize')[0]
                        fftsize.setContent(req.params['fftsize'])
                    
                    if req.params.has_key('tabletype'):
                        tabletype = port.xpathEval2('tabletype')[0]
                        tabletype.setContent(req.params['tabletype'])
                    if req.params.has_key('port_state'):
                        portstate = port.xpathEval2('portstate')[0]
                        portstate.setContent(req.params['port_state'])
                        if portstate.content != 'Enabled':
                            portModeDisabled = True
                    if req.params.has_key('clsm_state'):
                        clsmstate = port.xpathEval2('clsmstate')[0]
                        clsmstate.setContent(req.params['clsm_state'])
                    if req.params.has_key('redundancy_group'):
                        redundancygroup = port.xpathEval2('redundancy/group')[0]
                        redundancygroup.setContent(req.params['redundancy_group'])
                    if req.params.has_key('redundancy_role'):
                        redundancyrole = port.xpathEval2('redundancy/role')[0]
                        redundancyrole.setContent(req.params['redundancy_role'])
                    if req.params.has_key('pass_inbound_ca'):
                        redundancyrole = port.xpathEval2('pass_inbound_ca')[0]
                        redundancyrole.setContent(req.params['pass_inbound_ca'])
                    #if req.params.has_key('clsm_group'):
                    #    clsm_group = port.xpathEval2('clsm/group')[0]
                    #    clsm_group.setContent(req.params['clsm_group'])
                    if req.params.has_key('clsm_encoder_inet_addr'):
                        encoder_inet_addr = port.xpathEval2('clsm/encoder_inet_addr')[0]
                        encoder_inet_addr.setContent(req.params['clsm_encoder_inet_addr'])
                    if req.params.has_key('clsm_max_rate_normal'):
                        clsm_normal = port.xpathEval2('clsm/max_rate_normal')
                        if len(clsm_normal) == 0:
                            debug(req, 'clsm/max_rate_normal does not exist\n');
                            #addEl = man_progs.newChild(None, 'add', None)
                        clsm_normal[0].setContent(req.params['clsm_max_rate_normal'])
                    if req.params.has_key('clsm_max_rate_curbed'):
                        clsm_curbed = port.xpathEval2('clsm/max_rate_curbed')
                        if len(clsm_curbed) == 0:
                            debug(req, 'clsm/max_rate_normal does not exist\n');
                        clsm_curbed[0].setContent(req.params['clsm_max_rate_curbed'])
                    if ((not portModeDisabled) 
                            and (ignore_current_programs == 0)):
                        ret = port.xpathEval2('manual_programs')
                        if len(ret) > 0:
                            man_progs = ret[0]
                        else:
                            man_progs = port.newChild(None, 'manual_programs', None)
                        ret = port.xpathEval2('program_remap')
                        if len(ret) > 0:
                            prog_remap = ret[0]
                        else:
                            prog_remap = port.newChild(None, 'program_remap', None)
                        # add new items as .../manual_programs/add
                        for item in add_list:
                            svcIdx, svcService, svcServiceType, svcPids, svcPMT = item
                            #temp = man_progs.newChild(None, 'add', None)
                            #temp.newProp('program_number_in', item[0])
                            debug(req, 'Attempting to locate existing add[@program_number_in=%s]\n' % (svcService))
                            nodeset = man_progs.xpathEval2("add[@program_number_in='%s']" % (svcService))
                            if len(nodeset) == 0:
                                addEl = man_progs.newChild(None, 'add', None)
                                addEl.newProp('program_number_in', svcService)
                            # JPT-DEV Also add program_remap??
                            debug(req, 'Attempting to locate existing program[@program_number_in=%s]\n' % (svcService))
                            nodeset = prog_remap.xpathEval2("program[@program_number_in='%s']" % (svcService))
                            if len(nodeset) > 0:
                                prog = ret[0]
                            else:
                                prog = prog_remap.newChild(None, 'program', None)
                                prog.newProp('program_number_in', svcService)
                            #nodeset = prog.xpathEval2('service_type_out')
                            #if len(nodeset) == 0:
                            #    stypeout = prog.newChild(None, 'service_type_out', None)
                            #    stypeout.setContent('Digital Television')
                            nodeset = prog.xpathEval2('scramble')
                            if len(nodeset) == 0:
                                scramble = prog.newChild(None, 'scramble', None)
                                scramble.setContent('No')
                            nodeset = prog.xpathEval2('service_type_out')
                            if len(nodeset) == 0:
                                stypeout = prog.newChild(None, 'service_type_out', None)
                                debug(req, 'Setting service type out: %s\n' % (svcServiceType))
                                stypeout.setContent(svcServiceType)
                            for pidCsv in svcPids:
                                pidFields = pidCsv.split(',')    # steam_type, pid_in [, lang_code]
                                try:
                                    debug(req, "Looking for pid_remap[pid_in='%s']\n" % (pidFields[1]))
                                    nodeset = prog.xpathEval2("pid_remap[pid_in='%s']" % (pidFields[1]))
                                    #nodeset = prog.xpathEval2('pid_remap/pid_in')# % (pidFields[1]))
                                    #if True: 
                                    if len(nodeset) == 0:
                                        pidRemap = prog.newChild(None, 'pid_remap', None)
                                        pidRemap.newChild(None, 'pid_in', pidFields[1])
                                        pidRemap.newChild(None, 'pid_out', '0000')
                                        pidRemap.newChild(None, 'stream_type', pidFields[0])
                                        if len(pidFields) > 2:
                                            pidRemap.newChild(None, 'language_code', pidFields[2])
                                except libxml2.xpathError:
                                    req.error("xpathError: pid_remap[pid_in='%s']\n" % (pidFields[1]))
                            nodeset = prog.xpathEval2('pmt_dynamic_tracking_state')
                            if len(nodeset) == 0:
                                pmtTracking = prog.newChild(None, 'pmt_dynamic_tracking_state', None)
                                pmtTracking.setContent(svcPMT)
                                debug(req, 'Setting PMT: %s\n' % svcPMT)
                        # JPTDEV Weird additional nodes seen, so remove them.
                        for node in prog_remap.xpathEval2('scramble'):
                            debug(req, 'Removing program_remap/scramble\n')
                            node.unlinkNode()
                            node.freeNode()    
                        for node in prog_remap.xpathEval2('service_type_out'):
                            debug(req, 'Removing program_remap/service_type_out\n')
                            node.unlinkNode()
                            node.freeNode()    
                        for node in prog_remap.xpathEval2('pid_remap'):
                            debug(req, 'Removing program_remap/pid_remap\n')
                            node.unlinkNode()
                            node.freeNode()    
                    # found the proper port, so stop searching
                    break
            if (not portModeDisabled):
                # remove ghost component
                # if only PMT component remains, remove ghost
                for item in ghost_remove_list:
                    ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType = item
                    debug(req, 'removing pid_remap (%s, %s, %s)\n'% (ghostIdx, ghostService, ghostPidIn))
                    #if ghostIdx == '0':
                    #    continue
                    ghostNode = self._muxconfig.xpathEval2("/configuration/ghost[@index='%s']" % (ghostIdx))
                    ghostPidRemaps = ghostNode[0].xpathEval2('program/pid_remap')
                    lenGhostPidRemaps = len(ghostPidRemaps)
                    foundPmt = 0
                    foundTargetPid = 0
                    for remap in ghostPidRemaps:
                        streamType = remap.xpathEval2('stream_type')
                        if (len(streamType) == 1 and streamType[0].content == 'PMT'):
                            foundPmt = 1
                            continue
                        sourcePort = remap.xpathEval2('source_port')
                        sourceProgramNumber = remap.xpathEval2('source_program_number')
                        sourcePid = remap.xpathEval2('pid_in')
                        #debug(req, 'removing pid_remap (%s, %s, %s)\n'% (ghostIdx, ghostService, ghostPidIn))
                        if (len(sourcePort) == 1 and inputIndex == sourcePort[0].content
                                and len(sourceProgramNumber) == 1 and ghostService == sourceProgramNumber[0].content
                                and len(sourcePid) == 1 and ghostPidIn == sourcePid[0].content):
                            debug(req, 'found pid_remap (%s, %s, %s)\n'% ('1', ghostService, ghostPidIn))
                            foundTargetPid = 1
                            remap.unlinkNode()
                            remap.freeNode()
                    if (lenGhostPidRemaps == 2
                            and foundPmt > 0
                            and foundTargetPid > 0):
                        debug(req, 'removing ghost %s\n'% (ghostIdx))
                        ghostNode[0].unlinkNode()
                        ghostNode[0].freeNode()
                        ghostNode = None
                        debug(req, 'removing ghost %s (completed)\n'% (ghostIdx))
                if len(ghost_list) > 0:
                    debug(req, 'Now adding ghost services\n')
                    for item in ghost_list: debug(req, str(item) + '\n')
                    # items should be used to create single ghost service rather than one ghost service for each item
                    ghostNodes = self._muxconfig.xpathEval2('/configuration/ghost')
                    #debug(req, 'len=' + str(len(ghostIndices))+'\n')
                    for i in range(1,128):
                        availableIndex = i
                        for node in ghostNodes:
                            debug(req, node.prop('index') + '\n')                        
                            if str(i) == node.prop('index'):
                                availableIndex = 0
                                break
                        if availableIndex:
                            break        
                    cfg = self._muxconfig.xpathEval2('configuration')[0]
                    ghost = cfg.newChild(None, 'ghost', None)
                    ghost.newProp('index', str(i))
                    prog = ghost.newChild(None, 'program', None)
                    node = prog.newChild(None, 'program_number_out', '0')
                    node.newProp('base', '10')
                    #prog.newChild(None, 'name_out', '%s-%s' % (ghostName, ghostPidIn))
                    prog.newChild(None, 'name_out', 'G%d' % (i))
                    #prog.newChild(None, 'provider_out', ghostProvider)
                    prog.newChild(None, 'service_type_out', 'Digital Radio Sound')
                    # mandatory PMT pid
                    pidRemap = prog.newChild(None, 'pid_remap', None)
                    node = pidRemap.newChild(None, 'source_port', '0')
                    node.newProp('base', '10')
                    node = pidRemap.newChild(None, 'source_program_number', ghostService)
                    node.newProp('base', '10')
                    node = pidRemap.newChild(None, 'pid_in', '0000')
                    node.newProp('base', '16')                
                    node = pidRemap.newChild(None, 'pid_out', '0000')
                    node.newProp('base', '16')
                    pidRemap.newChild(None, 'stream_type', 'PMT')
        
                    for item in ghost_list:
                        ghostIdx, ghostPidIn, ghostService, ghostProvider, ghostName, ghostStreamType = item
                        pidRemap = prog.newChild(None, 'pid_remap', None)
                        node = pidRemap.newChild(None, 'source_port', inputIndex)#'1')
                        node.newProp('base', '10')
                        node = pidRemap.newChild(None, 'source_program_number', ghostService)
                        node.newProp('base', '10')
                        node = pidRemap.newChild(None, 'pid_in', ghostPidIn)
                        node.newProp('base', '16')                
                        node = pidRemap.newChild(None, 'pid_out', '0000')
                        node.newProp('base', '16')
                        pidRemap.newChild(None, 'stream_type', ghostStreamType)

            # save config
            self._muxconfig.saveFormatFile(PATH_XML_DOCS + self._configFile, 1)
            self._muxconfig.saveFormatFile(PATH_XML_DOCS + 'webref.xml', 1)
            #self._muxconfig.saveFile(PATH_XML_DOCS + self._configFile)
#           self._delay = 20
#          self._delay_href = 'inputs.py'
#          self._delay_message = 'Apply successful. <BR>Return to Inputs page for additional input modification. >>'
            self._message = REFRESH_MESSAGE
        except KeyError, x:
            self._message = str(x[0])
        self.view(req)
       

#cgi.CGIRequest(Input1Handler).process()
def handler(modpy_request):
    return modpy.Request(InputXHandler).process(modpy_request)
