import sys
import os
from xml.etree import ElementTree as ET



class PrcocessNetlist:
    """
    This class include all the function required for pre-proccessing of netlist 
    before converting to Ngspice Netlist.
    """
    modelxmlDIR = '../modelParamXML'
    def __init__(self):
        pass
      
    def readNetlist(self,filename):
        f = open(filename)
        data=f.read()
        f.close()
        return data.splitlines()

    def readParamInfo(self,kicadNetlis):
        """Read Parameter information and store it into dictionary"""
        param={}
        for eachline in kicadNetlis:
            print eachline
            eachline=eachline.strip()
            if len(eachline)>1:
                words=eachline.split()
                option=words[0].lower()
                if option=='.param':
                    for i in range(1, len(words), 1):
                        paramList=words[i].split('=')
                        param[paramList[0]]=paramList[1]
        return param
    
    def preprocessNetlist(self,kicadNetlis,param):
        """Preprocess netlist (replace parameters)"""
        netlist=[]
        for eachline in kicadNetlis:
            # Remove leading and trailing blanks spaces from line 
            eachline=eachline.strip()
            # Remove special character $
            eachline=eachline.replace('$','')
            # Replace parameter with values
            for subParam in eachline.split():
                if '}' in subParam:
                    key=subParam.split()[0]
                    key=key.strip('{')
                    key=key.strip('}')
                    if key in param:
                        eachline=eachline.replace('{'+key+'}',param[key])
                    else:
                        print "Parameter " + key +" does not exists"
                        value=raw_input('Enter parameter value: ')
                        eachline=eachline.replace('{'+key+'}',value)
            #Convert netlist into lower case letter     
            eachline=eachline.lower()
            # Construct netlist
            if len(eachline)>1:
                if eachline[0]=='+':
                    netlist.append(netlist.pop()+eachline.replace('+',' '))
                else:
                    netlist.append(eachline)
        #Copy information line
        infoline=netlist[0]
        netlist.remove(netlist[0])
        return netlist,infoline
    
    def separateNetlistInfo(self,netlist):
        optionInfo=[]
        schematicInfo=[]
        for eachline in netlist:
            if eachline[0]=='*':
                continue
            elif eachline[0]=='.':
                optionInfo.append(eachline)
            else:
                schematicInfo.append(eachline)
        return optionInfo,schematicInfo
    
        
    def insertSpecialSourceParam(self,schematicInfo,sourcelist):
        #Inser Special source parameter
        schematicInfo1=[]
        
        print "Reading schematic info for source details"
        
        for compline in schematicInfo:
            words=compline.split()
            compName=words[0]
            # Ask for parameters of source
            if compName[0]=='v' or compName[0]=='i':
                # Find the index component from circuit
                index=schematicInfo.index(compline)
                if words[3]=="pulse":
                    Title="Add parameters for pulse source "+compName
                    v1='  Enter initial value(Volts/Amps): '
                    v2='  Enter pulsed value(Volts/Amps): '
                    td='  Enter delay time (seconds): '
                    tr='  Enter rise time (seconds): '
                    tf='  Enter fall time (seconds): '
                    pw='  Enter pulse width (seconds): '
                    tp='  Enter period (seconds): '
                    sourcelist.append([index,compline,words[3],Title,v1,v2,td,tr,tf,pw,tp])
                    
                elif words[3]=="sine":
                    Title="Add parameters for sine source "+compName
                    vo='  Enter offset value (Volts/Amps): '
                    va='  Enter amplitude (Volts/Amps): '
                    freq='  Enter frequency (Hz): '
                    td='  Enter delay time (seconds): '
                    theta='  Enter damping factor (1/seconds): '
                    sourcelist.append([index,compline,words[3],Title,vo,va,freq,td,theta])

                elif words[3]=="pwl":
                    Title="Add parameters for pwl source "+compName
                    t_v=' Enter in pwl format without bracket i.e t1 v1 t2 v2.... '
                    sourcelist.append([index,compline,words[3],Title,t_v])

                elif words[3]=="ac":
                    Title="Add parameters for ac source "+compName
                    v_a='  Enter amplitude (Volts/Amps): '
                    p_a ='  Enter Phase Shift: '
                    sourcelist.append([index,compline,words[3],Title,v_a,p_a])

                elif words[3]=="exp":
                    Title="Add parameters for exponential source "+compName
                    v1='  Enter initial value(Volts/Amps): '
                    v2='  Enter pulsed value(Volts/Amps): '
                    td1='  Enter rise delay time (seconds): '
                    tau1='  Enter rise time constant (seconds):     '
                    td2='  Enter fall time (seconds): '
                    tau2='  Enter fall time constant (seconds): '
                    sourcelist.append([index,compline,words[3],Title,v1,v2,td1,tau1,td2,tau2])

                elif words[3]=="dc":
                    Title="Add parameters for DC source "+compName
                    v1='  Enter value(Volts/Amps): '
                    v2='  Enter zero frequency: '
                    sourcelist.append([index,compline,words[3],Title,v1,v2])
                
            elif compName[0]=='h' or compName[0]=='f':
                # Find the index component from the circuit
                index=schematicInfo.index(compline)
                schematicInfo.remove(compline)
                schematicInfo.insert(index,"* "+compName)
                schematicInfo1.append("V"+compName+" "+words[3]+" "+words[4]+" 0")
                schematicInfo1.append(compName+" "+words[1]+" "+words[2]+" "+"V"+compName+" "+words[5])
                
        schematicInfo=schematicInfo+schematicInfo1
        print "Source List : ",sourcelist
        #print schematicInfo
        return schematicInfo,sourcelist
    
    
    def convertICintoBasicBlocks(self,schematicInfo,outputOption,modelList,plotText):
        print "Reading Schematic info for Model"
        #Insert details of Ngspice model
        unknownModelList = []
        multipleModelList = []
        plotList = ['plot_v1','plot_v2','plot_i2','plot_log','plot_db','plot_phase']
        interMediateNodeCount=1
        k = 1
        for compline in schematicInfo:
            words = compline.split()
            compName = words[0]
            #print "Compline----------------->",compline
            #print "compName-------------->",compName
            # Find the IC from schematic 
            if compName[0]=='u' or compName[0] == 'U':
                # Find the component from the circuit
                index=schematicInfo.index(compline)
                compType=words[len(words)-1];
                schematicInfo.remove(compline)
                paramDict = {}
                #e.g compLine : u1 1 2 gain 
                #compType : gain
                #compName : u1
                #print "Compline",compline 
                #print "CompType",compType
                #print "Words",words
                #print "compName",compName
                #Looking if model file is present
                if compType != "port" and compType != "ic" and compType not in plotList and compType != 'transfo':
                    xmlfile = compType+".xml"   #XML Model File
                    count = 0 #Check if model of same name is present
                    modelPath = []
                    all_dir = [x[0] for x in os.walk(PrcocessNetlist.modelxmlDIR)]
                    for each_dir in all_dir:
                        all_file = os.listdir(each_dir)
                        if xmlfile in all_file:
                            count += 1
                            modelPath.append(os.path.join(each_dir,xmlfile))
                          
                    if count > 1:
                        multipleModelList.append(modelPath)
                    elif count == 0:
                        unknownModelList.append(compType)
                    elif count == 1:
                        try:
                            print "Start Parsing Previous Values XML for ngspice model :",modelPath  
                            tree = ET.parse(modelPath[0])
                            
                            root = tree.getroot()
                            #Getting number of nodes for model and title
                            for child in tree.iter():
                                if child.tag == 'node_number':
                                    num_of_nodes = int(child.text)
                                elif child.tag == 'title':
                                    title = child.text+" "+compName
                                elif child.tag == 'name':
                                    modelname = child.text
                                elif child.tag == 'type':
                                    #Checking for Analog and Digital
                                    type = child.text
                                elif child.tag == 'split':
                                    splitDetail = child.text
                                    
                                
                            for param in tree.findall('param'):
                                for item in param:
                                    #print "Tags ",item.tag
                                    #print "Value",item.text
                                    if 'vector'in item.attrib:
                                        #print "Tag having vector attribute",item.tag,item.attrib['vector']
                                        temp_count = 1
                                        temp_list = []
                                        for i in range(0,int(item.attrib['vector'])):
                                            temp_list.append(item.text+" "+str(temp_count))
                                            temp_count += 1
                                        if 'default' in item.attrib:
                                            paramDict[item.tag+":"+item.attrib['default']] = temp_list
                                        else:
                                            paramDict[item.tag] = item.text
                                                                        
                                    else:
                                        if 'default' in item.attrib:
                                            paramDict[item.tag+":"+item.attrib['default']] = item.text
                                        else:
                                            paramDict[item.tag] = item.text
                                    
                                
                            #print "Number of Nodes : ",num_of_nodes
                            #print "Title : ",title
                            #print "Parameters",paramDict
                            #Creating line for adding model line in schematic
                            if splitDetail == 'None':
                                modelLine = "a"+str(k)+" "
                                for i in range(1,num_of_nodes+1):
                                    modelLine += words[i]+" "
                                modelLine += compName
                                
                            else:
                                print "Split Details :",splitDetail
                                modelLine = "a"+str(k)+" "
                                vectorDetail = splitDetail.split(':')
                                #print "Vector Details",vectorDetail
                                pos = 1 #Node position
                                for item in vectorDetail:
                                    try:
                                        if item.split("-")[1] == 'V':
                                            #print "Vector"
                                            if compType == "aswitch":
                                                modelLine += "("
                                                for i in range(0,int(item.split("-")[0])):
                                                    modelLine += words[pos]+" "
                                                    pos += 1
                                                modelLine += ") "
                                            else:
                                                modelLine += "["
                                                for i in range(0,int(item.split("-")[0])):
                                                    modelLine += words[pos]+" "
                                                    pos += 1
                                                modelLine += "] "    
                                        elif item.split("-")[1] == 'NV':
                                            #print "Non Vector"  
                                            for i in range(0,int(item.split("-")[0])):
                                                modelLine += words[pos]+" "
                                                pos += 1
                                    
                                    except:
                                        print  "There is error while processing Vector Details"
                                        sys.exit(2)
                                modelLine += compName        
                                
                            #print "Final Model Line :",modelLine
                            try:
                                schematicInfo.append(modelLine)
                                k=k+1
                            except Exception as e:
                                print "Error while appending ModelLine ",modelLine
                                print "Exception Message : ",str(e)
                            #Insert comment at remove line
                            schematicInfo.insert(index,"* "+compline)
                            comment = "* Schematic Name: "+compType+", NgSpice Name: "+modelname
                            #Here instead of adding compType(use for XML), added modelName(Unique Model Name)
                            modelList.append([index,compline,modelname,compName,comment,title,type,paramDict])
                        except Exception as e:
                            print  "Unable to parse the model, Please check your your XML file"
                            print "Exception Message : ",str(e)
                            sys.exit(2)
                elif compType == "ic":
                    schematicInfo.insert(index,"* "+compline)
                    modelname = "ic"
                    comment = "* "+compline
                    title = "Initial Condition for "+compName
                    type = "NA" #Its is not model 
                    text = "Enter initial voltage at node for "+compline
                    paramDict[title] = text
                    modelList.append([index,compline,modelname,compName,comment,title,type,paramDict])
                
                elif compType in plotList:
                    schematicInfo.insert(index,"* "+compline)
                    if compType == 'plot_v1':
                        words = compline.split()
                        plotText.append("plot v("+words[1]+")")
                    elif compType == 'plot_v2':
                        words = compline.split()
                        plotText.append("plot v("+words[1]+","+words[2]+")")
                    elif compType == 'plot_i2':
                        words = compline.split()
                        #Adding zero voltage source to netlist
                        schematicInfo.append("v_"+words[0]+" "+words[1]+" "+words[2]+" "+"0")
                        plotText.append("plot i(v_"+words[0]+")")
                    elif compType == 'plot_log':
                        words = compline.split()
                        plotText.append("plot log("+words[1]+")")
                    elif compType == 'plot_db':
                        words = compline.split()
                        plotText.append("plot db("+words[1]+")")
                    elif compType == 'plot_phase':
                        words = compline.split()
                        plotText.append("plot phase("+words[1]+")")
                
                elif compType == 'transfo':
                    schematicInfo.insert(index,"* "+compline)
                    
                    #For Primary Couple
                    modelLine = "a"+str(k)+" ("+words[1]+" "+words[2]+") (interNode_"+str(interMediateNodeCount)+" "+words[3]+") "
                    modelLine += compName+"_primary"
                    schematicInfo.append(modelLine)
                    k=k+1
                    #For iron core
                    modelLine = "a"+str(k)+" ("+words[4]+" "+words[2]+") (interNode_"+str(interMediateNodeCount+1)+" "+words[3]+") "
                    modelLine += compName+"_secondary"
                    schematicInfo.append(modelLine)
                    k=k+1
                    #For Secondary Couple
                    modelLine = "a"+str(k)+" (interNode_"+str(interMediateNodeCount)+" interNode_"+str(interMediateNodeCount+1)+") "
                    modelLine += compName+"_iron_core"
                    schematicInfo.append(modelLine)
                    k=k+1
                    interMediateNodeCount += 2
                    
                    modelname = "transfo"
                    comment = "* "+compline
                    title = "Transformer details for model "+compName
                    type = "NA" #It is model but do not load from xml and lib file
                    paramDict['h1_array'] = "Enter the H1 array "
                    paramDict['primary_turns'] = "Enter the primary number of turns (default=310) "
                    paramDict['area'] = "Enter iron core area (default=1)"
                    paramDict['secondar_turns'] = "Enter the secondary number of turns (default=620)"
                    paramDict['length'] = "Enter iron core length (default=0.01)"
                    paramDict['b1_array'] = "Enter the B1 array "
                                        
                    
                    modelList.append([index,compline,modelname,compName,comment,title,type,paramDict])
                
                else:
                    schematicInfo.insert(index,"* "+compline)
                    
                print "UnknownModelList Used in the Schematic",unknownModelList
                print "Multiple Model XML file with same name ",multipleModelList
                print "Model List Details : ",modelList  
                
        return schematicInfo,outputOption,modelList,unknownModelList,multipleModelList,plotText
        
        
            
