from exceptions import Exception
import struct
from itertools import chain



class IncorrectFormatException(Exception):
    pass



class FRQInfo(object):
    """FRQClass, read and stores information from .frq file

    __init__ method will load header and info

    Raises IncorrectFormatException

    Attributes:
        filename (str): .frq file path
        num_channels        (int) : 
        frame_size          (int) : 
        total_single_frames (int) : 
        info_offset         (int) : 
        info_size           (int) : 
        data_offset         (int) :

        info(dict): info['param'] = value(str)    

        signals (list of lists [[]]): if signals have not been loaded yet,
                                      will load them, len(signals) = num_channels 

    """
    def __init__(self, filename):
        self.filename = filename
        f = open(filename , "rb")

        # init signals storage
        self._signals = []
        # read TMFRFrontheader:
        # typedef struct
        # {
        # unsigned char hdr[4];
        # int NumChannels;
        # int FrameSize;
        # int TotalSingleFrames;
        # int InfoOffset;
        # int InfoSize;
        # int dataoffset;
        # int dummy[9];
        # }TMFRFrontheader;
        header = struct.unpack('3c015i', f.read(64))
        # example of header : ('F', 'R', 'Q', 2, 512, 30, 64, 1984, 2048, \
        #                       0, 0, 0, 0, 0, 0, 0, 0, 0)
        # save usefull info
        if (header[0] + header[1] + header[2]) != 'FRQ':
            f.close()
            raise IncorrectFormatException(
                        str(self.filename) + " is in incorrect format")

        self.num_channels        = header[3]
        self.frame_size          = header[4]
        self.total_single_frames = header[5]
        self.info_offset         = header[6]
        self.info_size           = header[7]
        self.data_offset         = header[8]
        #read info
        # example of info
        # TsPH:20160502T080002501+0200|TsPL:20160502T080002859+0200|TsOH:20160502T080002706+0200| \
        # TsOL:20160502T080003064+0200|Velocity:71,393|Shift:2017|Distance:4000|Length:6,526| \ 
        # Curvitude:3,254|Center:0,450|FillF:0,537|Curv1:3,094|Curv2:1,333|NZPD:1,000| \
        # P00:0,06|P01:0,25|P02:0,48|P03:0,70|P04:0,91|P05:1,00|P06:0,90|P07:0,72| \
        # P08:0,58|P09:0,52|P10:0,50|P11:0,54|P12:0,50|P13:0,48|P14:0,49|P15:0,47| \
        # P16:0,30|P17:0,17|P18:0,08|P19:0,03|Pb:2683|Pe:6352|KlasRes:4|KlT:3|KlV:18|WDir:0|LoopWidth:1,500"
        info = f.read(self.info_size)
        self.info = dict()
        for item in info[:info.index('\x00')].split('|'):
            self.info[item.split(':')[0]] = item.split(':')[1]

        
        f.close()

    def load_signals(self):
        """load signals from .frq file"""
        # if self.bad:
        #     raise IncorrectFormatException(
        #                 str(self.filename) + " is in incorrect format")
            
        f = open(self.filename , "rb")
        self._signals = []
        f.seek(self.data_offset)
        cformat = '<' + str(self.frame_size) + 'i'
        # unpack frames
        frames = [struct.unpack(cformat, f.read(self.frame_size*4))
                             for _ in range(self.total_single_frames)]
        
        # put frames into channels
        for n_ch in range(self.num_channels):
            signal = [frame for i, frame in enumerate(frames) 
                                         if i % self.num_channels == n_ch]
            self._signals.append(list(chain(*signal)))
        
        f.close()

    @property
    def signals(self):
        # if self.bad:
        #     raise IncorrectFormatException(
        #                 str(self.filename) + " is in incorrect format")
        if(self._signals == []):
            self.load_signals()
        return self._signals
      
            
    def __str__(self):
        return "FRQInfo object, filename: " + str(self.filename) + "\n" + \
                str(self.info)


# if __name__ == "__main__":
#     import matplotlib.pyplot as plt
#     frq_filename =  "..\\data\\FRQ\\KP-CE\\20160502\\08\\KP-CE-W2_20160502T080057644+0200.frq"
#     frq = FRQinfo(frq_filename)
#     plt.plot(frq.signals[0])
#     plt.show()