#!/usr/bin/env python3                                                                                                                                                                       # -*- coding: utf-8 -*-
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import matplotlib.pyplot as plt
import pyqtgraph as pg
from pyqtgraph.dockarea import *
import fcntl
import os
import struct
import random
import time as tm
import sys
import board
import busio
import adafruit_ads1x15.ads1115 as ADS
from adafruit_ads1x15.analog_in import AnalogIn



version="SS MACH 0.1.0 [ "+os.path.realpath(__file__)+" ]\n"
constant_xsensor=260
constant_ysensor=12e-3 #0.24/0.00980665 (*1e-3 protoze V a ne mV) a polovina protoze mame jen 5V napajeni
const_maxfilecount=100
datadir="/home/pi/Data"
window_x=800
window_y=600


######### ysensor init
# Create the I2C bus
i2c = busio.I2C(board.SCL, board.SDA)
# Create the ADC object using the I2C bus
ads = ADS.ADS1115(i2c)
ads.gain=8
# Create single-ended input on channel 0
#chan = AnalogIn(ads, ADS.P0)
# Create differential input between channel 0 and 1
chan = AnalogIn(ads, ADS.P0, ADS.P1)


#########FONTS
buttonfont=QtGui.QFont()
buttonfont.setPixelSize(60)
tickfont=QtGui.QFont()
tickfont.setPixelSize(30)
labelfont=QtGui.QFont()
labelfont.setPixelSize(16)
msgfont=QtGui.QFont()
msgfont.setPixelSize(30)
bigmsgfont=QtGui.QFont()
bigmsgfont.setPixelSize(40)
#QtGui.QApplication.setGraphicsSystem('raster')

#GLOBAL VARIABLES
xpos=0 #poloha
buttonsleep=0.5 #delka cekani
X=np.array([])
Xc=np.array([])
Y=np.array([])
Yab=np.array([])
T=np.array([])
FOTO=np.array([])
time=QtCore.QTime.currentTime()
time.start()
mouse=0


###MAIN WINDOW AND DOCKS
app = QtGui.QApplication([])
MainWindow = QtGui.QMainWindow()
MainWindow.setWindowTitle(version)
#MainWindow.resize(window_x,window_y)

stest=app.desktop().screenGeometry().height()>(window_y-1)


if stest:
    MainWindow.resize(window_x,window_y)
else:
    MainWindow.showFullScreen()


#########MOUSE SENSOR BUSSINESS
inputdir="/dev/input/"
inputfile=open("/dev/zero","rb")
inputfile.close()
mouselist=os.listdir(inputdir)
mouselist=[i for i in mouselist if 'mouse' in i]

def config_xsensor():
    global inputfile
    global mouse
    prt("config_xsensor "+setting_xsensor.value())
    try:
        inputfile.close()
        inputfile=open(inputdir+setting_xsensor.value(),"rb")
        fd = inputfile.fileno()
        flag = fcntl.fcntl(fd, fcntl.F_GETFL)
        fcntl.fcntl(fd, fcntl.F_SETFL, flag | os.O_NONBLOCK)
        buf=inputfile.read(3)
        mouse=1
        prt ("X SENSOR=MOUSE")
    except IOError:
        inputfile.close()
        mouse=0
        prt ("NO X SENSOR (NOMOUSE) (not root?)")

def config_ysensor():
    prt("config_ysensor "+setting_ysensor.value())
    
#DOCKS

area = DockArea()
MainWindow.setCentralWidget(area)
dock_plot = Dock("Plot", size=(600, 480))     ## give this dock the minimum pos
dock_buttons = Dock("Control", size=(40,480))
dock_setting = Dock("Setting", size=(1,1))
dock_log = Dock("Log", size=(1,1))
dock_help = Dock("Help", size=(1,1))
area.addDock(dock_help, 'left')      ## place d1 at left edge of dock area (
area.addDock(dock_buttons, 'right')     ## place d2 at right edge of dock area
area.addDock(dock_log, 'above',dock_help)      ## place d1 at left edge of dock area (
area.addDock(dock_setting, 'above', dock_log) ## place d3 at bottom edge of d1
area.addDock(dock_plot, 'above', dock_setting)## place d3 at bottom edge of d1

#LOG dock
log_text=QtGui.QPlainTextEdit()
log_text.setFont(labelfont)
dock_log.addWidget(log_text)

def prt(string):
    log_text.insertPlainText(str(string)+"\n")

#HELP dock
help_text=QtGui.QPlainTextEdit()
help_text.setFont(labelfont)
dock_help.addWidget(help_text)
help_text.insertPlainText("HELP\n \
This is short help\n \
for longer help see readme.txt (someone need to create this file first;))\n\
\n\
First go to settings/mouse and set the right mouse input \
for displacement sensor. Then \n\
EX=EXIT \n\
RE=RESET (erase data)\n\
ZE=ZERO x axis\n\
SA=SAVE\n\
\n\
")


###PLOT dock
plot_widget = pg.PlotWidget(name='Plot1')  ## giving the plots names allows us to link their axes together
plot_widget.showGrid(x=True, y=True, alpha=50.0)


####BUTTONS_dock
button_reset=QtGui.QPushButton("RE", MainWindow)
button_zero=QtGui.QPushButton("ZE", MainWindow)
button_save=QtGui.QPushButton("SA", MainWindow)
button_exit=QtGui.QPushButton("EX", MainWindow)
button_foto=QtGui.QPushButton("FOTO", MainWindow)
button_start=QtGui.QCheckBox("START", MainWindow)

button_reset.setFont(buttonfont)
button_zero.setFont(buttonfont)
button_save.setFont(buttonfont)
button_exit.setFont(buttonfont)
button_foto.setFont(buttonfont)
button_start.setFont(buttonfont)

#########BUTTONS LAYOUT
layout_buttons=pg.LayoutWidget()
layout_buttons.addWidget(button_exit, row=1, col=0)
layout_buttons.addWidget(button_reset,row=3, col=0)
layout_buttons.addWidget(button_zero,row=5,  col=0)
layout_buttons.addWidget(button_save,row=7,  col=0)
layout_buttons.addWidget(button_foto,row=9,  col=0)
layout_buttons.addWidget(button_start,row=11,  col=0)



#####SETTINGS COMPONENTS
setting_xsensor=pg.ComboBox()
setting_xsensor.setFont(labelfont)
setting_xsensor.addItems(mouselist)
setting_xsensor.currentIndexChanged.connect(config_xsensor)
setting_xsensor.addItem("demo/no X sensor")

l_setting_xsensor=QtGui.QLabel("X(mouse) sensor")
l_setting_xsensor.setFont(labelfont)

setting_xsensor_constant=pg.SpinBox(value=constant_xsensor,minStep=1,int=True, decimals=5,min=1,max=10000)
setting_xsensor_constant.setFont(labelfont)
setting_xsensor_constant.setMinimumHeight(labelfont.pixelSize()+6)

l_setting_xsensor_constant=QtGui.QLabel("X sensor constant")
l_setting_xsensor_constant.setFont(labelfont)


setting_ysensor=pg.ComboBox()
setting_ysensor.setFont(labelfont)
setting_ysensor.addItems(["analog/range 1","analog/range2","demo/noanalog"])
setting_ysensor.currentIndexChanged.connect(config_ysensor)
l_setting_ysensor=QtGui.QLabel("Y(analog) sensor")
l_setting_ysensor.setFont(labelfont)

setting_ysensor_constant=pg.SpinBox(value=constant_ysensor,minStep=1e-3, decimals=5,min=1e-6,max=100000)
setting_ysensor_constant.setFont(labelfont)
setting_ysensor_constant.setMinimumHeight(labelfont.pixelSize()+6)
l_setting_ysensor_constant=QtGui.QLabel("Y sensor constant")
l_setting_ysensor_constant.setFont(labelfont)

setting_a=pg.SpinBox(step=0.1)
setting_a.setValue(2.58)
setting_a.setFont(labelfont)
setting_a.setMinimum(0.1)
setting_a.setDecimals(4)
setting_a.setMinimumHeight(labelfont.pixelSize()+6)
l_setting_a=QtGui.QLabel("Sample dim a [mm]")
l_setting_a.setFont(labelfont)

setting_b=pg.SpinBox(step=0.1)
setting_b.setValue(1.28)
setting_b.setFont(labelfont)
setting_b.setMinimum(0.1)
setting_b.setDecimals(4)
setting_b.setMinimumHeight(labelfont.pixelSize()+6)
l_setting_b=QtGui.QLabel("Sample dim b [mm]")
l_setting_b.setFont(labelfont)

setting_c=pg.SpinBox(step=0.1)
setting_c.setValue(21.11)
setting_c.setFont(labelfont)
setting_c.setMinimum(0.1)
setting_c.setDecimals(4)
setting_c.setMinimumHeight(labelfont.pixelSize()+6)
l_setting_c=QtGui.QLabel("Sample dim c [mm]")
l_setting_c.setFont(labelfont)

#######data dir control
button_setting_dir=QtGui.QPushButton("Change dir",MainWindow)
button_setting_dir.setFont(labelfont)
setting_dir=QtGui.QLineEdit(datadir,MainWindow)
setting_dir.setFont(labelfont)
setting_dir.setEnabled(False)
l_setting_dir=QtGui.QLabel("Data Directory")
l_setting_dir.setFont(labelfont)

l_setting_prefix=QtGui.QLabel("Prefix")
l_setting_prefix.setFont(labelfont)
setting_prefix=QtGui.QLineEdit("Test",MainWindow)
setting_prefix.setFont(labelfont)

setting_nr=pg.SpinBox(value=1,minStep=1,int=True, decimals=20)

setting_nr.setFont(labelfont)
setting_nr.setMinimum(0)
setting_nr.setMinimumHeight(labelfont.pixelSize()+6)
l_setting_nr=QtGui.QLabel("Number")
l_setting_nr.setFont(labelfont)


setting_usetimestamp=QtGui.QCheckBox("")
setting_usetimestamp.setFont(labelfont)
setting_usetimestamp.setChecked(False)
if QtCore.QDate.currentDate().year()>2018:
    setting_usetimestamp.setChecked(True) #if year >2018 it means that date time was set properly (from network), so timestamp is correct 


l_setting_usetimestamp=QtGui.QLabel("Use timestamp in filename")
l_setting_usetimestamp.setFont(labelfont)

#l_space=QtGui.QLabel("xxx")
#l_space.setFont(labelfont)
space="   "
#SETTINGS_LAYOUT


layout_setting=pg.LayoutWidget()
layout_setting.addWidget(l_setting_xsensor)
layout_setting.addWidget(setting_xsensor)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_xsensor_constant)
layout_setting.addWidget(setting_xsensor_constant)
layout_setting.nextRow()
if stest:
    layout_setting.addWidget(QtGui.QLabel(space))
    layout_setting.nextRow()
layout_setting.addWidget(l_setting_ysensor)
layout_setting.addWidget(setting_ysensor)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_ysensor_constant)
layout_setting.addWidget(setting_ysensor_constant)
layout_setting.nextRow()
layout_setting.addWidget(QtGui.QLabel(space))
layout_setting.nextRow()
layout_setting.addWidget(l_setting_a)
layout_setting.addWidget(setting_a)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_b)
layout_setting.addWidget(setting_b)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_c)
layout_setting.addWidget(setting_c)
layout_setting.nextRow()
layout_setting.addWidget(QtGui.QLabel(space))
layout_setting.nextRow()
layout_setting.addWidget(l_setting_dir)
layout_setting.addWidget(button_setting_dir,colspan=2)
layout_setting.nextRow()
layout_setting.addWidget(setting_dir,colspan=3)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_prefix)
layout_setting.addWidget(setting_prefix)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_nr)
layout_setting.addWidget(setting_nr)
layout_setting.nextRow()
layout_setting.addWidget(l_setting_usetimestamp)
layout_setting.addWidget(setting_usetimestamp)

if stest:
    layout_setting.nextRow()
    layout_setting.addWidget(QtGui.QLabel(space),rowspan=10)



l_info=QtGui.QLabel("   ")
if stest:
    l_info.setFont(msgfont)
else:
    l_info.setFont(bigmsgfont)
###DOCK AND MAIN WINDOWS
dock_plot.addWidget(plot_widget)
#dock_plot.nextRow()
dock_plot.addWidget(l_info)
dock_buttons.hideTitleBar()
dock_buttons.addWidget(layout_buttons)
dock_setting.addWidget(layout_setting)
MainWindow.show()

######PLOT INIT Create an empty plot curve to be filled later, set its pen
p1 = plot_widget.plot()
p1.setPen((255,255,0))

plot_widget.setXRange(0, 1)
plot_widget.setYRange(0, 0.2)
plot_widget.enableAutoRange("xy",False)
plot_widget.setLabel('left', ' ', units='')
plot_widget.setLabel('bottom', ' ', units='')

plot_widget.getAxis("bottom").tickFont = tickfont
plot_widget.getAxis("bottom").labelFont = tickfont
plot_widget.getAxis("left").tickFont = tickfont
plot_widget.getAxis("left").labelFont = tickfont
plot_widget.getAxis("bottom").setStyle(tickTextOffset = 20)



def reset():
    global offset
    #log_text.clear()
    prt("RESET")
    prt(version)
    offset=chan.voltage
    prt("offset="+str(offset))
    #prt(MainWindow.height())
    global xpos, X, Xc, Y, Yab, T, time, FOTO
    xpos=0
    X=np.array([])
    Xc=np.array([])    
    Y=np.array([])
    Yab=np.array([])
    FOTO=np.array([])
    T=np.array([], dtype=int)
    plot_widget.enableAutoRange("xy",False)
    plot_widget.setXRange(0, 1)
    plot_widget.setYRange(0, 0.2)
    xmin,xmax=plot_widget.getAxis("bottom").range
    ymin,ymax=plot_widget.getAxis("left").range
    #text.setPos((xmax-xmin)/15+xmin,ymax-(ymax-ymin)/15)
    p1.setData(y=Y, x=X)
    #plot_widget.enableAutoRange("xy",True)
    tm.sleep(buttonsleep)
    #l_info.setText(version)
    time.restart()


def read_and_updateData():
    
    global inputfile
    global mouse
    global xpos, X, Xc, Y, Yab, T, time
    global T
    global datadir
    ##global FOTO
    #y=abs(random.random())*10/setting_ysensor_constant.value()
    voltage=chan.voltage
    #print(voltage)
    y=(voltage-offset)/setting_ysensor_constant.value()
    currenttime=time.elapsed()/1000
    ##deltaT=0
    a=setting_a.value()
    b=setting_b.value()
    c=setting_c.value()

    if T.size>2:
        plot_widget.enableAutoRange("xy",True)
        #deltaT=currenttime-T[-1]

    ##if mouse==0:
        #prt (inputfile)
        #buf = inputfile.read(3)
        #prt (buf)
        #if buf:
            #dummy,x = struct.unpack( "bb", buf[1:] )
            #if currenttime>=5:
                #xpos=xpos+x/setting_xsensor_constant.value()
                #X=np.append(X,[xpos],0)
                #Xc=np.append(Xc,[xpos/c],0)
                #Y=np.append(Y,[y],0)
                #Yab=np.append(Yab,[y/(a*b)],0)
                #T=np.append(T,[currenttime],0)
                #FOTO = np.append(FOTO,[0.0])
                #tm.sleep(10)
    
    if button_start.checkState():
            T=np.append(T,[currenttime],0)
        ##xpos=xpos+0.005/setting_xsensor_constant.value()
        #I do not like this duplicity here but let's leave it for now
        ##X=np.append(X,[xpos],0)
        ##Xc=np.append(Xc,[(xpos/c) if c!=0 else 0],0)
            Y=np.append(Y,[y],0)
            Yab=np.append(Yab,[y/(a*b) if a*b!=0 else 0],0)
        #savedtime = currenttime-5.0
        ##FOTO = np.append(FOTO,[0.0])
            #tm.sleep(10.-((tm.time()-starttime)%60))

    if y>15:
        l_info.setStyleSheet("QLabel { background-color : red}");
        l_info.setText("FORCE TOO HIGH!")
    elif 13<y<15:
        l_info.setStyleSheet("QLabel { background-color : yellow}");
        l_info.setText("APPROACHING UPPER LIMIT!")
        
        
    else:
        l_info.setText("X={:6.4f} Y={:6.2f}".format(xpos,y))
        l_info.setStyleSheet("QLabel { background-color : none}");

    if button_reset.isDown():
        prt("reset")
        reset()
    
    ##if button_foto.isDown():
        ##prt ("FOTO")
        ##FOTO = np.array(FOTO)
        

    if button_zero.isDown():
        prt("ZERO")
        X-=xpos
        xpos=0
        Xc=X/c
        T-=T[-1]
        tm.sleep(buttonsleep)
        time.restart()

    if button_exit.isDown():
        prt("EXIT")
        msg = QtGui.QMessageBox()
        msg.setFont(msgfont)
        msg.setIcon(QtGui.QMessageBox.Question)
        msg.setText("EXIT (NO SAVE) ?")
        msg.setWindowTitle("Exit?")
        msg.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No)
        if msg.exec_()==QtGui.QMessageBox.Yes:
            exit()

    if button_save.isDown():
        prt("SAVE")
        setting_dir.setText(datadir)
        fileexist=1
        maxcount=const_maxfilecount

        if setting_usetimestamp.isChecked():
            prt ("ischecked")
            fileexist=0
            dat=QtCore.QDate.currentDate()
            tim=QtCore.QTime.currentTime()
            fnameshort=format(dat.year()-2000,"02d")+format(dat.month(),"02d")+format(dat.day(),"02d")+"_"+format(tim.hour(),"02d")+format(tim.minute(),"02d")+format(tim.second(),"02d")+"_"+setting_prefix.text()
            fname=datadir+"/"+fnameshort
            prt (fname)
        while (fileexist==1):
            prt ("inloop")
            fnameshort=setting_prefix.text()+"_"+setting_nr.text()
            fname=datadir+"/"+fnameshort
            prt("------------------")
            prt(fname)
            try:
                prt("fileexist "+str(fileexist))
                file=open(fname,"r")
                file.close
                setting_nr.setValue(setting_nr.value()+1)
                maxcount=maxcount-1
                prt ("maxcount" + str(maxcount))
            except FileNotFoundError:
                prt("Exception:")
                fileexist=0
                break
                
        if maxcount<1:

            msg = QtGui.QMessageBox()
            msg.setIcon(QtGui.QMessageBox.Question)
            msg.setText("TOO MANY FILES IN DATADIR, PLS CLEAN!!!")
            prt ("TOO MANY FILES IN DATADIR, PLS CLEAN!!!")
            msg.setWindowTitle("Warning")
            msg.setStandardButtons(QtGui.QMessageBox.Ok)
            msg.setFont(msgfont)
            msg.exec_()
                    
        prt(fname)

        try:
            file=open(fname,"x")

        except IOError:
            prt("Problem opening file:"+fname)
            return

        np.set_printoptions(threshold=sys.maxsize)
        np.set_printoptions(formatter={'float': '{:+0.6f}'.format})
        ##th = 0.01
        #Y2 = np.split(Y,2)
        #Y2 = Y[Y>th]
        ##DATA=np.column_stack((T[-len(Y2):],X[-len(Y2):],Y2,Xc[-len(Y2):],Yab[-len(Y2):],FOTO[-len(Y2):]))
        ##print(DATA)
        ##DATA=str(np.column_stack((T[-len(Y2):],X[-len(Y2):],Y2,Xc[-len(Y2):],Yab[-len(Y2):],FOTO[-len(Y2):]))).replace("\n","").replace(" [","").replace("]","\n").replace("[[","").replace(" ","\t").replace("+","")
        DATA=str(np.column_stack((T,Y,Yab))).replace("\n","").replace(" [","").replace("]","\n").replace("[[","").replace(" ","\t").replace("+","")
        print(DATA)
        cr="\n"
        file.write(version)
        file.write("filename="+fname+cr)
        file.write("x(mouse)_sensor="+setting_xsensor.value()+cr )
        file.write("xsensor_constant="+str(setting_xsensor_constant.value())+cr )
        file.write("y(analog)_sensor="+setting_ysensor.value()+cr )
        file.write("ysensor_constant="+str(setting_ysensor_constant.value())+cr )
        file.write("sample_dim_a_mm="+str(setting_a.value())+cr )
        file.write("sample_dim_b_mm="+str(setting_b.value())+cr )
        file.write("sample_dim_c_mm="+str(setting_c.value())+cr ) 
        file.write ("Time             " + "X             " + "Y             " + "X/c               " + "Y/ab            "+"photo        "+cr )
        file.write(DATA)
        file.close()
        #DATA2=str(np.column_stack((X[-len(Y2):],Y2,Xc[-len(Y2):],Yab[-len(Y2):],FOTO[-len(Y2):]))).replace("\n","").replace(" [","").replace("]","\n").replace("[[","").replace(" ","\t").replace("+","")
        #print(DATA2)
        #file.write(version)
        #file.write("filename="+fname+cr)
        #file.write("x(mouse)_sensor="+setting_xsensor.value()+cr )
        #file.write("xsensor_constant="+str(setting_xsensor_constant.value())+cr )
        #file.write("y(analog)_sensor="+setting_ysensor.value()+cr )
        #file.write("ysensor_constant="+str(setting_ysensor_constant.value())+cr )
        #file.write("sample_dim_a_mm="+str(setting_a.value())+cr )
        #file.write("sample_dim_b_mm="+str(setting_b.value())+cr )
        #file.write("sample_dim_c_mm="+str(setting_c.value())+cr ) 
        #file.write ("X             " + "Y             " + "X/c               " + "Y/ab            "+"photo        "+cr )
        #file.write(DATA2)
        #file.close()
        
        #ax.plot(T,Yab)
        ##plt.ylabel("compressive stress (MPa)")
        #plt.show()
        #plt.savefig("plot")
        
        file=open(fname,"r")
        prt(file.read())
        file.close()

        msg = QtGui.QMessageBox()
        msg.setIcon(QtGui.QMessageBox.Question)
        msg.setText("Saved to:\n"+datadir+"/\n"+fnameshort)
        prt("Saved to "+fname)
        msg.setWindowTitle("Save")
        msg.setStandardButtons(QtGui.QMessageBox.Ok)
        msg.setFont(msgfont)
        msg.exec_()

    if button_setting_dir.isDown():        
        prt ("set dir")
        dir_ = QtGui.QFileDialog.getExistingDirectory(None, 'Select a folder:', 'C:\\', QtGui.QFileDialog.ShowDirsOnly)
        if dir_:
            datadir=dir_
            setting_dir.setText(datadir)
            
    #xmin,xmax=plot_widget.getAxis("bottom").range
    #ymin,ymax=plot_widget.getAxis("left").range
    p1.setData(y=Y, x=T)
    #text.setPos((xmax-xmin)/10+xmin,ymax-(ymax-ymin)/10)

config_xsensor()
config_ysensor()
reset()

######### Start a timer to rapidly update the plot in plot_widget
t = QtCore.QTimer()
t.timeout.connect(read_and_updateData)
t.start(50)


########### Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
    import sys
    starttime=tm.time()
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()
        