from IPython.core.display import (
    display,
    HTML,
)

"""
Explanation: bind and this in JavaScript
Excerpts from bind and this - Object Creation in JavaScript P1 - FunFunFunction #43 by @mpjme
Meta preparation for this blog post to make the video excerpts display in a Jupyter notebook and then blog post.
tl; dr;
Jumpt to the start.
As a blog post writer, I want to display html text into a cell.
So I need to import objects as follows:
End of explanation
"""


def convert_to_seconds_from(timestring, delimiter=":"):
    """Convert a timestring to seconds.
    
    :timestring: HH:MM:SS as a str
    :returns: seconds as int
    """
    return sum(
        # raise 60 to power of i in (0, 1, 2) and
        # multiply it by seconds, minutes and then hours
        int(time_value) * (60 ** i)
        for i, time_value 
        in enumerate(reversed(timestring.split(delimiter)))
    )

"""
Explanation: As a blog post writer, I want to embed YouTube video excerpts with a start and end. 
The embed URL takes a start and end argument as an integer in seconds.
So I need a function to convert a time string into seconds.
End of explanation
"""


def get_embed_string_from(excerpt, video_url='https://www.youtube.com/embed/GhbhD1HR5vk'):
    """Create some HTML to display the YouTube video excerpts."""
    EMPTY_STRING = ''
    label, times = excerpt
    start_stop = ['<br/>'.join([': '.join(item for item in items if item)]) 
                  for items in zip(('start', 'end'), times)]
    start_stop = EMPTY_STRING.join(["<p>{}</p>".format(item) for item in start_stop])\
        if all(times) else EMPTY_STRING
    embeded_video_template = ''.join((
            '<h3>{label}</h3>',
            '{start_stop}',
            '<br/>',
            '<iframe width="560" height="315" ',
            'src="{video_url}?rel=0&start={start}&end={end}" ',
            'frameborder="0" allowfullscreen></iframe>',
    ))
    start, end = [convert_to_seconds_from(item) for item in times]\
        if all(times) else times
    return embeded_video_template.format(
        video_url=video_url,
        label=label,
        start_stop=start_stop,
        start=start,
        end=end
    )

"""
Explanation: As a blog post writer, I want to embed YouTube video excerpts.
This requires creating formatted html to display.
So I need a function to create them html based on my excerpt values.
End of explanation
"""


display(HTML('<span id="excerpts"></span>'))

video_excerpts = (
    ('Why begin with \'this\' and \'bind\'?', ('00:00:54', '00:01:17'), ),
    ('Your soul will want JS to be like Python.', ('00:02:20', '00:02:35'),),
    ('A dog literal object.', ('00:05:15', '00:06:48'), ),
    ('What the fuck shit ass? It means you\'re learning.', ('00:06:49', '00:07:04'),),
    ('JavaScript is this bastard child of Java and Scheme.', ('00:08:39', '00:09:08'), ),
    ('Clash between object oriented and functional paradigms.', ('00:10:05', '00:11:14'), ),
    ('Binding \'dog\' to \'this\'.', ('00:11:40', '00:13:00'), ),
    ('A real life example of using bind.', ('00:13:25', '00:14:16'), ),
    ('The entire video.', ('', ''), ),

)
keys, _ = zip(*video_excerpts)
video_excerpts_map = dict(zip(keys, video_excerpts))

"""
Explanation: Record the start and stop times of interest.
End of explanation
"""


display(HTML('<span id="start"></span>'))

display(HTML(get_embed_string_from(video_excerpts_map['Why begin with \'this\' and \'bind\'?'])))

display(HTML(get_embed_string_from(video_excerpts_map['A dog literal object.'])))

display(HTML('<span id="fuck-shit-ass"></span>'))
display(HTML(get_embed_string_from(video_excerpts_map['What the fuck shit ass? It means you\'re learning.'])))

"""
Explanation: Display the excerpts in the notebook which in turn renders them into the blog post after Pelican processes them.
End of explanation
"""


# create an anchor
display(HTML('<span id="call_unbound"></span>'))

# calling an "unbound" method
class MyClass(object):
    def my_function(self):
        return "'{}' was called.\nself == {}".format(self.my_function, self)

print('MyClass.my_function: ', MyClass.my_function)
try:
    MyClass.my_function()
except TypeError as e:
    print('Error when calling "unbound" function "my_function":', TypeError(e))
# The exception is not raised when called on an instance.
my_class = MyClass()
print("MyClass: ", my_class)
print("Calling my_class.my_function", my_class.my_function())

"""
Explanation: Calling an object literal's function in isolation. See the JavaScript code in a Node.js notebook here.
What is a "bound method" in Python?

StackOverflow discussion


Since the difference between a function and an unbound method is pretty minimal, Python 3 gets rid of the distinction; under Python 3 accessing a function on a class instance just gives you the function itself.

Though an exception will be raised if you call a class method on a class itself before instantiating it.
End of explanation
"""


display(HTML('<span id="bastard-child"></span>'))
display(HTML(get_embed_string_from(video_excerpts_map['JavaScript is this bastard child of Java and Scheme.'])))

display(HTML('<span id="clash"></span>'))
display(HTML(get_embed_string_from(video_excerpts_map['Clash between object oriented and functional paradigms.'])))

display(HTML('<span id="real-life-example"></span>'))
display(HTML(get_embed_string_from(video_excerpts_map['A real life example of using bind.'])))

# the entire video
display(HTML(get_embed_string_from(video_excerpts_map['The entire video.'])))

"""
Explanation: Note that after instantiating an object from class "MyClass" the "my_function" function becomes a "bound method" which means that a first positional argument is expected to be 'self' aka the object instance. 
bound method MyClass.my_function of main.MyClass object at 0x7fe0145ae438>
Python takes care of this and always passes an instance of the class aka MyClass object at… in the first position of bound methods.
JavaScript is a bastard child of Java (object oriented paradigm) and Scheme (functional paradigm).
End of explanation
"""


for video_excerpt in video_excerpts:
    html = get_embed_string_from(video_excerpt)
    html = HTML(html)
    display(html)

"""
Explanation: All the excerpts.
End of explanation
"""


