# MIT license: https://opensource.org/licenses/MIT
# See https://github.com/Isotel/mixedsim/blob/master/python/ngspice_read.py
# for a more complete library. Isotel's version is GPL licensed
from __future__ import division
#import division
import numpy as np
import pandas as pd
import glob
BSIZE_SP = 512 # Max size of a line of data; we don't want to read the
               # whole file to find a line, in case file does not have
               # expected structure.
MDATA_LIST = [b'title', b'date', b'plotname', b'flags', b'no. variables',
              b'no. points', b'dimensions', b'command', b'option']
def ngRawRead(fname: str):
    """Read ngspice binary raw files. Return tuple of the data, and the
    plot metadata. The dtype of the data contains field names. This is
    not very robust yet, and only supports ngspice.
    >>> darr, mdata = rawread('test.py')
    >>> darr.dtype.names
    >>> plot(np.real(darr['frequency']), np.abs(darr['v(out)']))
    """
    # Example header of raw file
    # Title: rc band pass example circuit
    # Date: Sun Feb 21 11:29:14  2016
    # Plotname: AC Analysis
    # Flags: complex
    # No. Variables: 3
    # No. Points: 41
    # Variables:
    #         0       frequency       frequency       grid=3
    #         1       v(out)  voltage
    #         2       v(in)   voltage
    # Binary:
    with open(fname, 'rb') as fp:
        plot = {}
        count = 0
        arrs = []
        plots = []
        names = dict()
        ind = 0
        while (True):
            try:
                mdata = fp.readline(BSIZE_SP).split(b':', maxsplit=1)
            except:
                raise
            if len(mdata) == 2:
                if mdata[0].lower() in MDATA_LIST:
                    plot[mdata[0].lower()] = mdata[1].strip()
                if mdata[0].lower() == b'variables':
                    nvars = int(plot[b'no. variables'])
                    npoints = int(plot[b'no. points'])
                    plot['varnames'] = []
                    plot['varunits'] = []
                    for varn in range(nvars):

                        varspec = (fp.readline(BSIZE_SP).strip()
                                   .decode('ascii').split())
                        assert(varn == int(varspec[0]))

                        #- Skip duplicated variables
                        if(varspec[1] not in names):
                            names[varspec[1]] = 1
                        else:
                            varspec[1] += str(ind)
                            ind +=1
                        plot['varnames'].append(varspec[1])
                        plot['varunits'].append(varspec[2])
                if mdata[0].lower() == b'binary':
                    rowdtype = np.dtype({'names': plot['varnames'],
                                         'formats': [np.complex128 if b'complex'
                                                     in plot[b'flags']
                                                     else np.float64]*nvars})
                    arrs.append(np.fromfile(fp, dtype=rowdtype, count=npoints))
                    plots.append(plot)
                    fp.readline()
            else:
                break

    return (arrs, plots)

def toDataFrames(ngarr):
    (arrs,plots) = ngarr

    dfs = list()
    for i in range(0,len(plots)):
        df = pd.DataFrame(data=arrs[i],columns=plots[i]['varnames'])
        dfs.append(df)
    return dfs

def toDataFrame(fraw):
    (arrs,plots) = ngRawRead(fraw)

    dfs = list()
    for i in range(0,len(plots)):
        df = pd.DataFrame(data=arrs[i],columns=plots[i]['varnames'])
        dfs.append(df)

    if(len(dfs)> 0):
        return dfs[0]
    else:
        return None





if __name__ == '__main__':
    arrs, plots = ngRawRead('test.raw')
    print(arrs)
