#!/usr/bin/env python
# -*- coding: utf-8 -*-

''' Creates course folder/ Saves chapters'''

import os, io
import sys, zipfile, json
import time
import shutil
import re
import install
from module import message, cookies, read
try:
    from bs4 import BeautifulSoup
    from colorama import Fore
    import requests
except ImportError:
    pass

def utf_encode(string):
    return (string).encode('utf-8')

def utf_decode(string):
    return string.decode('utf-8')

def create_soup(url):
    ''' create soup object '''
    request = requests.get(url)
    page_content = request.content
    return BeautifulSoup(page_content, 'html.parser')

def check_exercise_file(url):
    ''' check if a course has an exercise file '''
    soup = create_soup(url)
    ex_file = soup.find(id='exercise-tab')
    if ex_file is not None:
        return True
    return False

def course_path(url, lynda_folder_path):
    ''' finding course path '''
    soup = create_soup(url)
    course_title = soup.find('h1', {"class": "default-title"}).text
    
    # Check for valid characters
    replacements = [
        ('[?]', ''),
        ('[/]', '_'),
        ('["]', "'"),
        ('[:><\\|*]', ' -')
    ]

    for old, new in replacements:
        course_title = re.sub(old, new, course_title)
    
    course_title = course_title.strip()
    return lynda_folder_path + course_title

def course(url, lynda_folder_path):
    ''' create course folder '''
    current_course = course_path(url, lynda_folder_path)
    courses = os.listdir(lynda_folder_path)

    answer = None
    for course in courses:
        if (lynda_folder_path + course) == current_course:
            if read.redownload_course == 'force':
                # delete existing course and re-download
                shutil.rmtree(current_course)
                message.colored_message(Fore.LIGHTRED_EX, "\n✅  Course folder already exists. Current preference -> FORCE redownload")
                message.colored_message(Fore.LIGHTRED_EX, "\n❌  Existing course folder deleted!!")
                time.sleep(2)
                message.colored_message(Fore.LIGHTGREEN_EX, "\n♻️  Re-downloading the course.\n")
                time.sleep(2)
            elif read.redownload_course == 'skip':
                # skip download process
                message.colored_message(Fore.LIGHTRED_EX, "\n✅  Course folder already exists. Current preference -> SKIP redownload")
                sys.exit(message.colored_message(Fore.LIGHTRED_EX, "\n-> Skipping course download.\n"))    
            elif read.redownload_course == 'prompt':
                # prompt user with available choices
                QUESTION = '\n✅  Course folder already exists: Do you wish to delete it and download again? (Y/N): '
                sys.stdout.write(Fore.LIGHTBLUE_EX + QUESTION + Fore.RESET)
                while answer != 'y':
                    # get user input
                    answer = input().lower()

                    if answer == 'y':
                        shutil.rmtree(current_course)
                        message.colored_message(Fore.LIGHTRED_EX, "\n❌  Existing course folder deleted!!")
                        time.sleep(2)
                        message.colored_message(Fore.LIGHTGREEN_EX, "\n♻️  Re-downloading the course.\n")
                    elif answer == 'n':
                        sys.exit(message.colored_message(Fore.LIGHTRED_EX, "\n-> Program Ended!!\n"))
                    else:
                        sys.stdout.write(Fore.LIGHTRED_EX + "\n- oops!! that's not a valid choice, type Y or N: " + Fore.RESET)
    
    print(f'\ncreating course folder at: {current_course}')
    os.mkdir(current_course)

def info_file(url, course_path):
    ''' gather course information. '''
    soup = create_soup(url)
    course_title = soup.find('h1', {"class": "default-title"}).text
    course_ids = soup.findAll('div', {"data-course-id":True}) # find all course id attributes
    course_id = course_ids[0]['data-course-id'] # select the first course id attribute value
    author_name = soup.find('cite', {"data-ga-label": "author-name"}).text
    #topic tags
    topic_tags = soup.findAll('a', {"data-ga-label": "topic-tag"})
    topic_tag = '\t'
    for tag in topic_tags:
        topic_tag += '#' + tag.text + '\t'
    #software tags
    software_tags = soup.findAll('a', {"data-ga-label": "software-tag"})
    software_tag = ''
    for tag in software_tags:
        software_tag += '#' + tag.text + '\t'
    if software_tag == '':
        software_tag += 'None'
    release_date = soup.find('span', {"id": "release-date"}).text
    duration = soup.find('div', {"class": "duration"}).find('span').text
    download_date = time.strftime("%d/%B/%Y")   # todays date

    message.write("\nCourse Name", course_title)
    message.write("Course id", course_id)
    message.write("Author Name", author_name)
    message.write("Topics", topic_tag)
    message.write("Softwares", software_tag)
    message.write("Duration", duration)
    message.write("Release Date", release_date)
    message.write("Downloaded On", download_date)
    message.write("Course URL", url)

    os.chdir(course_path)   # Jump to course directory to save info.txt

    # write to info.txt
    info_file = io.open('info.txt', mode="a", encoding="utf-8")
    info_file.writelines(u'Course Name' + '\t\t' + course_title + '\n')
    info_file.writelines(u'Course id' + '\t\t' + course_id + '\n')
    info_file.writelines(u'Author Name' + '\t\t' + author_name + '\n')
    info_file.writelines(u'Topics' + '\t\t' + topic_tag + '\n')
    info_file.writelines(u'Softwares' + '\t\t' + software_tag + '\n')
    info_file.writelines(u'Duration' + '\t\t' + duration + '\n')
    info_file.writelines(u'Release Date' + '\t\t' + release_date + '\n')
    info_file.writelines(u'Downloaded On' + '\t\t' + download_date + '\n')
    info_file.writelines(u'Course URL' + '\t\t' + url + '\n')
    info_file.close()

    # write to content.md
    content_md = io.open('CONTENT.md', mode="a", encoding="utf-8")
    content_md.writelines(u"# " + course_title + " with " + author_name + " on lynda.com \n")
    content_md.close()

    # print message
    message.print_line(message.INFO_FILE_CREATED)

def format_chapter(chapter, chapter_count):
    ''' format chapter text '''

    # handle empty named chapters
    if len(chapter) == 0:
        chapter = "Unnamed"

    # Check for valid characters
    replacements = [
        ('[?]', ''),
        ('[/]', '_'),
        ('["]', "'"),
        ('[:><\\|*]', ' -')
    ]

    for old, new in replacements:
        chapter = re.sub(old, new, chapter)                

    if chapter[1] == '.':
        chapter = str(chapter_count).zfill(2) + '. ' + chapter[3:]
    elif chapter[2] == '.':
        chapter = str(chapter_count).zfill(2) + '. ' + chapter[4:]
    else:
        chapter = str(chapter_count).zfill(2) + '. ' + chapter

    return chapter

def chapters(url, course_folder_path):
    ''' create chapters folder '''
    soup = create_soup(url)
    heading4 = soup.find_all('h4', {"class": "ga"})
    chapter_no = 0

    message.colored_message(Fore.LIGHTYELLOW_EX, "Creating Chapters:\n") # Print message

    
    for h in heading4:
        chapter = format_chapter(h.text, chapter_no)
        chapter_no += 1
        message.print_line(chapter)

        new_chapter = course_folder_path + "/" + chapter
        new_chapter = new_chapter.strip()
        os.mkdir(new_chapter) # create folders (chapters)
            
    message.colored_message(Fore.LIGHTGREEN_EX, '\n✅  '+str(chapter_no)+' chapters created!!\n')

def contentmd(url):
    ''' write chapters and videos information to content.md '''

    soup = create_soup(url)

    chapters = soup.find_all("h4", class_="ga")
    ul_video = soup.find_all('ul', class_="row toc-items")
    
    chapter_count = 0
    video_count = 0


    content_md = io.open('CONTENT.md', mode="a", encoding="utf-8")

    bug = False
    for li in ul_video:
        try:
            chapter = format_chapter(chapters[chapter_count].text, chapter_count) 
            chapter_markdown = u'\n\n## {}\n'.format(chapter)
            content_md.writelines(chapter_markdown)
        except Exception:
            bug = True
            break              
        chapter_count += 1
        group = li.find_all('a', class_='video-name')
        for video in group:
            video_count += 1
            try:
                video_name = u"{} - {}".format(str(video_count).zfill(2), video.text.strip())
                if read.markdown_links:
                    video_markdown = "\n* [" + video_name + "](" + chapter + "/" + video_name + ".mp4)"
                else:
                    video_markdown = "\n* " + video_name
                content_md.writelines(video_markdown)
            except Exception:
                bug = True
                break
    if bug:
        print('🤕  There seems to be an error while writing to content.md, please report the bug on GitHub')
    else:
        print("👍🏻  CONTENT.md created.\n")                
    content_md.close()                  # close content.md

def total_videos(url):
    ''' counts total available video files '''

    soup = create_soup(url)
    ul_video = soup.find_all('ul', class_="row toc-items")
    video_count = 0

    for li in ul_video:
        group = li.find_all('a', class_='video-name')
        video_count += len(group)
    return video_count

def videos(url, cookie_path, course_folder):
    ''' Download all the videos in course folder'''
    os.chdir(course_folder)
    download_preference = read.course_download_pref

    try:
        subtitles = ' --all-subs ' if read.download_subtitles else ' ' # Check subtitle preferences
        # Output name of videos/subtitles
        output = ' -o ' +'"'+ course_folder + "/%(playlist_index)s - %(title)s.%(ext)s" + '"'
        # Exter name downloader option
        ext_downloader = ' --external-downloader aria2c' if read.aria2_installed else ''
        cookie = ' --cookies ' + '"' + cookie_path + '"'     # cookie
        uName = read.username

        if "'" in uName:                                     # escaping single quote (') for users with quote in their username
            uName = uName.replace("'", "\\'")
        username = ' -u ' + uName                            # username
        password = ' -p ' + read.password                    # password

        # Checking download preferences
        if  download_preference in ['cookies', 'cookie']:
            cookies.edit_cookie(cookie_path, message.NETSCAPE) # Edit cookie file
            os.system('youtube-dl --no-check-certificate' + cookie + output + subtitles + url + ext_downloader)
        else:
            os.system('youtube-dl --no-check-certificate' + username + password + output + subtitles + url + ext_downloader)
    except KeyboardInterrupt:
        sys.exit('Program Interrupted')

def aria2():
    ''' Download aria2c for windows '''
    try:
        import requests
    except ImportError:
        pass
    os.chdir(install.LYNDOR_PATH)
    if install.check_os() == 'windows':
        try:
            os.mkdir('aria2c')
        except:
            pass
        aria = requests.get(
            'https://github.com/aria2/aria2/releases/download/release-1.33.1/aria2-1.33.1-win-64bit-build1.zip')
        print('\n-> Downloading aria2c for windows')
        with open('./aria2c/aria2c.zip', 'wb') as f:
            f.write(aria.content)
        print('\n>>> aria2c.zip has been downloaded inside "Lyndor/aria2c" folder')
        unzip('aria2c', 'aria2c.zip')
        print('>>> aria2c.zip has been unzipped, copy its path and save to PATH variable.\n')


def unzip(directory, zip_file):
    ''' unzip a file '''
    with zipfile.ZipFile(directory + '/' + zip_file, 'r') as f:
        f.extractall(path=directory)


def settings_json():
    ''' Create settings_json file '''
    os.chdir(install.LYNDOR_PATH)

    settings_dict = {
        "credentials": {
            "regular_login": {
                "username": "",
                "password": ""
            }, 
            "library_login": {
                "card_number": "",
                "card_pin": "",
                "organization_url": ""
            },
            "course_download_pref": "regular-login",
            "exfile_download_pref": "regular-login",
        },
        "preferences": {
            "location": install.set_path() + '/Lynda',
            "markdown_links": False,
            "download_subtitles": False,
            "download_exercise_file": False,                # feature unavailable for organizational login
            "web_browser_for_exfile": "chrome",             # select chrome or firefox as a web browser
            "aria2_installed": False,                       # set True after installing aria2
            "download_time": "",
            "redownload_course": "prompt",                  # choose between -> prompt, skip & force re-download
            "exfile_download_method": "selenium",           # choose between selenium and aria2
        }
    }

    settings = os.path.join(install.LYNDOR_PATH, 'settings/static/js/settings.json')
    out_file = open(settings, 'w')
    json.dump(settings_dict, out_file, indent=4)
    out_file.close()

    print(f"\n>>> Courses will be saved at -> {read.settings_json('preferences', 'location')} \n")
    print('-> settings.json file created at Lyndor/settings/static/js/settings.json\n')


def lynda_folder():
    ''' Create lynda folder '''
    path = read.settings_json('preferences', 'location')
    if not os.path.exists(path):
        os.makedirs(path)
        print(f'-> Lynda folder created at: {path} \n')
    else:
        print('>>> Lynda folder already exists\n')


def aliases_bat():
    '''Create aliases file'''
    os.chdir(install.LYNDOR_PATH)
    if install.check_os() == 'windows':
        run_path = 'doskey lynda= python "' + os.getcwd() + '/run.py"'
        alias = open('aliases.bat', 'w')
        alias.write(run_path)
        alias.close()
        print('-> aliases.bat file created.\n')


def run_lyndor_bat():
    ''' create Run-Lyndor.bat in windows '''
    os.chdir(install.LYNDOR_PATH)
    bulk_download = open('Bulk Download.txt', 'w')
    bulk_download.close()
    shutil.move('Bulk Download.txt', read.settings_json(
        'preferences', 'location') + '/Bulk Download.txt')
    print('-> Bulk Download.txt file created successfully.\n')
    
    if install.check_os() == 'windows':
        run_path = 'python "' + os.getcwd() + '/run.py"'
        lynda = open('Run-Lyndor.bat', 'a')
        lynda.writelines('@ECHO OFF\n')
        lynda.writelines('REM Batch file to execute run.py\n')
        lynda.writelines('SET PATH=%PATH%;C:\Python27;C:\Python27\Scripts\n')
        lynda.writelines(run_path + '\n')
        lynda.writelines('pause')
        lynda.close()
        try:
            os.rename('Run-Lyndor.bat', read.settings_json('preferences',
                                                           'location') + '/Run-Lyndor.bat')
        except:
            pass
        finally:
            print('-> Run-Lyndor.bat file created.\n')


def webdriver():
    ''' Download web driver '''
    try:
        import requests
    except ImportError:
        pass
    os.chdir(install.LYNDOR_PATH)   # change directory to LYNDOR
    try:
        # create directory webdriver to save platform specific webdrivers
        os.mkdir('webdriver')
    except:
        pass
    print('\n-> Downloading web driver for', install.check_os())

    if install.check_os() == 'windows':
        chrome_url = 'https://chromedriver.storage.googleapis.com/2.35/chromedriver_win32.zip'
        firefox_url = 'https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-win64.zip'
    elif install.check_os() == 'macos':
        chrome_url = 'https://chromedriver.storage.googleapis.com/2.35/chromedriver_mac64.zip'
        firefox_url = 'https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-macos.tar.gz'
    elif install.check_os() == 'linux':
        chrome_url = 'https://chromedriver.storage.googleapis.com/2.35/chromedriver_linux64.zip'
        firefox_url = 'https://github.com/mozilla/geckodriver/releases/download/v0.19.1/geckodriver-v0.19.1-linux64.tar.gz'

    chrome = requests.get(chrome_url)
    firefox = requests.get(firefox_url)

    with open('webdriver/chromedriver.zip', 'wb') as f:
        f.write(chrome.content)

    with open('webdriver/firefoxdriver.zip', 'wb') as f:
        f.write(firefox.content)

    print('\n>>> Web driver downloaded inside "/Lyndor/webdriver" folder, extract the zip file and \
set the webdriver directory path to "PATH" variable, see README.md file for more detail.')
    print('\n>>> Installation complete update your settings by running "python settings/settings.py"')
    print('\nThis will run a local webserver at port 5000, you will see a message like')
    print('* Running on http://127.0.0.1:5000/ visit such URL in web-browser\n')