#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''PolarimeterMain provides the bare methods to run the polarimeter.

It is an example for an interface to the Polarimeter class.
To start an analysis, first run warmup 'w' for the sensor and 
light to stabilize. If you haven't set the zero position in a 
previous run or have moved the device type 'z', with the standard (water).
Replace the sample with the solution to determine the rotation angle for
and run the analysis with 'a'.

@author: guido lutterbach
@contact: guido@smartypies.com
@version: 1.0
@copyright: guido lutterbach, July 2018
'''

import cmd, time, logging
from Polarimeter import Polarimeter, Measurement


class PolMain(cmd.Cmd):
    '''Main class to run analysis with polarimeter.'''

    polmeter = Polarimeter()

    intro = '''usage: type following commands
            w       - sensor and light warmup. One cycle takes about 2 min. Repeat until values are stable.
            z       - set zero /calibrate polarimeter
            ana [r [l]] - find delta angle, calculate concentration when specific rotation and length (default 1) are given  
            rec [name]|off - record measurement data to file name or stop it
            o       - one measurement
            q (quit)'''
    prompt = '>>'
    file = None

    __logfile = None
    __warmupsuccess = False

    def do_w(self, arg):
        self.__warmup()

    def do_o(self, arg):
        '''One measurement.'''
        self.__measure()

    def do_z(self, arg):
        '''Reset position and angle.'''
        if self.__warmupsuccess:
            self.polmeter.setzero()
        else:
            print('Please run warmup first!')

    def do_rec(self, arg):
        '''Record measurements to file.'''
        if arg == 'off':
            if self.__logfile is not None:
                print('Close record file: ', self.__logfile.name)
                self.__logfile.close()
                self.__logfile = None
            else:
                print('No record file open')
        else:
            if self.__logfile is not None:
                print('Close record file: ', self.__logfile.name)
                self.__logfile.close()
                self.__logfile = None

            if len(arg) == 0:
                now = time.localtime()
                fname = "{:4d}{:02d}{:02d}{:02d}{:02d}{:02d}.csv".format(
                    now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour,
                    now.tm_min, now.tm_sec)
                self.__logfile = open(fname, 'w')
            else:
                self.__logfile = open(arg, 'w')

            print('Open record file: ', self.__logfile.name)

    def do_q(self, arg):
        '''Quit.'''
        if self.__logfile:
            self.__logfile.close()
        return True

    def do_ana(self, arg):
        '''Run the analysis.'''
        if self.__warmupsuccess:
            larg = tuple(map(float, arg.split()))
            angl = float(self.polmeter.analyze())
            valstring = '{:.2f}'.format(angl)
            if len(larg) > 0:
                fac = 1.0
                if len(larg) >= 2:
                    fac = 100.0 / (larg[0] * larg[1])
                elif len(larg) == 1:
                    fac = 100.0 / larg[0]
                conc = angl * fac
                valstring+=', {:.2f}'.format(conc)
                
            valstring+=', {}'.format(time.asctime())
            print(valstring)
            if self.__logfile:
                self.__logfile.write(valstring + '\n')
        else:
            print('Please run warmup first!')

    def default(self, line):
        print('undefined key')

    def __measure(self):
        '''retrieve raw data from device, format and log here'''
        val = self.polmeter.measure()
        valstring = '{}, {}, {}'.format(val.position, val.value, val.time)
        print(valstring)
        if self.__logfile:
            self.__logfile.write(valstring + '\n')

    def __warmup(self):
        '''Warmup procedure for light and sensor stabilization.'''
        print('Please run several cycles (~2 min each) until successfull.')
        self.polmeter.lighton()
        # search for suitable light intensity max. 10 steps
        for i in range(0, 10):
            val = self.polmeter.measure()
            if val.value >= 1500 and val.value <= 2500:
                break

            for j in range(0, 100):
                self.polmeter.forward()
            val = None

        if val is None:
            print('No suitable light intensity found. Please check LED?')
            raise Exception('Light error')

        self.polmeter.motoroff()
        # check value every second. Wait for 10 consecutive measurements within 0.2 or max 120 sec.
        cnt = 0
        previous = -1

        for i in range(1, 121):
            print('*', end='', flush=True)
            val = self.polmeter.measure()
            if abs(val.value - previous) <= 0.2:
                cnt += 1
            else:
                previous = val.value
                cnt = 0
            if cnt == 10:
                print()
                print('Warm up done!')
                self.__warmupsuccess = True
                return
            time.sleep(1)
            if i % 60 == 0:
                print()

        print(
            'No stable value in this 2 min cycle, please repeat. Last value: ', previous)
        return


if __name__ == "__main__":
    try:
        logging.basicConfig(
            level=logging.WARN, format='%(levelname)-8s %(message)s')
        logger = logging.getLogger('Polarimeter')
        PM = PolMain()
        PM.cmdloop()
    finally:
        PM.polmeter.shutdown()
