# -*- coding: utf-8 -*-
from cms import constants
from cms.utils.conf import get_cms_setting
from django.core.exceptions import PermissionDenied
from cms.exceptions import NoHomeFound, PublicIsUnmodifiable
from cms.models.managers import PageManager, PagePermissionsPermissionManager
from cms.models.metaclasses import PageMetaClass
from cms.models.placeholdermodel import Placeholder
from cms.models.pluginmodel import CMSPlugin
from cms.publisher.errors import MpttPublisherCantPublish
from cms.utils import i18n, page as page_utils
from cms.utils import timezone
from cms.utils.copy_plugins import copy_plugins_to
from cms.utils.helpers import reversion_register
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.db import models
from django.shortcuts import get_object_or_404
from django.utils.translation import get_language, ugettext_lazy as _
from menus.menu_pool import menu_pool
from mptt.models import MPTTModel
from os.path import join
from datetime import timedelta
import copy


class Page(MPTTModel):
    """
    A simple hierarchical page model
    """
    __metaclass__ = PageMetaClass
    LIMIT_VISIBILITY_IN_MENU_CHOICES = (
        (1, _('for logged in users only')),
        (2, _('for anonymous users only')),
    )
    PUBLISHER_STATE_DEFAULT = 0
    PUBLISHER_STATE_DIRTY = 1
    PUBLISHER_STATE_DELETE = 2
    # Page was marked published, but some of page parents are not.
    PUBLISHER_STATE_PENDING = 4

    template_choices = [(x, _(y)) for x, y in get_cms_setting('TEMPLATES')]

    created_by = models.CharField(_("created by"), max_length=70, editable=False)
    changed_by = models.CharField(_("changed by"), max_length=70, editable=False)
    parent = models.ForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
    creation_date = models.DateTimeField(auto_now_add=True)
    changed_date = models.DateTimeField(auto_now=True)

    publication_date = models.DateTimeField(_("publication date"), null=True, blank=True, help_text=_('When the page should go live. Status must be "Published" for page to go live.'), db_index=True)
    publication_end_date = models.DateTimeField(_("publication end date"), null=True, blank=True, help_text=_('When to expire the page. Leave empty to never expire.'), db_index=True)
    in_navigation = models.BooleanField(_("in navigation"), default=True, db_index=True)
    soft_root = models.BooleanField(_("soft root"), db_index=True, default=False, help_text=_("All ancestors will not be displayed in the navigation"))
    reverse_id = models.CharField(_("id"), max_length=40, db_index=True, blank=True, null=True, help_text=_("An unique identifier that is used with the page_url templatetag for linking to this page"))
    navigation_extenders = models.CharField(_("attached menu"), max_length=80, db_index=True, blank=True, null=True)
    published = models.BooleanField(_("is published"), blank=True)

    template = models.CharField(_("template"), max_length=100, choices=template_choices, help_text=_('The template used to render the content.'))
    site = models.ForeignKey(Site, help_text=_('The site the page is accessible at.'), verbose_name=_("site"))

    login_required = models.BooleanField(_("login required"), default=False)
    limit_visibility_in_menu = models.SmallIntegerField(_("menu visibility"), default=None, null=True, blank=True, choices=LIMIT_VISIBILITY_IN_MENU_CHOICES, db_index=True, help_text=_("limit when this page is visible in the menu"))

    level = models.PositiveIntegerField(db_index=True, editable=False)
    lft = models.PositiveIntegerField(db_index=True, editable=False)
    rght = models.PositiveIntegerField(db_index=True, editable=False)
    tree_id = models.PositiveIntegerField(db_index=True, editable=False)

    # Placeholders (plugins)
    placeholders = models.ManyToManyField(Placeholder, editable=False)

    # Publisher fields
    moderator_state = models.SmallIntegerField(_('moderator state'), default=0, blank=True, editable=False)
    publisher_is_draft = models.BooleanField(default=1, editable=False, db_index=True)
    # This is misnamed - the one-to-one relation is populated on both ends
    publisher_public = models.OneToOneField('self', related_name='publisher_draft', null=True, editable=False)
    publisher_state = models.SmallIntegerField(default=0, editable=False, db_index=True)

    # Managers
    objects = PageManager()
    permissions = PagePermissionsPermissionManager()

    class Meta:
        permissions = (
            ('view_page', 'Can view page'),
            ('publish_page', 'Can publish page'),
        )
        verbose_name = _('page')
        verbose_name_plural = _('pages')
        ordering = ('tree_id', 'lft')
        app_label = 'cms'

    class PublisherMeta:
        exclude_fields_append = ['id', 'publisher_is_draft', 'publisher_public',
                                 'publisher_state', 'moderator_state',
                                 'placeholders', 'lft', 'rght', 'tree_id',
                                 'parent']

    def __unicode__(self):
        title = self.get_menu_title(fallback=True)
        if title is None:
            title = u""
        return unicode(title)

    def is_dirty(self):
        return self.publisher_state == self.PUBLISHER_STATE_DIRTY

    def get_absolute_url(self, langua
ge=None, fallback=True):
        if 
self.is_home():
            return reverse('pages-root')
        path = self.get_path(language, fallback) or self.get_slug(language, fallback)
        return reverse('pages-details-by-slug', kwargs={"slug": path})

    def move_page(self, target, position='first-child'):
        """
        Called from admin interface when page is moved. Should be used on
        all the places which are changing page position. Used like an interface
        to mptt, but after move is done page_moved signal is fired.

        Note for issue #1166: url conflicts are handled by updated
        check_title_slugs, overwrite_url on the moved page don't need any check
        as it remains the same regardless of the page position in the tree
        """
        # make sure move_page does not break when using INHERIT template
        # and moving to a top level position
        if (position in ('left', 'right')
            and not target.parent
            and self.template == constants.TEMPLATE_INHERITANCE_MAGIC):
            self.template = self.get_template()
        self.move_to(target, position)

        # fire signal
        from cms.models.moderatormodels import PageModeratorState
        from cms.utils import moderator
        import cms.signals as cms_signals
        cms_signals.page_moved.send(sender=Page, instance=self)  # titles get saved before moderation
        self.save()  # always save the page after move, because of publisher
        moderator.page_changed(self, force_moderation_action=PageModeratorState.ACTION_MOVE)
        # check the slugs
        page_utils.check_title_slugs(self)

    def _copy_titles(self, target):
        """
        Copy all the titles to a new page (which must have a pk).
        :param target: The page where the new titles should be stored
        """
        old_titles = dict(target.title_set.values_list('language', 'pk'))
        for title in self.title_set.all():
            # If an old title exists, overwrite. Otherwise create new
            title.pk = old_titles.pop(title.language, None)
            title.page = target
            title.save()
        if old_titles:
            from titlemodels import Title
            Title.objects.filter(id__in=old_titles.values()).delete()

    def _copy_contents(self, target):
        """
        Copy all the plugins to a new page.
        :param target: The page where the new content should be stored
        """
        # TODO: Make this into a "graceful" copy instead of deleting and overwriting
        # copy the placeholders (and plugins on those placeholders!)
        CMSPlugin.objects.filter(placeholder__page=target).delete()
        for ph in self.placeholders.all():
            plugins = ph.get_plugins_list()
            try:
     