import smbus
from . import background_task
import logging
import time

try:
    from config import APP_NAME as ROOT_LOGGER_NAME
except ImportError:
    ROOT_LOGGER_NAME = 'root'

logger = logging.getLogger(ROOT_LOGGER_NAME).getChild(__name__)


class bmp_180(background_task):
    RUN_SLEEP_TIME = 2.0
    SMBUS_DELAY = 0.5
    MIN_REFRESH_RATE = RUN_SLEEP_TIME + 3 * SMBUS_DELAY
    KEY_TEMPERATURE = 'temperature'
    KEY_PRESSURE = 'pressure'
    KEY_TIME = 'time'

    def __init__(self, data_callback=None):
        self.__data_callback__ = data_callback
        self.DEBUG = False
        # Initialise background_task
        background_task.__init__(self)

    def __run__(self):
        data = self.__bmp_data_transmission__()
        if data is not None:
            logger.info('BMP-Communication successful: %s', repr(data))
            if self.__data_callback__ is not None:
                self.__data_callback__(**data)
        else:
            logger.debug('BMP-Communication failed: No data received')

    def __bmp_data_transmission__(self):
        if not self.DEBUG:
            rv = {}
            # Get I2C bus
            try:
                bus = smbus.SMBus(1)
            except PermissionError:
                logger.warning("Switching to DEBUG mode due to permission error...")
                self.DEBUG = True
            else:
                # BMP180 address, 0x77(119)
                # Read data back from 0xAA(170), 22 bytes
                data = bus.read_i2c_block_data(0x77, 0xAA, 22)

                # Convert the data
                AC1 = data[0] * 256 + data[1]
                if AC1 > 32767:
                    AC1 -= 65535
                AC2 = data[2] * 256 + data[3]
                if AC2 > 32767:
                    AC2 -= 65535
                AC3 = data[4] * 256 + data[5]
                if AC3 > 32767:
                    AC3 -= 65535
                AC4 = data[6] * 256 + data[7]
                AC5 = data[8] * 256 + data[9]
                AC6 = data[10] * 256 + data[11]
                B1 = data[12] * 256 + data[13]
                if B1 > 32767:
                    B1 -= 65535
                B2 = data[14] * 256 + data[15]
                if B2 > 32767:
                    B2 -= 65535
                MB = data[16] * 256 + data[17]
                if MB > 32767:
                    MB -= 65535
                MC = data[18] * 256 + data[19]
                if MC > 32767:
                    MC -= 65535
                MD = data[20] * 256 + data[21]
                if MD > 32767:
                    MD -= 65535

                time.sleep(self.SMBUS_DELAY)

                # BMP180 address, 0x77(119)
                # Select measurement control register, 0xF4(244)
                #        0x2E(46)    Enable temperature measurement
                bus.write_byte_data(0x77, 0xF4, 0x2E)

                time.sleep(self.SMBUS_DELAY)

                # BMP180 address, 0x77(119)
                # Read data back from 0xF6(246), 2 bytes
                # temp MSB, temp LSB
                data = bus.read_i2c_block_data(0x77, 0xF6, 2)

                # Convert the data
                temp = data[0] * 256 + data[1]

                # BMP180 address, 0x77(119)
                # Select measurement control register, 0xF4(244)
                #        0x74(116)    Enable pressure measurement, OSS = 1
                bus.write_byte_data(0x77, 0xF4, 0x74)

                time.sleep(self.SMBUS_DELAY)

                # BMP180 address, 0x77(119)
                # Read data back from 0xF6(246), 3 bytes
                # pres MSB1, pres MSB, pres LSB
                data = bus.read_i2c_block_data(0x77, 0xF6, 3)

                rv[self.KEY_TIME] = int(time.time())

                # Convert the data
                pres = ((data[0] * 65536) + (data[1] * 256) + data[2]) / 128
                # Callibration for Temperature
                X1 = (temp - AC6) * AC5 / 32768.0
                X2 = (MC * 2048.0) / (X1 + MD)
                B5 = X1 + X2
                rv[self.KEY_TEMPERATURE] = ((B5 + 8.0) / 16.0) / 10.0

                # Calibration for Pressure
                B6 = B5 - 4000
                X1 = (B2 * (B6 * B6 / 4096.0)) / 2048.0
                X2 = AC2 * B6 / 2048.0
                X3 = X1 + X2
                B3 = (((AC1 * 4 + X3) * 2) + 2) / 4.0
                X1 = AC3 * B6 / 8192.0
                X2 = (B1 * (B6 * B6 / 2048.0)) / 65536.0
                X3 = ((X1 + X2) + 2) / 4.0
                B4 = AC4 * (X3 + 32768) / 32768.0
                B7 = ((pres - B3) * (25000.0))
                pressure = 0.0
                if B7 < 2147483648:
                    pressure = (B7 * 2) / B4
                else:
                    pressure = (B7 / B4) * 2
                X1 = (pressure / 256.0) * (pressure / 256.0)
                X1 = (X1 * 3038.0) / 65536.0
                X2 = ((-7357) * pressure) / 65536.0
                rv[self.KEY_PRESSURE] = (pressure + (X1 + X2 + 3791) / 16.0) / 100

                return rv
        else:
            time.sleep(3 * self.SMBUS_DELAY)
            return {
                self.KEY_PRESSURE: 1717.,
                self.KEY_TEMPERATURE: 17.17,
                self.KEY_TIME: int(time.time())
            }
