# -*- coding: utf-8 -*-

# core.py
# This file is part of qarte-5
# Code name: Слава Україні! (Sláva Ukrayíni!)
# Author: Vincent Vande Vyvre <vincent.vandevyvre@oqapy.eu>
# Copyright: 2016-2025 Vincent Vande Vyvre
# Licence: GPL3
# Home page: https://launchpad.net/qarte

import os
import sys
import json
import pickle
import time
import locale

import logging
lgg = logging.getLogger(__name__)

import gettext
LOC_PATH = '/usr/share/locale'
gettext.install('qarte', LOC_PATH)
# For testing a specific translation, comment the previous line,
# uncomment the two next lines and set the language code.
#tr = gettext.translation('qarte', LOC_PATH, languages=['de'])
#tr.install()

from data import VERSION, VERSION_STR
from config import Config
from artetv import ArteTV
from arteconcert import ArteConcert
from gui.mainui import MainUi
from settings import Settings
from gui.warning import WarningBox
from about import About

try:
    from shutil import disk_usage
except ImportError:
    from tools import disk_usage

from PyQt5.QtCore import QCoreApplication, QLocale
from PyQt5.QtWidgets import QApplication

LOC = QLocale.system().name()
try:
    LANG, c = LOC.split('_')
except:
    LANG = 'fr'

if LANG not in ['fr', 'de']:
    LANG = 'fr'


class Core:
    """Define the main class of Qarte.

    """
    def __init__(self, args):
        self.set_environment(args)
        self.is_interact_with_dialog = False
        self.build_main_window()
        self.artetv = ArteTV(self)
        self.ui.tv_basket.driver = self.artetv
        self.artelive = ArteConcert(self)
        self.artelive.parsingFinished.connect(self.set_concerts_list)
        live = self.ui.live_pg
        live.viewer.cfg = self.cfg
        self.artetv.parsingFinished.connect(self.set_videos_list)
        self.artetv.config_parser()
        live.live_basket.driver = self.artelive
        self.ui.configure_signals()

    def build_main_window(self):
        lgg.info('Build main window')
        self.ui = MainUi(self, self.cfg.get("size"))
        self.ui.show()
        QCoreApplication.processEvents()
        self.ui.resize_splitters()

    def set_environment(self, args):
        """Build the working environment.

        """
        self.workspace = self.define_workspace()
        self.build_config(args)
        lgg.info("with video player: %s" % self.cfg.get('video_player'))

    def build_config(self, args):
        """Load the user's preferences.

        Args:
        args -- arguments at launching Qarte
        """
        self.cfg = Config(self)
        if "--no-player" in args:
            self.cfg.update('video_player', False)

        elif "--with-player" in args:
            self.cfg.update('video_player', True)

        self.cfg.update('version', VERSION)

    def define_workspace(self):
        """Get the workspace, usually at /home/username/.Qarte

        Returns:
        dict(paths)
        """
        lgg.info('Set workspace')
        user = os.path.expanduser("~")
        paths = {}
        #XXX Devel path only !
        #user = os.path.dirname(os.getcwd())
        paths['user'] = os.path.join(user, ".Qarte")
        paths['config'] = os.path.join(paths['user'], "user_config")
        paths['live_tmp'] = os.path.join(paths['user'], "livePreviews")
        paths['tv_tmp'] = os.path.join(paths['user'], "plusPreviews")
        paths['live_stats'] = os.path.join(paths['user'], "olds.stat")
        paths['tv_index'] = os.path.join(paths['user'], "tv_index")
        paths['tv_videos_data'] = os.path.join(paths['user'], "tv_videos_data")
        paths['filters'] = os.path.join(paths['user'], "filter_historic")
        paths['concerts_fr'] = os.path.join(paths['user'], "concerts_fr.jsn")
        paths['concerts_de'] = os.path.join(paths['user'], "concerts_de.jsn")
        paths['temp']  = os.path.join(paths['user'], "temp")
        for name in ('live_tmp', 'tv_tmp', 'temp'):
            if not os.path.isdir(paths[name]):
                try:
                    os.makedirs(paths[name])
                except Exception as why:
                    lgg.critical('Unable to create: %s\nReason: %s' 
                                 % (paths[name], why))
                    sys.exit()

        return paths

    def set_videos_list(self, number):
        """Display the list of arte TV videos.

        Args:
        number -- number of videos available
        """
        if self.ui:
            self.ui.arte_list.display_videos()

        self.check_video_folder()
        if not self.artelive.concerts:
            self.artelive.config_parser()

    def check_video_folder(self):
        """Verify if the video's folder is defined.

        """
        if self.cfg.get('videos_folder') is None:
            self.display_config_dialog()

        if not os.path.isdir(self.cfg.get('videos_folder')):
            os.makedirs(self.cfg.get('videos_folder'))

    def on_tv_item_selected(self, idx):
        """Check if selection mode is interactiv with differed download
        dialog.

        Args:
        idx -- item's index
        """
        if self.artetv.is_in_category:
            self.artetv.display_category_content(idx)
            return

        item = self.artetv.videos[idx]
        lgg.info('Choose: %s' % item.title)
        if self.is_interact_with_dialog:
            if not hasattr(item, 'category'):
                self.artetv.get_stream_urls(item)
            if item.streams is not None:
                self.check_quality(item)
                self.scheduler.set_video_item(item)
                self.scheduler.dialog.show()
                self.is_interact_with_dialog = False

    def on_concert_item_selected(self, item):
        lgg.info('Choose: %s' % item.title)
        if self.is_interact_with_dialog:
            qualities = self.artelive.get_stream_urls(item)

            if qualities is None:
                lgg.warning("No stream URLs found, item rejected")
                return

            self.artelive.clean_qualities(qualities)
            item.qualities = qualities
            item.set_file_name()
            item.set_quality(self.artelive.default_quality)
            self.scheduler.set_video_item(item)
            self.scheduler.dialog.show()
            self.is_interact_with_dialog = False

    def check_quality(self, video):
        if video.quality is None:
            if self.cfg.get('tv_quality') is not None:
                video.quality = self.cfg.get('tv_quality')

            else:
                ls = [None, 'fr', 'de']
                video.quality = "HTTP_MP4_EQ_%s" % str(ls.index(self.lang))

    def set_concerts_list(self):
        self.artelive.display_available_concerts()

    def display_config_dialog(self):
        """Show the user's preferences dialog box.

        """
        lgg.info('Call settings dialog box')
        self.settings = Settings(self)
        self.settings.show()
        self.settings.configure(self.cfg)
        self.settings.exec_()

    def reload_arte_tv(self):
        lgg.info('Reload arte TV Guide')
        # Language may be changed
        self.artetv.lang = self.cfg.get('lang')
        self.artetv.config_parser()

    def display_about_dialog(self):
        lgg.info('Call About dialog box')
        self.about = About(VERSION_STR)

    def create_deferred_task(self, video=None):
        lgg.info('Call deferred task dialog box: %s' % video)
        self.scheduler = LoadingScheduler(self, video)

    def close_application(self):
        """Close Qarte.

        """
        lgg.info('Prepare to exit')
        if not self.check_downloading():
            self.cfg.save_user_config()
            self.clean_temp_dirs()
            return True

        else:
            return False

    def check_downloading(self):
        """Return True if a downloading is still active.

        """
        if self.artetv.is_pending_tasks(): # or self.artelive.is_loading:
            choice = self.show_warning(10, _("A downloading is active!"))
            return True

        return False

    def check_free_space(self, size, fld):
        stats = disk_usage(fld)
        if stats.free < (size + 2048):
            lgg.info("Not enought free space, show warning")
            self.show_space_warning(fld, size, stats.free)
            self.display_config_dialog()
            return False

        return True

    def clean_temp_dirs(self):
        temp = self.workspace['temp']
        for i in (os.listdir(temp)):
            fpath = os.path.join(temp, i)
            if os.path.isfile(fpath):
                try:
                    os.remove(fpath)
                except Exception as why:
                    lgg.warning("Can't remove %s %s" %(i, why))

    def show_warning(self, code, *args):
        """Show the warning dialog box.

        Args:
        """
        lgg.info('Warning: %s %s' %(code, "; ".join(args)))
        warn = WarningBox(code, None, self.ui)
        rep = warn.exec_()
        lgg.info('Warning return: %s' % rep)
        return rep

    def show_space_warning(self, fname, size, free):
        size = "%s bytes" % QLocale(LOC).toString(size)
        free = "%s bytes" % QLocale(LOC).toString(free)
        from gui.spacewarning import SpaceWarning
        spw = SpaceWarning(fname, size, free)
        ret = spw.exec_()

    def get_target_path(self, fld):
        """Return a temp file name builded with time.

        """
        d = str(time.time()).replace(".", "")
        t = "".join(["tv", d])
        count = 1
        while 1:
            target = os.path.join(fld, t)
            if os.path.isfile(target):
                t = "".join(["tv", d, str(count)])
                count += 1

            else:
                break

        return target


if __name__ == '__main__':
    args = sys.argv
    lvl = logging.DEBUG
    LOG_FORMAT = "%(asctime)-6s %(levelname)s: %(name)s - %(message)s"
    logging.basicConfig(format=LOG_FORMAT, datefmt='%H:%M:%S', level=lvl)
    lgg = logging.getLogger(__name__)
    app = QApplication(args)
    core = Core(args)
    sys.exit(app.exec_())
