#!/usr/bin/env python3
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Run a recognizer using the Google Assistant Library.

The Google Assistant Library has direct access to the audio API, so this Python
code doesn't need to record audio. Hot word detection "OK, Google" is supported.

The Google Assistant Library can be installed with:
    env/bin/pip install google-assistant-library==0.0.2

It is available for Raspberry Pi 2/3 only; Pi Zero is not supported.
"""

import logging
import subprocess
import sys
import feedparser   #used for getting podcasts (not implemented yet).

import aiy.assistant.auth_helpers
import aiy.audio
import aiy.voicehat
import RPi.GPIO as gpio
import time

import datetime
import email
import imaplib
import mailbox


EMAIL_ACCOUNT = " @gmail.com"
PASSWORD = " password"

from google.assistant.library import Assistant
from google.assistant.library.event import EventType



logging.basicConfig(
    level=logging.INFO,
    format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)


def power_off_pi():
    aiy.audio.say('Good bye!')
    subprocess.call('sudo shutdown now', shell=True)


def reboot_pi():
    aiy.audio.say('See you in a bit!')
    subprocess.call('sudo reboot', shell=True)

def volume(change):

    """Changes the volume and says the new level."""

    GET_VOLUME = r'amixer get Master | grep "Front Left:" | sed "s/.*\[\([0-9]\+\)%\].*/\1/"'
    SET_VOLUME = 'amixer -q set Master %d%%'

    res = subprocess.check_output(GET_VOLUME, shell=True).strip()
    try:
        logging.info("volume: %s", res)
        vol = int(res) + change
        vol = max(0, min(100, vol))
        subprocess.call(SET_VOLUME % vol, shell=True)
        aiy.audio.say('Volume at %d %%.' % vol)
    except (ValueError, subprocess.CalledProcessError):
        logging.exception("Error using amixer to adjust volume.")


def volume_up():
    volume(10)


def volume_down():
    volume(-10)


def text2int(textnum, numwords={}):
    if not numwords:
        units = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight","nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" ]

        tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]

        scales = ["hundred", "thousand", "million", "billion", "trillion"]

    numwords["and"] = (1, 0)
    for idx, word in enumerate(units):    numwords[word] = (1, idx)
    for idx, word in enumerate(tens):     numwords[word] = (1, idx * 10)
    for idx, word in enumerate(scales):   numwords[word] = (10 ** (idx * 3 or 2), 0)

    current = result = 0
    for word in textnum.split():
        if word not in numwords:
          raise Exception("Illegal word: " + word)

        scale, increment = numwords[word]
        current = current * scale + increment
        if scale > 100:
            result += current
            current = 0

    return result + current
# print (text2int("seven billion one hundred million thirty one thousand three hundred and thirty seven"))


    
def play_from_youtube():
    global T_text
    global playshell
    track = T_text[5:]   # this gets rid of play_ in the command
    #
    # check if a specificied duration was requested (
    # if text = [a song] for fifteen minutes" then remove last two workds from
    #           search string and calculate the number of minutes at which the song
    #           should be stopped.
    #


##

    numwords ={}
    #track =("mozart three hundred thirty seven minutes")
    #print(track)
        #print(track.endswith("minutes"))
    if track.endswith("minutes"):
        timer_set = True  #minutes of play specified so timer is in use. 
        #specified play duration detected
        #print("string detected")
        track = track[:-8] #(" minutes","")  # gets rid of "_minutes" from end of string
        print (track)
        track_a= track.split(" ")
        print(track_a)
        print("array length = ", len(track_a))
        track_a.reverse()
        if not (track_a[0].isdigit()):
                    
            for i in range (len(track_a)):
                print( i, track_a[i])

            if not numwords:
                units = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight","nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" ]

                tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]

                scales = ["hundred", "thousand", "million", "billion", "trillion"]

            numwords["and"] = (1, 0)
            for idx, word in enumerate(units):    numwords[word] = (1, idx)
            for idx, word in enumerate(tens):     numwords[word] = (1, idx * 10)
            for idx, word in enumerate(scales):   numwords[word] = (10 ** (idx * 3 or 2), 0)

            i=-1
            for word in track_a:
                i =i +1
                if word not in numwords:
                  print (i, track_a[i]) # raise Exception("Illegal word: " + word)
                  first_word_w_number = i
                  break
            print("the last ",  first_word_w_number, " words have text numbers in them. ")
            print("the first text number = ", track_a[first_word_w_number])
            track_a.reverse()
            x=0
            numbers_str=""
            for i in range (len(track_a)-first_word_w_number,len(track_a),1):
                numbers_str = numbers_str + track_a[i] + " " 
                print(i, track_a[i])
                x = x +1
                
        #        if (len(track_a) -i)>= first_word_w_number-2:
        #            numbers_str[x] = track_a[i]
                    
        #       numbers_str_a now has the textstring which need to be joined a then subracted from  original track to have track seperate from time play duration


            
                    
            print (track_a, numbers_str)


            #numbers_str= " ",join(numbers_str_a([0,first_word_w_number])
            x= len(numbers_str)
            track = track[:-x]
        #   get rid of white spaces
            track = track.strip()
            numbers_str = numbers_str.strip()
        #   convert to integer
            time_to_play = text2int(numbers_str,numwords ={})
            print(track)
            print(numbers_str)#, " and voila .... integer = ", time_to_play)
            print (time_to_play)

        else:
            # word string was an acual ascii number alreay, reconstitute string.
            print(track_a[0])
            time_to_play = int(track_a[0])  # this should have strin of aci in i it
            x = len (track_a[0])
            track = track[:-(x+1)]  # there is a space in front of asci number to get rid of this (+1)
            print(track)
            print (time_to_play)
    else: # no minutes duration of play was specified.
        timer_set= False
        

##
    #print(track)
    if (playshell == None):
        print('trying to play music')
        playshell = subprocess.Popen(["/usr/local/bin/mpsyt",""],stdin=subprocess.PIPE ,stdout=subprocess.PIPE)

    playshell.stdin.write(bytes('/' + track + '\n1\n', 'utf-8'))
    playshell.stdin.flush()

    gpio.setmode(gpio.BCM)
    gpio.setup(23, gpio.IN)
    pla_status = "VLC is starting"
    #loop_cont = true





    x=0
    i=0
    while (gpio.input(23)):
        
        try:
            t_done =subprocess.check_output(["ps", "-C", "vlc"])
        except subprocess.CalledProcessError as e:
            t_done= e.output #output generated before error
            code        =e.returncode
        
            
        #t_done = subprocess.Popen.poll(vlc)
        t_done_text=t_done.decode('utf-8')
        
    
        if (t_done_text[-4:-1 ]== "vlc"):
            pla_status = "VLC is playing"
            
        elif (pla_status == "VLC is playing"):
            pla_status = "VLC done"
            print(pla_status)
            break

        time.sleep(1)
        x = x+1
        if x >= 59:
            #minute is up
            x=0
            i= i+1  #minute counter
        if (timer_set): # minutes play time was incountered in track string so use counter-timer
            if (i>=time_to_play):
                #stop VLC playing subprocess by exiting the while loop.
                print (time_to_play, " minutes timer is up.... exiting VLC player")
                break
        
        
    if (pla_status != "VLC done"):
        # button push before player was done so kill player which is running
        pkill = subprocess.Popen(["/usr/bin/pkill","vlc"],stdin=subprocess.PIPE)
        print("player  stopped")

def go_and_grab_list_from_latest_unread_email():
    global T_text
    playshell = None
    mail = imaplib.IMAP4_SSL('imap.gmail.com')
    mail.login(EMAIL_ACCOUNT, PASSWORD)
    mail.list()
    mail.select('inbox')
    result, data = mail.uid('search', None, "UNSEEN") # (ALL/UNSEEN)
    j = len(data[0].split())

    for k in range(j):
        latest_email_uid = data[0].split()[k]
        result, email_data = mail.uid('fetch', latest_email_uid, '(RFC822)')
        # result, email_data = conn.store(num,'-FLAGS','\\Seen') 
        # this might work to set flag to seen, if it doesn't already
        raw_email = email_data[0][1]
        raw_email_string = raw_email.decode('utf-8')
        email_message = email.message_from_string(raw_email_string)

        # Header Details
        date_tuple = email.utils.parsedate_tz(email_message['Date'])
        if date_tuple:
            local_date = datetime.datetime.fromtimestamp(email.utils.mktime_tz(date_tuple))
            local_message_date = "%s" %(str(local_date.strftime("%a, %d %b %Y %H:%M:%S")))
        email_from = str(email.header.make_header(email.header.decode_header(email_message['From'])))
        email_to = str(email.header.make_header(email.header.decode_header(email_message['To'])))
        subject = str(email.header.make_header(email.header.decode_header(email_message['Subject'])))

        # Body details
        for part in email_message.walk():
            if part.get_content_type() == "text/plain":
                body = part.get_payload(decode=True)
                file_name = "email_" + str(k) + ".txt"
                output_file = open(file_name, 'w')
                output_file.write("From: %s\nTo: %s\nDate: %s\nSubject: %s\n\nBody: \n\n%s" %(email_from, email_to,local_message_date, subject, body.decode('utf-8')))
                output_file.close()
                T_e_mailtext =body.decode('utf-8')
                T_e_mailtext_a =T_e_mailtext.split("\r")
                print(T_e_mailtext_a)
                for m in range(0,(len(T_e_mailtext_a) -1)):
                    T_e_mailtext_a[m] = T_e_mailtext_a[m].strip()
                    print("now playing :  ", T_e_mailtext_a[m])
                    T_text = "play " + T_e_mailtext_a[m]
                    time.sleep(3)  # give vlc player 3 seconds to shut down before starting next song
                    # fire up youtobe search for track.
                    play_from_youtube()
                    
                    #hopefully the program comes back to continue from here after being done playing youtube music
                    
                #print(T_e_mailtext_a)
                
            else:
                continue    
    


                                     
def play_podcast():
    #this is where it goes.
    aiy.audio.say("Podcast search has not been set up yet")
    

def say_laws_of_robotics():
    global T_text
    print(T_text)
    aiy.audio.say("The laws of robotics are:")
    aiy.audio.say("A robot may not injure a human being or, through inaction, allow a human being to come to harm.")
    aiy.audio.say("A robot must obey orders given it by human beings except where such orders would conflict with the First Law.")
    aiy.audio.say("A robot must protect its own existence as long as such protection does not conflict with the First or Second Law.")
    aiy.audio.say(". And finally,, Christian is always right!!!")

def say_ip():
    ip_address = subprocess.check_output("hostname -I | cut -d' ' -f1", shell=True)
    aiy.audio.say('My IP address is %s' % ip_address.decode('utf-8'))


def process_event(assistant, event):
    global T_text
    global playshell
    status_ui = aiy.voicehat.get_status_ui()
    if event.type == EventType.ON_START_FINISHED:
        status_ui.status('ready')
        if sys.stdout.isatty():
            print('Say "OK, Google" then speak, or press Ctrl+C to quit...')

    elif event.type == EventType.ON_CONVERSATION_TURN_STARTED:
        status_ui.status('listening')

    elif event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED and event.args:
        print('You said:', event.args['text'])
        text = event.args['text'].lower()
        T_text = text
        print (T_text)
        if text == 'power off':
            assistant.stop_conversation()
            power_off_pi()
        elif text == 'reboot':
            assistant.stop_conversation()
            reboot_pi()
        elif text == 'volume up':
            assistant.stop_conversation()
            volume_up()
        elif text == 'volume down':
            assistant.stop_conversation()
            volume_down()            
        elif T_text[:4] == 'play':
            assistant.stop_conversation()
            playshell = None
            play_from_youtube()
        elif text == 'read and play email':
            assistant.stop_conversation()
            playshell = None
            go_and_grab_list_from_latest_unread_email()
        elif text == 'play podcast':
            assistant.stop_conversation()
            play_podcast()
        elif text == 'three laws of robotics':
            assistant.stop_conversation()
            say_laws_of_robotics()            
        elif text == 'ip address':
            assistant.stop_conversation()
            say_ip()

    elif event.type == EventType.ON_END_OF_UTTERANCE:
        status_ui.status('thinking')

    elif event.type == EventType.ON_CONVERSATION_TURN_FINISHED:
        status_ui.status('ready')

    elif event.type == EventType.ON_ASSISTANT_ERROR and event.args and event.args['is_fatal']:
        sys.exit(1)
        
#def _on_button_pressed():
#    radio_off()

def main():
    credentials = aiy.assistant.auth_helpers.get_assistant_credentials()
    with Assistant(credentials) as assistant:
        for event in assistant.start():
            process_event(assistant, event)


if __name__ == '__main__':
    main()
