#/usr/bin/env python2.7
# -*- coding: utf-8 -*-

"""radcast.py: main functionality of radcast"""

import os
import subprocess
import jinja2
import logging
from . import settings
from .utilities import slugify

__copyright__ = "Copyright 2017, Josh Wheeler"
__license__ = "GPL-3.0"
__status__ = "Development"

#    radcast: radical podcast automation
#    Copyright (C) 2017 Josh Wheeler
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

# load values from config file into cfg
cfg = settings.cfg
preset = settings.presets[cfg["preset"]]


def deserialize_clip(clip_dict):
    """Deserialize clip from python dictionary to clip object"""

    c = clip_dict

    logging.debug("Deserialize %s" % c)

    clip = Clip(c["filename"])
    clip.in_frame = c.get("in_frame", 0)
    clip.out_frame = c.get("out_frame", None)
    clip.fade = c.get("fade", None)
    clip.start_frame = c.get("start_frame", None)

    return clip.get_clip()


class Clip(object):
    """Clip object and attributes

    fades can either be a value or True. If True, default transition
    length from user's settings file will be used.
    """

    def __init__(self, filename=None, color=None):

        self.filename = filename
        self.in_frame = 0
        self.out_frame = None
        self.current_frame = None
        self.fade = None
        self.mos = False
        self.still = 5

    def get_clip(self):
        """Return clip object"""

        transition_length = cfg.get("transition_length", 12)

        # fades can either be True or a value. If true, they get default
        # transition length set in config file. If no default transition length
        # is set, they will get 24 frames for default

        if self.fade is True:
            self.fade = transition_length

        # if clip is a still frame, apply mos and length
        fname, ext = os.path.splitext(self.filename)
        formats = [".jpg", ".jpeg", ".jp2", ".png", ".tif", ".tiff", ".gif", "bmp"]
        if any(ext.lower() in s for s in formats):
            self.mos = True
            self.out_frame = self.still * cfg.get("fps", 24)

        # hacky solution to mos the ending logo for a melt audio fade
        if os.path.basename(fname).lower() == "logo":
            self.mos = True

        return self


class Podcast(object):
    def __init__(self):
        self.title = "Untitled"
        self.description = ""
        self.sequence = []
        self.program = None
        self.preset = settings.presets[cfg["preset"]] 
        self.path = None
        self.padding = cfg.get("padding", True)
        self.pre_roll = []
        self.post_roll = []
        self.output_dir = "/media/output"
        self.output_file = None

        # pre-roll and post-roll from cfg

        cfg_pre_roll = cfg.get("pre_roll", None)
        cfg_post_roll = cfg.get("post_roll", None)

        # if output directory is missing, set to current directory
        if not os.path.isdir(self.output_dir):
            self.output_dir = os.getcwd()

        if cfg_pre_roll:
            for c in cfg_pre_roll:
                self.pre_roll.append(deserialize_clip(c))
                logging.info("Adding pre-roll from config: %s" % cfg_pre_roll)
        if cfg_post_roll:
            for c in cfg_post_roll:
                self.post_roll.append(deserialize_clip(c))
                logging.info("Adding post-roll from config: %s" % cfg_post_roll)

        # if padding isn't a numeric value, set a default length
        if self.padding is True:
            self.padding = cfg.get("fps", 24)

    def generate_melt(self, template="simple.melt"):
        """generate a melt file based on template given.
        If no template is given, default.melt is used."""

        self.melt_file = "%s/%s.melt" % (self.output_dir, slugify(self.title))

        loader = jinja2.PackageLoader("radcast", "templates")
        env = jinja2.Environment(loader=loader)
        env.trim_blocks = True
        env.lstrip_blocks = True
        f = open(self.melt_file, "w+")
        template_xml = env.get_template(template)
        # set up template variables
        render = template_xml.render(
            program=self.program,
            pre_roll=self.pre_roll,
            post_roll=self.post_roll,
            padding=self.padding,
            )
        f.write(render)
        f.close()

        return self.melt_file

    def get_melt_command(self):

        # set producer to filename of generated melt file
        self.generate_melt()

        if not self.output_file:
            self.output_file = slugify(self.title) + ".m4v"
            self.output_file = ("%s/%s") % (self.output_dir, self.output_file)

        command = [
            'melt', '-profile', cfg.get("mlt_profile", "atsc_720p_24"),
            '-producer', self.melt_file,
            '-consumer', 'avformat:' + self.output_file,
            'vcodec=' + preset.get("vcodec", "libx264"),
            'color_primaries=' + preset.get("color_primaries", "bt709"),
            'preset=' + preset.get("preset", "slower"),
            'b=' + preset.get("b:v", "7500k"),
            'acodec=' + preset.get("acodec", "aac"),
            'ab=' + preset.get("b:a", "320k"),
            'ac=' + preset.get("ac", "2"),
            ]

        for f in preset.get("ffmpeg_params", None):
            command.append(f)

        logging.debug("Encode command: %s" % command)
        return command

    def encode(self):
        """Encode video and audio"""

        # render video
        subprocess.call(self.get_melt_command())

        # convert audio to flac and save file handle for trim operation
        flac = self.encode_flac(self.output_file)

        # remove silence and save file handle for mp3 encoding
        trimmed = self.remove_silence(flac)

        # encode mp3
        self.encode_mp3(trimmed)

        if os.path.isfile(trimmed):
            os.remove(trimmed)

    def remove_silence(self, infile):
        """Remove silent periods from audio at beginning and end"""

        input_file = infile
        output_file = "%s/%s" % (self.output_dir, slugify(self.title) + ".wav")

        logging.info("Trimming silence from %s\nSaving to %s" % (
            input_file,
            output_file
            )
        )

        command = [
            'sox',
            input_file,
            output_file,
            'silence',
            '1', '0.1', '0.1%',
            'reverse',
            'silence',
            '1', '0.1', '0.1%',
            'reverse'
        ]

        logging.debug("sox command: %s" % command)
        subprocess.call(command)
        return output_file

    def encode_flac(self, infile):
        """Encode flac using ffmpeg"""

        input_file = infile
        output_file = "%s/%s" % (self.output_dir, slugify(self.title) + ".flac")

        logging.info("Encoding flac from %s\nSaving to %s" % (
            input_file,
            output_file
            )
        )

        command = [
            'ffmpeg',
            '-loglevel', 'panic',
            '-hide_banner',
            '-y',
            '-i', input_file,
            '-ac', '1',
            output_file,
        ]

        logging.debug("ffmpeg command: %s" % command)
        subprocess.call(command)
        return output_file

    def encode_mp3(self, infile):
        """Encode audio to mp3 using ffmpeg"""

        input_file = infile
        output_file = "%s/%s" % (self.output_dir, slugify(self.title) + ".mp3")

        logging.info("Encoding podcast mp3 from %s\nSaving to %s" % (
            input_file,
            output_file
            )
        )

        command = [
            'ffmpeg',
            '-loglevel', 'panic',
            '-hide_banner',
            '-y',
            '-i', input_file,
            '-acodec', 'mp3',
            '-ab', '64k',
            '-ac', '1',
            output_file,
        ]

        logging.debug("ffmpeg command: %s" % command)
        subprocess.call(command)
        return output_file
