#!/usr/bin/env python

from __future__ import (
    unicode_literals,
    absolute_import,
    print_function,
    division,
    )
native_str = str
str = type('')

import sys
PY2 = sys.version_info.major == 2
import io
import os
import shutil
from subprocess import Popen, PIPE
from struct import Struct
from threading import Thread
from time import sleep, time, strftime

from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
from wsgiref.simple_server import make_server

import picamera
from ws4py.websocket import WebSocket
from ws4py.server.wsgirefserver import WSGIServer, WebSocketWSGIRequestHandler
from ws4py.server.wsgiutils import WebSocketWSGIApplication

import subprocess
import signal
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(4, GPIO.IN, GPIO.PUD_UP)
GPIO.add_event_detect(4, GPIO.FALLING)
GPIO.setup(25, GPIO.IN, GPIO.PUD_UP)
GPIO.add_event_detect(25, GPIO.FALLING)
GPIO.setup(8, GPIO.OUT, initial=0)
GPIO.setup(7, GPIO.OUT, initial=0)
GPIO.setup(32, GPIO.OUT, initial=False)

zvon = False;

import socket
import fcntl
import errno
from thread import *
host = ''
port = 5000;
kom = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ('Socket created')


try:
    kom.bind((host, port))

except (socket.error, msg):
    print ('Bind failed. Error Code: ' + str(msg[0]) + ' Message ' + msg[1])
    sys.exit();
    
print ('Socket bind complete')

WIDTH = 320
HEIGHT = 240
FRAMERATE = 24
HTTP_PORT = 8082
WS_PORT = 8084
JSMPEG_MAGIC = b'jsmp'
JSMPEG_HEADER = Struct(native_str('>4sHH'))

imagecount = 0

#-------------------------------------------------------------------------------
def lightthread(po):
    #p = GPIO.PWM(7, 50)
    GPIO.output(32, True)
    GPIO.output(7, True)
    #p.start(15)
    sleep(po)
    #p.stop()
    GPIO.output(7, False)
    GPIO.output(8, True)
    sleep(120)
    GPIO.output(8, False)
    GPIO.output(32, False)
    
def lightthread2(po):

    GPIO.output(8, True)
    sleep(120)
    GPIO.output(8, False)
    
#---socket-server---------------------------------------------------------------
def socketthread(kom):
    kom.listen(10)
    print ('Socket now listening')
    while 1:
        
        conn, addr = kom.accept()
        print ('Connected width ' + addr[0] + ': ' + str(addr[1]))
        fcntl.fcntl(conn, fcntl.F_SETFL, os.O_NONBLOCK)
      
        start_new_thread(clientthread ,(conn,)) 
    
def clientthread(conn):
    global zvon
    over=True;  
    while True:
        if zvon == over:
            over = not over
            data = (b'run')
            conn.sendall(data)
            sleep(1)
            
        try:
            msg = conn.recv(1024)
        except socket.error, e:
            continue
        else:
            print("clien_stop")
            break
    conn.close()
    
#----------------------------------------------------------------------------
class StreamingHttpHandler(BaseHTTPRequestHandler):
    def do_HEAD(self):
        self.do_GET()

    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
            return
        elif self.path == '/jsmpg.js':
            content_type = 'application/javascript'
            content = self.server.jsmpg_content
        elif self.path == '/index.html':
            content_type = 'text/html; charset=utf-8'
            content = self.server.index_template.replace(
                    '@ADDRESS@',
                    '%s:%d' % (self.request.getsockname()[0], WS_PORT))
        else:
            self.send_error(404, 'File not found')
            return
        content = content.encode('utf-8')
        self.send_response(200)
        self.send_header('Content-Type', content_type)
        self.send_header('Content-Length', len(content))
        self.send_header('Last-Modified', self.date_time_string(time()))
        self.end_headers()
        if self.command == 'GET':
            self.wfile.write(content)


class StreamingHttpServer(HTTPServer):
    def __init__(self):
        # Eurgh ... old-style classes ...
        if PY2:
            HTTPServer.__init__(self, ('', HTTP_PORT), StreamingHttpHandler)
        else:
            super(StreamingHttpServer, self).__init__(
                    ('', HTTP_PORT), StreamingHttpHandler)
        with io.open('index.html', 'r') as f:
            self.index_template = f.read()
        with io.open('jsmpg.js', 'r') as f:
            self.jsmpg_content = f.read()


class StreamingWebSocket(WebSocket):
    def opened(self):
        self.send(JSMPEG_HEADER.pack(JSMPEG_MAGIC, WIDTH, HEIGHT), binary=True)
        po = 0
        start_new_thread(lightthread2,(po,))
#--------------------------------------------------------------------------------------------------------
class BroadcastOutput(object):
    def __init__(self, camera):
        print('Spawning background conversion process')
        self.converter = Popen([
            'avconv',
            '-f', 'rawvideo',
            '-pix_fmt', 'yuv420p',
            '-s', '%dx%d' % camera.resolution,
            '-r', str(float(camera.framerate)),
            '-i', '-',
            '-f', 'mpeg1video',
            '-b', '800k',
            '-r', str(float(camera.framerate)),
            '-'],
            stdin=PIPE, stdout=PIPE, stderr=io.open(os.devnull, 'wb'),
            shell=False, close_fds=True)

    def write(self, b):
        self.converter.stdin.write(b)

    def flush(self):
        print('Waiting for background conversion process to exit')
        self.converter.stdin.close()
        self.converter.wait()


class BroadcastThread(Thread):
    def __init__(self, converter, websocket_server):
        super(BroadcastThread, self).__init__()
        self.converter = converter
        self.websocket_server = websocket_server

    def run(self):
        try:
            while True:
                buf = self.converter.stdout.read(512)
                if buf:
                    self.websocket_server.manager.broadcast(buf, binary=True)
                elif self.converter.poll() is not None:
                    break
        finally:
            self.converter.stdout.close()
            
#---------------------------------------------------------------------------------------------------------
def TakeUploadImage(camera):
    
    global imagecount
    filename = ('/home/pi/cache/image{'+ strftime('%Y-%m-%d-%H-%M') +'}'+ str(imagecount) +'.jpg')
    camera.capture(filename, use_video_port = True)
    imagecount = imagecount +1
    print (filename)

    cmd = ('/home/pi/Dropbox-Uploader/dropbox_uploader.sh upload ' + filename + ' \/')
    subprocess.call(cmd, shell=True)
    #os.remove(filename) 
     
#---------------------------------------------------------------------------------------------------------
def main():
    print('Initializing camera')
    global zvon
    with picamera.PiCamera() as camera:
        GPIO.output(32, True)
        camera.resolution = (WIDTH, HEIGHT)
        camera.framerate = FRAMERATE
        sleep(1) # camera warm-up time
        start_new_thread(socketthread,(kom,))
        print('Initializing websockets server on port %d' % WS_PORT)
        websocket_server = make_server(
            '', WS_PORT,
            server_class=WSGIServer,
            handler_class=WebSocketWSGIRequestHandler,
            app=WebSocketWSGIApplication(handler_cls=StreamingWebSocket))
        websocket_server.initialize_websockets_manager()
        websocket_thread = Thread(target=websocket_server.serve_forever)
        print('Initializing HTTP server on port %d' % HTTP_PORT)
        http_server = StreamingHttpServer()
        http_thread = Thread(target=http_server.serve_forever)
        print('Initializing broadcast thread')
        output = BroadcastOutput(camera)
        broadcast_thread = BroadcastThread(output.converter, websocket_server)
        print('Starting recording')
        camera.start_recording(output, 'yuv')
        GPIO.output(32, False)
        try:
            print('Starting websockets thread')
            websocket_thread.start()
            print('Starting HTTP server thread')
            http_thread.start()
            print('Starting broadcast thread')
            broadcast_thread.start()
            while True:
                camera.wait_recording(1)
                if GPIO.event_detected(25):
                    print('Button')
                    po = 60
                    start_new_thread(lightthread,(po,))
                    TakeUploadImage(camera)
                    zvon = not zvon
                                       
        except KeyboardInterrupt:
            pass
        finally:
            print('Stopping recording')
            camera.stop_recording()
            print('Stopping socket')
            kom.close()
            print('Waiting for broadcast thread to finish')
            broadcast_thread.join()
            print('Shutting down HTTP server')
            http_server.shutdown()
            print('Shutting down websockets server')
            websocket_server.shutdown()
            print('Waiting for HTTP server thread to finish')
            http_thread.join()
            print('Waiting for websockets thread to finish')
            websocket_thread.join()
            GPIO.cleanup()
            


if __name__ == '__main__':
    main()
