# -*- coding: utf-8 -*-
"""Module containing util functions for the pdfebc program.

It uses Google's SMTP server for sending emails. If you wish to use another server, simply change
the SMTP_SERVER variable to your preferred server.

Requires a config file in $HOME/.config/pdfebc/config.ini that should look like:
    [email]
    user = sender_email
    pass = password
    reciever = reciever_email

All characters after the colon and whitespace (as much whitespace as you'd like) until
EOL counts as the username/password.

.. module:: utils
    :platform: Unix
    :synopsis: Core functions for pdfebc.

.. moduleauthor:: Simon Larsén <slarse@kth.se>
"""
import smtplib
import os
import configparser
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.multipart import MIMEMultipart
import appdirs

CONFIG_PATH = os.path.join(appdirs.user_config_dir('pdfebc'), 'email.cnf')
SECTION_KEY = "email"
PASSWORD_KEY = "pass"
USER_KEY = "user"
RECIEVER_KEY = "reciever"
SMTP_SERVER = "smtp.gmail.com"

def create_email_config(user, password, reciever):
    """Create an email config.

    Args:
        user (str): User e-mail address.
        password (str): Password to user e-mail address.
        reciever: Reciever e-mail address.

    Returns:
        configparser.ConfigParser: A ConfigParser
    """
    config = configparser.ConfigParser()
    config[SECTION_KEY] = {
        USER_KEY: user,
        PASSWORD_KEY: password,
        RECIEVER_KEY: reciever}
    return config

def write_config(config, output_path):
    """Write the config to the output path.

    Args:
        config (configparser.ConfigParser): A ConfigParser.
    """
    with open(output_path, 'w', encoding='utf-8') as f:
        config.write(f)

def read_email_config(config_path=CONFIG_PATH):
    """Read the email config file.

    Args:
        config_path (str): Relative path to the email config file.

    Returns:
        (str, str, str): User email, user password and reciever email.

    Raises:
        IOError
    """
    if not os.path.isfile(config_path):
        raise IOError("No config file found at %s" % config_path)
    config = configparser.ConfigParser()
    config.read(config_path)
    user = try_get_conf(config, SECTION_KEY, USER_KEY)
    password = try_get_conf(config, SECTION_KEY, PASSWORD_KEY)
    reciever = try_get_conf(config, SECTION_KEY, RECIEVER_KEY)
    return user, password, reciever

def try_get_conf(config, section, attribute):
    """Try to parse an attribute of the config file.

    Args:
        config (configparser.ConfigParser): A ConfigParser.
        section (str): The section of the config file to get information from.
        attribute (str): The attribute of the section to fetch.

    Returns:
        str: The string corresponding to the section and attribute.

    Raises:
        configparser.ParseError
    """
    try:
        return config[section][attribute]
    except KeyError:
        raise configparser.ParsingError("""Config file badly formed!\n
                Failed to get attribute '%s' from section '%s'!""" % (attribute, section))

def send_with_attachments(user, password, reciever, subject, message, filepaths):
    """Send an email from the user (a gmail) to the reciever.

    Args:
        user (str): The sender's email address.
        password (str): The password to the 'user' address.
        reciever (str): The reciever's email address.
        subject (str): Subject of the email.
        message (str): A message.
        filepaths (list(str)): Filepaths to files to be attached.
    """
    email_ = MIMEMultipart()
    email_.attach(MIMEText(message))
    email_["Subject"] = subject
    email_["From"] = user
    email_["To"] = reciever
    attach_files(filepaths, email_)
    send_email(user, password, email_)


def attach_files(filepaths, email_):
    """Take a list of filepaths and attach the files to a MIMEMultipart.

    Args:
        filepaths (list(str)): A list of filepaths.
        email_ (email.MIMEMultipart): A MIMEMultipart email_.
    """
    for filepath in filepaths:
        base = os.path.basename(filepath)
        with open(filepath, "rb") as file:
            part = MIMEApplication(file.read(), Name=base)
            part["Content-Disposition"] = 'attachment; filename="%s"' % base
            email_.attach(part)

def send_email(user, password, email_):
    """Send an email.

    Args:
        user (str): Sender's email address.
        password (str): Password to sender's email.
        email_ (email.MIMEMultipart): The email to send.
    """
    server = smtplib.SMTP(SMTP_SERVER, 587)
    server.starttls()
    server.login(user, password)
    server.send_message(email_)
    server.quit()

def send_files_preconf(filepaths):
    """Send files using the config.ini settings.

    Args:
        filepaths (list(str)): A list of filepaths.
    """
    user, password, reciever = read_email_config(CONFIG_PATH)
    subject = "PDF files from pdfebc"
    message = ""
    send_with_attachments(
        user, password, reciever, subject, message, filepaths
        )

def valid_config_exists(config_path=CONFIG_PATH):
    """Verify that a valid config file exists.

    Args:
        config_path (str): Path to the config file.

    Returns:
        boolean: True if there is a valid config file, false if not.
    """
    if (os.path.isfile(config_path)):
        try:
            read_email_config(config_path)
        except configparser.ParsingError:
            return False
    else:
        return False
    return True



@@ -255,82 +255,252 @@
 ile 
-in $HOME/.config/pdfebc/config.ini that should look like:%0A    %5Bemail
+called 'email.cnf' in the user conf directory specified by appdirs. In the%0Acase of Arch Linux, this is '$HOME/.config/pdfebc/email.cnf', but this may vary with distributions.%0AThe config file should have the following format:%0A%0A    %7C%5BEMAIL
 %5D%0A    
+%7C
 user
@@ -515,24 +515,25 @@
 r_email%0A    
+%7C
 pass = passw
@@ -536,24 +536,25 @@
 assword%0A    
+%7C
 reciever = r
@@ -1723,27 +1723,39 @@
 config, 
-output_path
+config_path=CONFIG_PATH
 ):%0A    %22
@@ -1792,16 +1792,76 @@
 ut path.
+%0A    Creates the necessary directories if they aren't there.
 %0A%0A    Ar
@@ -1940,24 +1940,114 @@
     
-with open(output
+if not os.path.exists(config_path):%0A        os.makedirs(os.path.dirname(config_path))%0A    with open(config
 _pat
@@ -5905,10 +5905,8 @@
 rn True%0A
-%0A%0A

Update module docstring and check for dir before creating in write_config