from object import Object
import colander, deform
from cms import dbutil
from bson.objectid import ObjectId
from cms.htmlutil import html_to_text
import widgets
import permissions
import repoze.workflow
import zope.interface
from pyramid import security
from interfaces import IContent, ITrash
import pyes

import logging
log = logging.getLogger(__name__)

class Content(Object):
    """ Base type for CMS content objects.
    Content is location-aware (uses the __parent__ attribute).
    Content is indexed in ElasticSearch.
    Content is workflowed with the "publication" workflow.
    """
    zope.interface.implements(IContent)

    _object_type = "content"

    def get_class_schema(cls, request=None):
        """ Return basic schema (title and description) for all Content.
        """
        schema = colander.SchemaNode(colander.Mapping())
        schema.add(colander.SchemaNode(colander.String(), name='title', include_in_other_text=False, widget=widgets.get_wide_text_widget()))

        schema.add(colander.SchemaNode(colander.String(), name='description', include_in_other_text=False, widget=widgets.get_wide_textarea_widget(rows=5)))
        return schema
    get_class_schema = classmethod(get_class_schema)

    def _get_nonschema_mongo_save_document(self):
        doc = Object._get_nonschema_mongo_save_document(self)
        doc['_object_type'] = self._object_type
        doc['__parent__'] = self.__parent__ and self.__parent__._id
        _pub_state = self.get_pub_state()
        if _pub_state: doc['_pub_state'] = _pub_state
        doc['_view'] = self._get_view_principals()
        doc['sortable_title'] = self.sortable_title.lower()
        doc['_in_trash'] = self.in_trash()
        return doc

    def _load_nonschema_attributes(self, **kwargs):
        Object._load_nonschema_attributes(self, **kwargs)
        _pub_state = kwargs.get('_pub_state')
        if _pub_state: self._pub_state = _pub_state

    def _get_view_principals(self):
        return list(security.principals_allowed_by_permission(self, permissions.VIEW))

    def _get_es_doctype(cls):
        #return "content"
        return cls._object_type
    _get_es_doctype = classmethod(_get_es_doctype)

    #
    # If you have the need to index additional attributes of a specific type,
    # override both _get_es_mapping() and _get_es_document() 
    # to call the base methods, get the returned dictionary, and add extra fields
    # to it before returning it.
    #
    # Note that for most types, this won't be necessary since colander.String schema
    # nodes will be added to the "other_text" index automatically (unless you explicitly
    # disable that behavior by setting include_in_other_text=False on the schema node).
    # 
    # If you have string fields that you want to use as categories, tags, or some other 
    # sort of value that you can filter on, be sure to:
    # 1. set include_in_other_text=False on the schema node
    # 2. set index="not_analyzed" in the mapping to disable tokenizing and allow the field 
    #    to be used for sorting
    # 

    def _get_es_mapping(cls):
        mapping = {}
        mapping['__name__'] = dict(type='string', include_in_all=False, index='not_analyzed')
        mapping['_view'] = dict(type='string', include_in_all=False, index='not_analyzed')
        mapping['_pub_state'] = dict(type='string', include_in_all=False, index='not_analyzed')
        mapping['_id_path'] = dict(type='string', include_in_all=False, index='not_analyzed')
        mapping['_object_type'] = dict(type='string', include_in_all=False, index='not_analyzed')
        mapping['title'] = dict(type='string', include_in_all=True, boost=4.0)