import paho.mqtt.client as mqtt
import paho.mqtt.client as paho
import RPi.GPIO as GPIO

from gpiozero import MotionSensor
from picamera import PiCamera
from time import sleep
from datetime import datetime
import time
import schedule
import base64
import threading

import smtplib
import imghdr
import subprocess
from email.message import EmailMessage


PIR = MotionSensor(4)
power = 8

GPIO.setup(power, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
quality =300

def on_connect( client, userdata, flags, rc):
    print ("Pripojene do CloudMQTT :" +str(rc))
    client.subscribe("Rpi/#",0)

variable = (time.strftime("%b-%d-%Y-%H-%M"))

def on_message_quality( client, userdaSSta, msg):
    message = msg.payload.decode(encoding='UTF-8')
    print(message)
    global quality
    
    if message == "550":
        quality=550
    elif message == "800":
        quality=800
    elif message == "1000":
        quality=1000
    elif message == "1500":
        quality=1500
    else:
        quality=300
        client.publish("Info/", "Go to settings to set better quality of the image")
    print(quality)

def on_message( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')

    if message == "pic":
        print("fotka")
        try:
            print(" ",quality)
            camera= PiCamera()
            camera.start_preview()
            sleep(2)
            global filename
            global foto
            foto= variable
            filename='/home/pi/Desktop/ImagePreview/preview-'+ foto +'.jpg'
            print("Fotka nazov: ", foto)
            camera.capture(filename, resize=(quality,quality))
            camera.stop_preview()
            pass
        finally:
            camera.close()
            image_data= open(filename, "rb")
            image_string = image_data.read()
            imageByteArray = bytes(image_string)
            client.publish("Info/","The object was captured. Wait for the preview!")
            client.publish("Photo/",imageByteArray, 0)
            print(imageByteArray)
            time.sleep(5)
    elif message == "ON":
        print("ON")
        client.publish("Detection/","Monitoring...")
        pub.resume()
    elif message == "OFF":
        pub.pause()
        print("OFF")
        client.publish("Detection/","Monitoring is OFF")
    elif message == "scheduleOff":
        print("scheduleOffOFF")
        client.publish("Info/","Schedule is OFF")
        schedule.clear('task')
    else:
        print("?!? Unknown message?!?")
        client.publish("Unknown/", "Unknown message. Try again :)")

def on_message_everyday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().day.at(message).do(jobStart, 'EveryDay').tag('task', 'every')

def on_message_everydayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at: ", message)
        schedule.every().day.at(message).do(jobEnd, 'EveryDay').tag('task', 'every')

def on_message_monday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().monday.at(message).do(jobStart, 'Monday').tag('task', 'monday')

def on_message_mondayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at: ", message)
        schedule.every().monday.at(message).do(jobEnd, 'Monday').tag('task', 'monday')

def on_message_tuesday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().tuesday.at(message).do(jobStart, 'Tuesday').tag('task', 'tuesday')

def on_message_tuesdayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at:", message)
        schedule.every().tuesday.at(message).do(jobEnd, 'Tuesday').tag('task', 'tuesday')

def on_message_wednesday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().wednesday.at(message).do(jobStart, 'Wednesday').tag('task', 'wednesday')

def on_message_wednesdayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at:", message)
        schedule.every().wednesday.at(message).do(jobEnd, 'Wednesday').tag('task', 'wednesday')


def on_message_thursday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().thursday.at(message).do(jobStart, 'Thursday').tag('task', 'thursday')

def on_message_thursdayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at:", message)
        schedule.every().thursday.at(message).do(jobEnd, 'Thursday').tag('task', 'thursday')

def on_message_friday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().friday.at(message).do(jobStart, 'Friday').tag('task', 'friday')

def on_message_fridayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at:", message)
        schedule.every().friday.at(message).do(jobEnd, 'Friday').tag('task', 'friday')


def on_message_saturday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().saturday.at(message).do(jobStart, 'Saturday').tag('task', 'saturday')

def on_message_saturdayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at:", message)
        schedule.every().saturday.at(message).do(jobEnd, 'Saturday').tag('task', 'saturday')

def on_message_sunday( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" starts at:", message)
        schedule.every().sunday.at(message).do(jobStart, 'Sunday').tag('task', 'sunday')

def on_message_sundayEnd( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    if message:
        print(" ends at:", message)
        schedule.every().sunday.at(message).do(jobEnd, 'Sunday').tag('task', 'sunday')


def on_message_mail( client, userdata, msg):
    message = msg.payload.decode(encoding='UTF-8')
    print("mail: ", message)
    if message=='mail':
    
        try:
            msg = EmailMessage()
            msg['Subject'] = 'ImagePreview'
            msg['From']= mailAdd
            msg['To'] = mailAdd
            msg.set_content('Here is your requested image preview')
            with open (filename, 'rb') as f:
               file_data = f.read()
               file_type = imghdr.what(f.name)
               file_name = foto
            msg.add_attachment(file_data, maintype='image',subtype=file_type, filename=file_name)
            with smtplib.SMTP_SSL('smtp.gmail.com', 465) as smtp:
                smtp.login(mailAdd, mailPass)
                smtp.send_message(msg)
            client.publish("Info/", "Email was sent")
        except:
            print("Something went wrong...")
            client.publish("Info/", "Unable to send email, check settings...")
def on_message_mail_address( client, userdata, msg):
    global mailAdd
    mailAdd = msg.payload.decode(encoding='UTF-8')
    print("mail address: ", mailAdd)

def on_message_mail_password( client, userdata, msg):
    global mailPass
    mailPass = msg.payload.decode(encoding='UTF-8')
    print("mail password: ", mailPass)

def jobStart(name):
    print("Scheduled on {}".format(name))
    pub.resume()
    client.publish("Detection/", "Has started according to your schedule")

def jobEnd(name):
    print("End of scheduled on {}".format(name))
    pub.pause()
    client.publish("Detection/", "Stopped according to your schedule")

client = mqtt.Client("xvasko")
client.on_connect = on_connect


client.username_pw_set("cqeopqjb","0ZilzPcY0rxh")
client.connect("34.250.16.30", 13237, 60)

class pubThread(threading.Thread):
    def __init__(self,threadId, name):
        threading.Thread.__init__(self)
        self.threadId = threadId
        self.name = name
        self.detect = threading.Event()
    def run(self):
        print("Starting: "+ self.name, "\n")
        while True:
            if self.detect.isSet():
                print(self.detect.isSet())
                detection()
        print("Exiting: "+ self.name)
    def pause(self):
        self.detect.clear()
    def resume(self):
        self.detect.set()

class powerThread(threading.Thread):
    def __init__(self,threadId, name):
        threading.Thread.__init__(self)
        self.threadId = threadId
        self.name = name
    def run(self):
        print("Starting: "+ self.name, "\n")
        while True:
            if GPIO.input(power) == 0:
                print("Power state is off: ")
                client.publish("Info/", "Power Outage!!!")
                sleep(1800)
            elif GPIO.input(power) == 1:
                print("Power state is: ",power)
                sleep(1800)
        print("Exiting: "+ self.name)


class subThread(threading.Thread):
    def __init__(self,threadId, name):
        threading.Thread.__init__(self)
        self.threadId = threadId
        self.name = name
    def run(self):
        print("Starting: "+ self.name, "\n")
        client.on_message = on_message
        client.message_callback_add('Rpi/EveryDay/#', on_message_everyday)
        client.message_callback_add('Rpi/EveryDayEnd/#', on_message_everydayEnd)
        client.message_callback_add('Rpi/Monday/#', on_message_monday)
        client.message_callback_add('Rpi/MondayEnd/#', on_message_mondayEnd)

        client.message_callback_add('Rpi/Tuesday/#', on_message_tuesday)
        client.message_callback_add('Rpi/TuesdayEnd/#', on_message_tuesdayEnd)

        client.message_callback_add('Rpi/Wednesday/#', on_message_wednesday)
        client.message_callback_add('Rpi/WednesdayEnd/#', on_message_wednesdayEnd)

        client.message_callback_add('Rpi/Thursday/#', on_message_thursday)
        client.message_callback_add('Rpi/ThursdayEnd/#', on_message_thursdayEnd)

        client.message_callback_add('Rpi/Friday/#', on_message_friday)
        client.message_callback_add('Rpi/FridayEnd/#', on_message_fridayEnd)

        client.message_callback_add('Rpi/Saturday/#', on_message_saturday)
        client.message_callback_add('Rpi/SaturdayEnd/#', on_message_saturdayEnd)

        client.message_callback_add('Rpi/Sunday/#', on_message_sunday)
        client.message_callback_add('Rpi/SundayEnd/#', on_message_sundayEnd)


        client.message_callback_add('Rpi/Mail/#', on_message_mail)
        client.message_callback_add('Rpi/Address/#', on_message_mail_address)
        client.message_callback_add('Rpi/Password/#', on_message_mail_password)

        client.message_callback_add('Rpi/Quality/#', on_message_quality)

        client.loop_forever()
        print("Exiting: "+ self.name)

def detection():
    PIR.wait_for_motion()
    if not pub.detect.isSet():
        return
    client.publish("Motion/","Motion detected!")
    print("Pohyb zdetekovany!")
    sleep(10)
    if PIR== 1:
         client.publish("Motion/","Motion detected!")
    else:
         client.publish("Motion/","Motoring...")

pub = pubThread(1, "PubThread")
sub = subThread(2, "SubThread")
powerCheck= powerThread(3, "PowerThread")


sub.start()
pub.start()
powerCheck.start()

while 1:
    schedule.run_pending()
    time.sleep(1)


client.disconenect()