"""
Manipulating the ULT fridge Platinum Thermometer logs.
"""

import os
import os.path
import time
import datetime
import numpy
import matplotlib.dates
import flib
import timelog

class PLMLog(timelog.TimeLog):
    """
    Represents a ULT PLM4 thermometry log over a certain time.
    Two logs can be concatenated with a '&' sign

    log format:
    1  [:,0]  Time (sec, since 00:00 1 January 1970 GMT)
    2  [:,1]  Curie Temperature [mK] T = B / (M0 - A)
    3  [:,2]  Magnetisation M0
    4  [:,3]  Transmitter Pulse Length
    5  [:,4]  NS MCT Temperature (mK, Greywall scale)
    6  [:,5]  NS MCT Bridge Ratio
    7  [:,6]  Background (stabilised)
    8  [:,7]  Gain Stability Index
    9  [:,8]  Gain
    10 [:,9]  Integration delay
    11 [:,10] Integration time
    12 [:,11] 0 if PLM was overloaded, otherwise 1
    """

    @staticmethod
    def fieldcount(): "return number of columns in the self.data"; return 12
        
    def T(self): "temperature"; return self.data[:,1]
    def M0(self): "M0"; return self.data[:,2]
    def xmit(self): "transmitter pulse length"; return self.data[:,3].astype('i')
    def T_MCTNS(self): "MCTNS Temp"; return self.data[:,4]
    def r_MCTNS(self): "MCTNS ratio"; return self.data[:,5]
    def bg(self): "raw background"; return self.data[:,6]
    def stabi(self): "gain stability index"; return self.data[:,7]
    def gain(self): "PLM-4 gain"; return self.data[:,8].astype('i')
    def idelay(self): "integration delay"; return self.data[:,9]
    def itime(self): "integration time"; return self.data[:,10]
    def overdrive(self): "True if the measurement overdrove PLM-4, otherwise False"; return self.dat[:,11] == 0
    def rawM0(self): "raw (unstabilised) M0"; return self.M0()*self.stabi() + self.bg()

    def atxmit(self, xmit):
        """
        Return a subset of the log obtained for a certain transmitter pulse length
        """
        return self.subset(self.xmit() == xmit)

    def xmits(self):
        """
        Return a list of transmitter pulse lengths used present in the log
        """
        return sorted(set(self.xmit()))

    def __repr__(self): return "PLMLog %s, xmit=%s" % (self.datespan(), self.xmits())

    @staticmethod
    def load(filename):
        """
        Load PLM log from a given file
        The function determines file format from the name:
            3. '????????plm-4.dat' run 20+, since 24 March 2008
            2. '????????plm4.dat'  early on run 20 (before 24 March 2008)
            1. '????????_plm4.dat' prior to run 20
        
        If a file read is in format 1 or 2, the following assumptions are made
        (the corresponding data were not recorded):
            
            variable gain defaults to 10
            integration delay to 55
            integration time to 125
            PLM is considered not to overload if M0 > 0
        """

        basename = os.path.basename(filename)
        if basename[8:] == 'plm-4.dat':
            # Loads a new (Run 20+, since 24 March 2008) format PLM log from a given file
            #
            # 1 [:,0] Time (sec, since 00:00 1 January 1970 GMT)
            # 2 [:,1] Curie Temperature [mK] T = B / (M0 - A)
            # 3 [:,2] Magnetisation M0
            # 4 [:,3] Transmitter Pulse Length
            # 5 [:,4] NS MCT Temperature (mK, Greywall scale)
            # 6 [:,5] NS MCT Bridge Ratio
            # 7 [:,6] Background (stabilised)
            # 8  [:,7]  Gain Stability Index
            # 9  [:,8]  Gain (or Gain Code - 0 for 10, 1 for 20, 2 for 50, 3 for 100)
            # 10 [:,9]  Integration delay
            # 11 [:,10] Integration time
            # 12 [:,11] 0 if PLM was overloaded, otherwise 1

            data = flib.loadascii(filename, usecols=range(12))

            # timestamps are stored as seconds since 00:00 1 Jan 1904.
            # Convert to seconds since 00:00 1 Jan 1970, C and UNIX time format.
            data[:,0] = flib.labview2tm(data[:,0])
            
            # for a short time gain code was stored instead of gain, 
            # e.g. 0 for 10, 1 for 20, 2 for 50, 3 for 100
            # correct this:
            data[data[:,8] == 0,8] = 10
            data[data[:,8] == 1,8] = 20
            data[data[:,8] == 2,8] = 50
            data[data[:,8] == 3,8] = 100

            return PLMLog(data)

        elif basename[8:] == 'plm4.dat':
            # Loads PLM log in format used early on Run 20 (before 24 March 2008) from a given file
            # 
            # 1 [:,0] Time (sec, since 00:00 1 January 1970 GMT)
            # 2 [:,1] Curie Temperature [mK] T = B / (M0 - A)
            # 3 [:,2] Magnetisation M0
            # 4 [:,3] Transmitter Pulse Length
            # 5 [:,4] NS MCT Temperature (mK, Greywall scale)
            # 6 [:,5] NS MCT Bridge Ratio
            # 7 [:,6] Background (stabilised)
            # 8 [:,7] Gain (stabilised) - proper name is gain stability index
            #
            # skip 10 rows because of the "Created on ..." is not preceded by a '#'.

            rawdata = flib.loadascii(filename, skiprows=10, usecols=range(8))

            # fill with NaN's
            data = 0./ numpy.zeros((len(rawdata), 12))
            data[:,0:8] = rawdata[:,0:8]

            # fill the absent columns, hope these are the correct values
            # 9  [:,8]  Gain
            # 10 [:,9]  Integration delay
            # 11 [:,10] Integration time
            # 12 [:,11] 0 if PLM was overloaded, otherwise 1
            data[:,8] = 10
            data[:,9] = 55
            data[:,10] = 125
            data[:,11] = (data[:,2] > 0) # assume no overload if M0 > 0

            # timestamps are stored as seconds since 00:00 1 Jan 1904.
            # Convert to seconds since 00:00 1 Jan 1970, C and UNIX time format.
            data[:,0] = flib.labview2tm(data[:,0])
            return PLMLog(data)

        elif basename[8:] == '_plm4.dat':
            # Loads an old (prior Run 20) format PLM log from a given file.
            # Filename is used to determine the date stamp.
            #
            # file format is:
            # 1 [:,0] - time, seconds since start of the day
            # 2 [:,1] - background
            # 3 [:,2] - gain stab. index
            # 4 [:,3] - M0
            # 5 [:,4] - Temperature
            # ... the rest is omitted. Contains some string and time since 00:00 1 Jan 1904.
            rawdata = flib.loadascii(filename, usecols=(0,1,2,3,4,5))

            # fill with NaN's
            data = 0./ numpy.zeros((len(rawdata), 12))

            # date is encoded in the filename
            year = int(basename[0:4])
            month = int(basename[4:6])
            day = int(basename[6:8])

            data[:,0] = rawdata[:,0] + time.mktime(datetime.date(year, month, day).timetuple())
            data[:,1] = rawdata[:,4]
            data[:,2] = rawdata[:,3]
            data[:,3] = rawdata[:,5]
            data[:,6] = rawdata[:,1]
            data[:,7] = rawdata[:,2]

            # fill the absent columns, hope these are the correct values
            # 9  [:,8]  Gain
            # 10 [:,9]  Integration delay
            # 11 [:,10] Integration time
            # 12 [:,11] 0 if PLM was overloaded, otherwise 1
            data[:,8] = 10
            data[:,9] = 55
            data[:,10] = 125
            data[:,11] = (data[:,2] > 0) # assume no overload if M0 > 0
           
            return PLMLog(data)
        else:
            # other file formats are not recognised
            return None
    
    @staticmethod
    def loadrun(run, start = None, end = None):
        """
        Return plm log for a given run, withing [start, end] period if boundaries are specified.
        """
        logdir = r'\\phpc338\Run20\PLM4' if run == 20 else r'C:\pub\plm\run%d'%run
        return PLMLog.loaddir(logdir, start=start, end=end).period(start, end)
