#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Apr  6 22:17:00 2019

@author: martindrech
"""
import numpy as np
from PyQt5 import QtCore
import time
import threading
from queue import Queue

class Helper_messager(QtCore.QObject):
    imageAquiredSignal = QtCore.pyqtSignal(int)


class AndorZyla:
    def __init__(self, num):
        self.ExposureTime = AndorFeats('Exposure Time')
        self.FrameRate = AndorFeats('Frame Rate')
        self.CameraAcquiring = AndorFeats('Camera Acquiring')
        self.AOIBinning = AndorFeats('AOIBinning')
        self.ImageArea = AndorFeats('Image Area')
        self.CameraModel = AndorFeats('Camera Model')
        self.SensorCooling = AndorFeats('Sensor Cooling')
        self.SensorTemperature = AndorFeats('Sensor Temperature')
        self.TemperatureStatus = AndorFeats('Temperature Sensors')
        self.ReadoutTime = AndorFeats('Readout Time')
        self.PixelReadoutRate = AndorFeats('Pixel Readout Rate')
        self.SimplePreAmpGainControl = AndorFeats('SimpleGainControl')
        self.SpuriousNoiseFilter = AndorFeats('Filter')
        self.TriggerMode = AndorFeats('Trigger Mode')
        self.acq_queue = Queue(maxsize=10)
        self.helper = Helper_messager()
        self.current_image = None

        self.CameraAcquiring.setValue(False)

        self.acq_index_i = 0

        self.ExposureTime.setValue(0.5)
        self.FrameRate.setValue(10)
        self.AOIBinning.setValue('1x1')
        self.ImageArea.setValue(2048)
        self.CameraModel.setValue('dummy')
        self.TriggerMode.setString('Internal')

        self.triggerEventHappened = False 
        self.images_array = []

    def Init(self):
        print("Dummy camera initialized")


    def live_acquisition_loop(self):
        if self.TriggerMode.getString() == 'Software':
            pass
        else:    
            t = threading.currentThread()
            while getattr(t, "do_run", True):
                self.current_image = self.images_array[self.acq_index_i%10]
                self.wait_for_image()
                self.acq_queue.put(self.current_image)
                self.helper.imageAquiredSignal.emit(self.acq_index_i)
                self.acq_index_i = self.acq_index_i + 1
            print("stopping acq loop thread")

   
    def wait_for_image(self):
        time.sleep(self.ExposureTime.getValue())
       
    def live_acquisition_configure(self):
        self.acq_index_i = 0
        
    def AcquisitionStart(self):
        self.CameraAcquiring.setValue(True)
        self._set_image_area()

    def AcquisitionStop(self):
        self.CameraAcquiring.setValue(False)

    def _flush(self):
        pass

    def _set_image_area(self):
        d = {'1x1': 2048, '2x2': 1024, '4x4': 512, '8x8': 256}
        self.ImageArea.setValue(d[self.AOIBinning.getValue()])
        self.images_array = []
        for i in range(10):
            self.images_array.append(self._twoD_gaussian())

    def _twoD_gaussian(self, lim=10, sigma=1, x0=0, y0=0):
        N = self.ImageArea.getValue()
        x, y = np.meshgrid(np.linspace(-lim, lim, N), np.linspace(-lim, lim, N))
        d = np.sqrt((x - x0) ** 2 + (y - y0) ** 2)
        g = np.exp(-((d) ** 2 / (2.0 * sigma ** 2)))
        noise = np.random.rand(N, N)
        return np.int8(g + noise) 

    def trigger(self):
         self.current_image = self.images_array[self.acq_index_i%10]
         time.sleep(self.ExposureTime.getValue())
         self.acq_queue.put(self.current_image)
         self.acq_index_i = self.acq_index_i + 1
         self.helper.imageAquiredSignal.emit(self.acq_index_i-1)
         
    def GetMetaData(self):
        metadata = dict()
        for feat in AndorFeats.registry:
            metadata[feat.name] = feat.getValue()

        return metadata
            
class AndorFeats:
    registry = []
    def __init__(self, name):
        self.value = None
        self.name = name
        self.registry.append(self)

    def getValue(self):
        return self.value

    def setValue(self, val):
        self.value = val

    def _twoD_gaussian(self, lim=10, N=100, sigma=1, x0=0, y0=0):
        x, y = np.meshgrid(np.linspace(-lim, lim, N), np.linspace(-lim, lim, N))
        d = np.sqrt((x - x0) ** 2 + (y - y0) ** 2)
        g = np.exp(-((d) ** 2 / (2.0 * sigma ** 2)))
        noise = np.random.rand(N, N)
        return g + noise

    def max(self):
        return 0

    def setString(self, s):
        self.value = s
        print(s)
        
    def getString(self):
        return str(self.value)