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

# Copyright © 2012-2014 Roberto Alsina and others.

# Permission is hereby granted, free of charge, to any
# person obtaining a copy of this software and associated
# documentation files (the "Software"), to deal in the
# Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the
# Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice
# shall be included in all copies or substantial portions of
# the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

from __future__ import unicode_literals, print_function
import codecs
import datetime
import os
import sys

from blinker import signal

from nikola.plugin_categories import Command
from nikola import utils

LOGGER = utils.get_logger('new_post', utils.STDERR_HANDLER)


def filter_post_pages(compiler, is_post, compilers, post_pages):
    """Given a compiler ("markdown", "rest"), and whether it's meant for
    a post or a page, and compilers, return the correct entry from
    post_pages."""

    # First throw away all the post_pages with the wrong is_post
    filtered = [entry for entry in post_pages if entry[3] == is_post]

    # These are the extensions supported by the required format
    extensions = compilers[compiler]

    # Throw away the post_pages with the wrong extensions
    filtered = [entry for entry in filtered if any([ext in entry[0] for ext in
                                                    extensions])]

    if not filtered:
        type_name = "post" if is_post else "page"
        raise Exception("Can't find a way, using your configuration, to create "
                        "a {0} in format {1}. You may want to tweak "
                        "COMPILERS or POSTS/PAGES in conf.py".format(
                            type_name, compiler))
    return filtered[0]


def get_default_compiler(is_post, compilers, post_pages):
    """Given compilers and post_pages, return a reasonable
    default compiler for this kind of post/page.
    """

    # First throw away all the post_pages with the wrong is_post
    filtered = [entry for entry in post_pages if entry[3] == is_post]

    # Get extensions in filtered post_pages until one matches a compiler
    for entry in filtered:
        extension = os.path.splitext(entry[0])[-1]
        for compiler, extensions in compilers.items():
            if extension in extensions:
                return compiler
    # No idea, back to default behaviour
    return 'rest'


def get_date(schedule=False, rule=None, last_date=None, force_today=False):
    """Returns a date stamp, given a recurrence rule.

    schedule - bool:
        whether to use the recurrence rule or not

    rule - str:
        an iCal RRULE string that specifies the rule for scheduling posts

    last_date - datetime:
        timestamp of the last post

    force_today - bool:
        tries to schedule a post to today, if possible, even if the scheduled
        time has already passed in the day.
    """

    date = now = datetime.datetime.now()
    if schedule:
        try:
            from dateutil import rrule
        except ImportError:
            LOGGER.error('To use the --schedule switch of new_post, '
                         'you have to install the "dateutil" package.')
            rrule = None
    if schedule and rrule and rule:
        if last_date and last_date.tzinfo:
            # strip tzinfo for comparisons
            last_date = last_date.replace(tzinfo=None)
        try:
            rule_ = rrule.rrulestr(rule, dtstart=last_date)
        except Exception:
            LOGGER.error('Unable to parse rule string, using current time.')
        else:
            # Try to post today, instead of tomorrow, if no other post today.
            if force_today:
                now = now.replace(hour=0, minute=0, second=0, microsecond=0)
            date = rule_.after(max(now, last_date or now), last_date is None)
    return date.strftime('%Y/%m/%d %H:%M:%S')


class CommandNewPost(Command):
    """Create a new post."""

    name = "new_post"
    doc_usage = "[options] [path]"
    doc_purpose = "create a new blog post or site page"
    cmd_options = [
        {
            'name': 'is_page',
            'short': 'p',
            'long': 'page',
            'type': bool,
            'default': False,
            'help': 'Create a page instead of a blog post.'
        },
        {
            'name': 'title',
            'short': 't',
            'long': 'title',
            'type': str,
            'default': '',
            'help': 'Title for the page/post.'
        },
        {
            'name': 'tags',
            'long': 'tags',
            'type': str,
            'default': '',
            'help': 'Comma-separated tags for the page/post.'
        },
        {
            'name': 'onefile',
            'short': '1',
            'type': bool,
            'default': False,
            'help': 'Create post with embedded metadata (single file format)'
        },
        {
            'name': 'twofile',
            'short': '2',
            'type': bool,
            'default': False,
            'help': 'Create post with separate metadata (two file format)'
        },
        {
            'name': 'post_format',
            'short': 'f',
            'long': 'format',
            'type': str,
            'default': '',
            'help': 'Markup format for post, one of rest, markdown, wiki, '
                    'bbcode, html, textile, txt2tags',
        },
        {
            'name': 'schedule',
            'short': 's',
            'type': bool,
            'default': False,
            'help': 'Schedule post based on recurrence rule'
        },

    ]

    def _execute(self, options, args):
        """Create a new post or page."""
        compiler_names = [p.name for p in
                          self.site.plugin_manager.getPluginsOfCategory(
                              "PageCompiler")]

        if len(args) > 1:
            print(self.help())
            return False
        elif args:
            path = args[0]
        else:
            path = None

        is_page = options.get('is_page', False)
        is_post = not is_page
        title = options['title'] or None
        tags = options['tags']
        onefile = options['onefile']
        twofile = options['twofile']

        if twofile:
            onefile = False
        if not onefile and not twofile:
            onefile = self.site.config.get('ONE_FILE_POSTS', True)

        post_format = options['post_format']

        if not post_format:  # Issue #400
            post_format = get_default_compiler(
                is_post,
                self.site.config['COMPILERS'],
                self.site.config['post_pages'])

        if post_format not in compiler_names:
            LOGGER.error("Unknown post format " + post_format)
            return
        compiler_plugin = self.site.plugin_manager.getPluginByName(
            post_format, "PageCompiler").plugin_object

        # Guess where we should put this
        entry = filter_post_pages(post_format, is_post,
                                  self.site.config['COMPILERS'],
                                  self.site.config['post_pages'])

        print("Creating New Post")
        print("-----------------\n")
        if title is None:
            print("Enter title: ", end='')
            # WHY, PYTHON3???? WHY?
            sys.stdout.flush()
            title = sys.stdin.readline()
        else:
            print("Title:", title)
        if isinstance(title, utils.bytes_str):
            title = title.decode(sys.stdin.encoding)
        title = title.strip()
        if not path:
            slug = utils.slugify(title)
        else:
            if isinstance(path, utils.bytes_str):
                path = path.decode(sys.stdin.encoding)
            slug = utils.slugify(os.path.splitext(os.path.basename(path))[0])
        # Calculate the date to use for the post
        schedule = options['schedule'] or self.site.config['SCHEDULE_ALL']
        rule = self.site.config['SCHEDULE_RULE']
        force_today = self.site.config['SCHEDULE_FORCE_TODAY']
        self.site.scan_posts()
        timeline = self.site.timeline
        last_date = None if not timeline else timeline[0].date
        date = get_date(schedule, rule, last_date, force_today)
        data = [title, slug, date, tags]
        output_path = os.path.dirname(entry[0])
        meta_path = os.path.join(output_path, slug + ".meta")
        pattern = os.path.basename(entry[0])
        suffix = pattern[1:]
        if not path:
            txt_path = os.path.join(output_path, slug + suffix)
        else:
            txt_path = path

        if (not onefile and os.path.isfile(meta_path)) or \
                os.path.isfile(txt_path):
            LOGGER.error("The title already exists!")
            exit()

        d_name = os.path.dirname(txt_path)
        utils.makedirs(d_name)
        metadata = self.site.config['ADDITIONAL_METADATA']
        compiler_plugin.create_post(
            txt_path, onefile, title=title,
            slug=slug, date=date, tags=tags, **metadata)

        event = dict(path=txt_path)

        if not onefile:  # write metadata file
            with codecs.open(meta_path, "wb+", "utf8") as fd:
                fd.write('\n'.join(data))
            with codecs.open(txt_path, "wb+", "utf8") as fd:
                fd.write("Write your post here.")
            LOGGER.notice("Your post's metadata is at: {0}".format(meta_path))
            event['meta_path'] = meta_path
        LOGGER.notice("Your post's text is at: {0}".format(txt_path))

        signal('new_post').send(self, **event)
