#!/usr/bin/python
"""Generates text that repeatedly affirms in different ways."""

__author__ = 'Nick Montfort <http://nickm.com>'
__version__ = '1.0'
__license__ = 'MIT'

# Written for the UCSD Software Studies Workshop, 21 May 2008.
# Thanks to Ralph Lombreglia, who discussed the program with me.
# Also, thanks to my students in "The Word Made Digital," MIT,
# Spring 2008 for commenting on and playing with the first voice.

from sys import stdout
from random import choice, randint
from time import sleep, localtime, time

# These two utility functions are used by the "voices" below, which 
# are otherwise independent.

def s():
	return choice([" is","'s"])

def finish(string, punct):
    # To avoid lowercasing the rest of the string, don't use
    # capitalize(), just uppercase the first letter.
    return string[0].upper() + string[1:] + punct + " "

# The different voices. Can be used to do the police.

def said_that():
    """Affirm having said that."""
    bland = ["indeed","exactly","certainly","precisely", \
	    "definitely","without doubt","of course","absolutely", \
	    "without question","by all means"]
    longer = choice( \
        ["that" + s() + " " + choice(bland) + " what I said", \
        choice(bland) + ", I said that", \
        "I " + choice(bland) + " said that"])
    full = choice(["yes","yes, "+longer,longer])
    return finish(full, ".")

def believe():
    """Affirm belief."""
    strong = ["totally","wholly","entirely","absolutely", \
	    "fully","unconditionally"]
    longer = choice( \
        ["I believe", \
        "my " + choice(["heart", "soul"]) + " believes", \
        "I " + choice(strong) + " believe"])
    holy_word = choice( ["hallelujah", "hallelujah in the highest", \
        "amen"] )
    full = choice(["yes","yes, "+longer,longer,holy_word])
    return finish(full, choice(["!","."]))

def writing():
    """Affirm that this is writing."""
    intensifier = ["indeed ","certainly ","definitely ", \
        "without doubt ","of course ","without doubt ", \
        "by all means ",""]
    form_of = ["a form of ","a manner of ","some type of ",""]
    writing_etc = ["writing","textual production","inscription"]
    longer = choice( \
        ["this is " + choice(intensifier) + choice(form_of) + \
         choice(writing_etc), ])
    full = choice(["yes","yes, "+longer,longer])
    return finish(full, ".")

def just_yes():
    """Affirm by just saying yes."""
    yes_word = "yes"
    punctuation = choice([" ..."*randint(1,3),".","?"])
    if randint(0,4) == 0:
        yes_word = "y" + "e"*randint(2,6) + "s"
        punctuation = "?"
    return finish(yes_word, punctuation)

def can_do():
    """Affirm that the speaker can do it."""
    can = ["I can","I can","I can do it","I have it in me", \
        "I can succeed","I will succeed"]
    maxim = ["every day in every way","there is no try", \
        "work hard, play hard","it's win-win","for the shareholder"]
    full = choice(["yes","yes "+choice(can),choice(can), \
        choice(maxim)])
    return finish(full, ".")

def did_it():
    """Affirms that the speaker did indeed do it."""
    did = ["I did","I did","I did it","I did it", \
        "I'm the one who did it","it was me"]
    admit = ["I admit","I'm admitting that","I don't deny that"]
    full = choice(["yes","yes, "+choice(did),choice(did), \
        choice(admit) + " " + choice(did)])
    return finish(full, ".")

def exhilarated():
    """Affirm wildly -- our team scored a point or something?"""
    exclamation = ["yeah","oh yeah","yeah baby","woohoo","woot", \
        "yeeehah","yeah man","all right"]
    full = choice(exclamation)
    sentence = finish(full, "!")
    if randint(0,4) == 0:
        sentence = sentence.upper()
    return sentence

def did_that_one():
    """Affirm that the speaker killed people."""
    did = ["I did","I sure did","I did that one", \
        "I'm the one who did it","it was me"]
    year = choice(["back ",""]) + "in 198" + str(randint(3,9))
    place = choice(["at that rest stop","near the truck stop",\
        "just outside of town"])
    full = choice(["yes","yes, "+choice(did),choice(did), \
        "I'm telling you that " + choice(did)])
    if randint(0,5) == 0:
        full = full + ", " + choice([year,place])
    return finish(full, ".")
	
def identify():
    """Affirm the identification of some male person."""
    terse = [""," certainly"," definitely"]
    longer = choice( \
        ["that" + s() + choice(terse) + " him", \
        "I" + choice(["'m sure I"," do"]) + " recognize him", \
        "it's him"])
    positive = "I'm " + choice( ["positive","sure","certain"] )
    full = choice(["yes","yes, "+longer,longer,positive])
    return finish(full, ".")

def great_idea():
    """Affirm that you, boss, have a great idea."""
    good_plan = ["I agree","great idea","sure","that sounds great", \
        "good plan"]
    boss = ["boss","sir"]
    full = choice(["yes","yes, "+choice(good_plan), \
        choice(good_plan) + ", " + choice(boss)])
    return finish(full, ".")

def time_is():
    """Affirm (deterministically) that it is the current time."""
    h = localtime().tm_hour % 12
    m = localtime().tm_min
    s = localtime().tm_sec
    half = ["morning","afternoon"][localtime().tm_hour > 12]
    hour = str(h)
    minute = str(m)
    if len(minute) < 2:
        minute = "0" + minute
    second = ["exactly","and fifteen seconds","and thirty seconds", \
        "and forty-five seconds"][s / 15]
    if s % 15 == 0:
        if time() % 1 <= .2 :
            full = "yes, right now, this " + half + ", it is " + \
                hour + ":" + minute + " " + second
            if h == 4 and m == 20 and second == "exactly":
                full += " -- blaze up"
        else:
            full = "it is"
    else:
        if time() % 1 <= .2 :
            full = "yes indeed"
        else:
            full = ["yep","yes","sure","mhm","yeah"][s % 5]
        if int((time() % 1) * 100) % 7 == 0:
            full += ", " + hour + ":" + minute
    return finish(full, ".")

def ecstatic():
    """Affirm ecstatically."""
    many_yeses = ("yes " * randint(1,8))[:-1]
    god = choice(["god", "oh god", "oh my god"])
    full = choice([god, god + " yes", many_yeses, "yes " + \
        choice(["right there","like that"])])
    return finish(full, ".")

def went_out():
    """Affirm that the speaker did go out with him and her and ..."""
    er = ["truth is, ","well, ","er, ","um, "]
    ers = choice(er) * randint(0,2)
    him_or_her = ["him","her"]
    he_or_she = ["he","she"]
    also = ["too","also","as well"]
    dated = ["dated","went out","had a thing"]
    dated_with = ["dated","went out with","had a thing with"]
    longer = choice(["we "+choice(dated), \
        choice(he_or_she)+" "+choice(dated_with)+" me", \
        "I "+choice(dated_with)+" "+choice(him_or_her)])
    full = choice(["yes",ers+"yes",ers+"yes, "+longer,ers+"yes, "+ \
        longer+" "+choice(also)])
    return finish(full, ".")

def correct():
    """Affirm that you got the right answer."""
    totally = ["is totally","is","sure is"]
    longer = choice( \
        ["that's it","that's right","correct","you are correct", \
        "that " + choice(totally) + " right"])
    praise = choice( ["very good", "excellent", "good work", \
        "nice job"] )
    full = choice(["yes","yes, "+longer,longer,praise])
    return finish(full, choice(["!","."]))

def thats_it():
    """Affirm that this is the end."""
    the_end = ["that's it","this is it","this is the end", \
        "finished","the end","that's all"]
    yes = ["yep","yes","yeah"]
    full = choice([choice(yes),choice(yes)+", "+choice(the_end), \
        choice(the_end)])
    return finish(full, ".")

# If the program is run from the command line, run the "slides"
# to accompany the 21 May 2008 Software Studies talk.
#
# Otherwise it can be imported and the methods can be called
# individually.

if __name__ == '__main__':

    tick = .2 # Number of seconds (can be fractional) between utterances
    section_length = 100 # Number of utterances per section
    code_tick = .27 # Go through the code a bit more slowly

    opening = ["","My Generation about Talking","", \
        "Nick Montfort","MIT","","Software Studies Workshop", \
        "UCSD","21 May 2008",""]
    for line in opening:
        stdout.write("  " + line + "\n")
        sleep(2)

    # The methods that are the different voices are placed in a list.
    # This makes it possible to use the first method, at index 0,
    # and pop off that method when it's time to move to a new voice.
    
    voices = [said_that, believe, writing, just_yes, can_do, \
              did_it, exhilarated, did_that_one, identify, \
              great_idea, time_is, ecstatic, went_out, correct, \
              thats_it]

    # The main loop, which continues as long as there is at least one 
    # voice left in the voices list. After section_length iterations, 
    # iterations % section_length will be so, so two newlines will be 
    # printed and the first voice in the list will be popped off.

    iteration = 0

    while (len(voices) > 0):
        iteration += 1
        text = voices[0]()
        if iteration % section_length == 0:
            text += "\n\n"
            voices.pop(0)
        stdout.write(text)
        # With write() and sleep() it seems necessary to flush the output
        # buffer to ensure that what is in it actually gets written out.
        stdout.flush()
        # sleep() isn't a very accurate way to pause, but works well
        # enough in this program.
        sleep(tick)

    # Print the program itself.
    
    code_lines = open("yes_voices.py","r").readlines()
    for line in code_lines:
        stdout.write(line)
        sleep(code_tick)
    stdout.write("\n\n")

#####################################################################
#
#  Copyright (c) 2008 Nick Montfort
#
#  Permission is hereby granted, free of charge, to any person
#  obtaining a copy of this software and associated documentation
#  files (the "Software"), to deal in the Software without
#  restriction, including without limitation the rights to use,
#  copy, modify, merge, publish, distribute, sublicense, and/or sell
#  copies of the Software, and to permit persons to whom the
#  Software is furnished to do so, subject to the following
#  conditions:
#  
#  The above copyright notice and this permission notice shall be
#  included in all copies or substantial portions of the Software.
#  
#  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
#  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
#  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
#  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
#  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
#  OTHER DEALINGS IN THE SOFTWARE.
#
#####################################################################
