#! /usr/bin/python3
import sys
import os
import glob
import shutil
from pydub import AudioSegment
import json
from watson_developer_cloud import SpeechToTextV1
import conf #contains username and password to access Watson API
from moviepy.tools import subprocess_call
from moviepy.config import get_setting
import threading
import time

######################################################################
# global variables
######################################################################

stt = SpeechToTextV1(	#Watson Speech To Text API login info
	username = conf.username,
	password = conf.password,
	x_watson_learning_opt_out=True
)

num_threads = 0 # will be set dynamically by detectCPUs()
special_chars = ['<', '>', '\\', '/', '*', ':', '?', '\"', '.'] # used later to detect special characters
basename = ""
person = ""
output_folder = ""
input_file = ""

######################################################################
# classes and functions
######################################################################

def detectCPUs():
	"""
	Detects the number of CPUs on a system. Credit: https://github.com/nunoplopes/alive/blob/master/tests/lit/lit/util.py
	"""
	if hasattr(os, "sysconf"):	# Linux, Unix and MacOS:
		if "SC_NPROCESSORS_ONLN" in os.sysconf_names:	# Linux & Unix:
			ncpus = os.sysconf("SC_NPROCESSORS_ONLN")
			if isinstance(ncpus, int) and ncpus > 0:
				return ncpus
		else: # OSX:
			return int(capture(['sysctl', '-n', 'hw.ncpu']))
	if "NUMBER_OF_PROCESSORS" in os.environ:	# Windows:
		ncpus = int(os.environ["NUMBER_OF_PROCESSORS"])
		if ncpus > 0:
			return ncpus
	return 1 # Default

class myThread (threading.Thread): #used this as guide: https://www.tutorialspoint.com/python3/python_multithreading.htm
	def __init__(self, threadID, audio, start_time):
		threading.Thread.__init__(self)
		self.threadID = threadID
		self.audio = audio
		self.start_time = start_time

	def run(self):
		audio_len = len(self.audio)
		increment_by = 60000
		good_timestamps = {}

		for i in range(self.threadID, audio_len, increment_by):
			end_time = audio_len if(i + 60000 > audio_len) else i+60000
			audio_chunk = self.audio[i:end_time]

			start = str("%d" % (float(self.threadID*audio_len + i) / 1000))
			end = str("%d" % (float(self.threadID*audio_len + end_time) / 1000))

			path = "workspace/" + basename + "_" + start + "-" + end + ".wav"
			audio_chunk.export(path, format="wav")

		for j in range(self.threadID, audio_len, increment_by):
			t2 = time.time()
			end_time = audio_len if(j + 60000 > audio_len) else j+60000
			start = str("%d" % (float(self.threadID*audio_len + j) / 1000))
			end = str("%d" % (float(self.threadID*audio_len + end_time) / 1000))
			path = "workspace/" + basename + "_" + start + "-" + end + ".wav"

			#Use Watson Speech API on audio chunk
			with open(path, 'rb') as audio:
				stt.models()
				stt.get_model('en-US_BroadbandModel')

				#these parameters above can be altered to effect the output of the api
				stt_result = stt.recognize( audio, content_type='audio/wav',
													timestamps=True,
													word_confidence=True,
													continuous=True,
													profanity_filter=False,
													word_alternatives_threshold=0.0 )

				#dump response to a json file if we want to check it later then open it
				with open('speech-snippets/' + basename + "_" + start + "-" + end + '.json', 'w') as data_file:
					json.dump(stt_result, data_file, indent=1)
				with open('speech-snippets/' + basename + "_" + start + "-" + end + '.json') as data_file:
					get_good_timestamps(good_timestamps, data_file, float(self.threadID*audio_len + j) / 1000)

				t3 = time.time()
				print("thread " + str(self.threadID) + ", j: " + str(j) + ", time: " + str(t3-t2))

		t4 = time.time()
		print("thread " + str(self.threadID) + " starting to extract_words")
		#clip audio into word clips
		extract_words(input_file, good_timestamps, self.threadID)
		t5 = time.time()
		print("thread " + str(self.threadID) + " finished extract_words. time: " + str(t5-t4))

def ffmpeg_extract_subclip(filename, start, end, targetname=None):
	"""
	Creates a new video file playing video file "filename" between
		the times "start" and "end".

	Parameters
	--------------------
		filename			-- 	path
		start 				--	time to start cutting from
		end 				--	time to finish cutting to
		targetname			--	output file name (not used)

	Returns
	--------------------
		nothing
	"""
	"""
		Note: This function is from the moviepy library but it was buggy so we fixed it here"""
	name,ext = os.path.splitext(filename)
	if not targetname:
		T1, T2 = [int(1000*t) for t in [start, end]]
		targetname = name+ "%sSUB%d_%d.%s"(name, T1, T2, ext)

	cmd = [get_setting("FFMPEG_BINARY"), "-y",
		"-ss", "%0.2f"%start,
	  	"-t", "%0.2f"%(end-start),
	  	"-i", filename,
		"-c:v", "libx264", "-x264opts", "keyint=1:min-keyint=1:scenecut=-1",
	  	targetname]

	subprocess_call(cmd, False)

def is_new_clip_better(word, new_s, new_e, old_s, old_e):
	"""
	Compares two clips, seeing which one is better.
	For now, this function simply considers "better" to be "longer"

	Parameters
	--------------------
		word				-- word being compared
		new_s				-- start time of new word
		new_e 				-- end time of new word
		old_s 				-- start time of old word
		old_e 				-- end time of old word

	Returns
	--------------------
		Bool				--	True if new clip is better than old one. False otherwise
	"""
	new_len = new_e - new_s
	old_len = old_e - old_s