#
# Copyright (c) 2018 James Hume (www.jeh-tech.com). All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
#    This product includes software developed by James Hume (www.jeh-tech.com)
# 4. Neither the name "James Hume" or website "www.jeh-tech.com"
#    may be used to endorse or promote products derived from this software
#    without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
import matplotlib.pyplot as pl
import matplotlib.animation as animation
import itertools
import matplotlib.ticker as plticker

fig, ax = pl.subplots()

ax.set_xlim([-1,3])
ax.set_ylim([-1,3])
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')


grid2_colour='darkgray'
grid2_alpha=0.0
grid2 = []
for y1, y2 in zip(range(-8, 3), range(-2, 9)):
	l, = ax.plot([-3,3], [y1,y2], linewidth=1.0, color=grid2_colour, alpha=grid2_alpha)
	grid2.append(l)
for y1 in range(-2, 3):
	l, = ax.plot([-3,3], [y1,y1], linewidth=1.0, color=grid2_colour, alpha=grid2_alpha)
	grid2.append(l)


ax.plot([0, 2], [0, 2], color='r', alpha=0.75, zorder=2, lw=3)
loc = plticker.MultipleLocator(base=1.0)
ax.xaxis.set_major_locator(loc)
ax.yaxis.set_major_locator(loc)
ax.grid(False)

v1, = ax.plot([2, 2], [0, 1], color='lawngreen', zorder=2, lw=3, alpha=0.0, linestyle="--")
v2, = ax.plot([2, 2], [1, 2], color='lawngreen', zorder=2, lw=3, alpha=0.0, linestyle="--")

v3, = ax.plot([0, 1], [0, 0], color='lawngreen', zorder=2, lw=3, alpha=0.0, linestyle="--")
v4, = ax.plot([1, 2], [0, 0], color='lawngreen', zorder=2, lw=3, alpha=0.0, linestyle="--")

v5, = ax.plot([0, 1], [0, 1], color='lawngreen', zorder=2, lw=3, alpha=0.0, linestyle="--")
v6, = ax.plot([1, 2], [1, 2], color='lawngreen', zorder=2, lw=3, alpha=0.0, linestyle="--")

t1 = ax.text(2.1,2.1, r'$2\hat i + 2\hat j \rightarrow (2, 2)$', alpha=1.0, fontsize="13")
t2 = ax.text(2.1,2.1, r'$2\hat{v_1} + 0\hat{v_2}\rightarrow (2, 0)_B$', alpha=0.0, fontsize="13")

FRAME = 0
FPS=15
FADE_IN_TIME = FPS * 2 #2 seconds

def fade_in(step, total_steps, item):
	item.set_alpha(float(step)/float(total_steps))

def show(step, total_steps, item):
	item.set_alpha(1.0)

def hide(step, total_steps, item_array):
	for item in item_array:
		item.set_alpha(float(total_steps-step)/float(total_steps))

def grid1_on(step, total_steps, item_array):
	ax.grid(True, alpha=float(step)/float(total_steps))

def grid1_off(step, total_steps, item_array):
	ax.grid(False, alpha=float(total_steps-step)/float(total_steps))

def grid2_on(step, total_steps, item_array):
	for l in grid2:
		l.set_alpha(float(step)/float(total_steps))

def grid2_off(step, total_steps, item_array):
	for l in grid2:
		l.set_alpha(float(total_steps-step)/float(total_steps))

# Timeline - list of object - start time, end time
TIMELINE = [
	{'start' : 0 * FPS, 'end' : 1 * FPS -1, 'item' : v3, 'func' : grid1_on},
	{'start' : 0 * FPS, 'end' : 1 * FPS -1, 'item' : v3, 'func' : grid2_off},
	{'start' : 1 * FPS, 'end' : 2 * FPS -1, 'item' : v3, 'func' : fade_in},
	{'start' : 2 * FPS, 'end' : 3 * FPS -1, 'item' : v4, 'func' : fade_in},
	{'start' : 3 * FPS, 'end' : 4 * FPS -1, 'item' : v1, 'func' : fade_in},
	{'start' : 4 * FPS, 'end' : 5 * FPS -1, 'item' : v2, 'func' : fade_in},
	{'start' : 5 * FPS, 'end' : 6 * FPS -1, 'item' : [v1,v2,v3,v4,t1], 'func' : hide},
	{'start' : 6 * FPS, 'end' : 7 * FPS -1, 'item' : ax, 'func' : grid1_off},
	{'start' : 6 * FPS, 'end' : 7 * FPS -1, 'item' : ax, 'func' : grid2_on},
	{'start' : 6 * FPS, 'end' : 7 * FPS   , 'item' : t2, 'func' : show},
	{'start' : 7 * FPS, 'end' : 8 * FPS -1, 'item' : v5, 'func' : fade_in},
	{'start' : 8 * FPS, 'end' : 9 * FPS -1, 'item' : v6, 'func' : fade_in},
	{'start' : 10 * FPS, 'end' : 11 * FPS -1, 'item' : [v5,v6,t2], 'func' : hide},
]

ACTIVE = []

def animate(i):
	global FRAME, TIMELINE, ACTIVE

	for item in TIMELINE:
		if item['start'] == FRAME:
			ACTIVE.append(item)
	TIMELINE[:] = [item for item in TIMELINE if item['start'] > FRAME]

	ACTIVE[:] = [item for item in ACTIVE if FRAME <= item['end']]
	for item in ACTIVE:
		item['func'](
			FRAME - item['start'],
			item['end'] - item['start'],
			item['item'])
	
	FRAME += 1

Writer = animation.writers['ffmpeg']
writer = Writer(fps=FPS, metadata=dict(artist='James Hume @ www.jeh-tech.com'), bitrate=1800)
ani = animation.FuncAnimation(fig, animate, frames = FPS * 11,  interval=100, blit=False)
ani.save('animation.mp4', writer=writer)
