"Ideogenesis: Note pages."

from __future__ import print_function, absolute_import

import logging

import tornado.web

import ideogenesis
from . import constants
from . import neo4jdbi
from . import saver
from . import settings
from . import utils
from .requesthandler import RequestHandler


class NoteSaver(saver.Saver):
    "Save the Note data from HTML form input."

    NODE_LABELS = set([constants.ANY, constants.NOTE])

    def input_entry(self):
        try:
            iuid = self.rqh.get_argument('entry')
            self.entry = self.rqh.get_entry(iuid)
            if self.entry is None: raise ValueError
        except (tornado.web.MissingArgumentError, ValueError):
            raise ValueError('no entry provided')

    def input_title(self):
        try:
            title = self.rqh.get_argument('title')
            if not title: raise ValueError
            title_normalized = utils.normalize(title)
            if not title_normalized: raise ValueError
        except (tornado.web.MissingArgumentError, ValueError):
            raise ValueError('no title provided')
        self['title'] = title
        self['title_normalized'] = title_normalized

    def input_access(self):
        access = self.rqh.get_argument('access', default=constants.PRIVATE)
        self.public = access.lower() == constants.PUBLIC

    def input_text(self):
        self['text'] = self.rqh.get_argument('text', None)

    @property
    def node_labels(self):
        "Return the labels to use for a node."
        result = set(self.NODE_LABELS)
        if self.public:
            result.add(constants.PUBLIC)
        return result

    def after_created(self):
        self.rqh.neo4j.create_relationship(self.node,
                                           self.entry,
                                           constants.TARGET)
        self.rqh.neo4j.create_relationship(self.rqh.current_user,
                                           self.node,
                                           constants.OWNS)


class NoteMixin(object):
    "Some useful methods for Note pages."

    def get_note_owner(self, note):
        "Get the user node for the owner of the note."
        statement = 'MATCH (n:Note {iuid:{iuid}})<-[:OWNS]-(u:User)' \
                    ' RETURN id(u)'
        nodes = self.neo4j.get_nodes_execute(statement, iuid=note['iuid'])
        if len(nodes) > 1:
            raise tornado.web.HTTPError(500, reason='multiple nodes matched')
        elif not nodes:
            return None
        return nodes[0]

    def get_note_entry(self, note):
        "Get the entry node for the note."
        statement = 'MATCH (n:Note {iuid:{iuid}})-[:TARGET]->(e:Entry)' \
                    ' RETURN id(e)'
        nodes = self.neo4j.get_nodes_execute(statement, iuid=note['iuid'])
        if len(nodes) > 1:
            raise tornado.web.HTTPError(500, reason='multiple nodes matched')
        elif not nodes:
            return None
        return nodes[0]

    def check_owner(self, note):
        owner = self.get_note_owner(note)
        if owner is not self.current_user:
            raise tornado.web.HTTPError(403, reason='user is not owner')


class Note(NoteMixin, RequestHandler):
    "Note page."

    def get(self, iuid):
        note = self.get_node(constants.NOTE, iuid=iuid)
        if note is None:
            raise tornado.web.HTTPError(404, reason='no such note')
        owner = self.get_note_owner(note)
        is_owner = owner is self.current_user
        if constants.PUBLIC not in note.labels and not is_owner:
            raise tornado.web.HTTPError(403, reason='note is not public')
        self.render('note.html',
                    note=note,
                    is_owner=is_owner,
                    owner=owner,
                    entry=self.get_note_entry(note))

    @tornado.web.authenticated
    def post(self, iuid):
        self.check_xsrf_cookie()
        if self.get_argument('_http_method', None) == 'delete':
            self.delete(iuid)
            return
        raise tornado.web.HTTPError(405, reason='POST only allowed for DELETE')

    @tornado.web.authenticated
    def delete(self, iuid):
        self.check_curator()
        note = self.get_node(constants.NOTE, iuid=iuid)
        if note is None:
            raise tornado.web.HTTPError(404)
        with neo4jdbi.Transaction(self.neo4j) as trx:
            # Delete Logs and their relationships with the Note
            stmt = 'MATCH (:Note {iuid:{iuid}})-[r]-(l:Log)-[o]-()' \
                   ' DELETE r,l,o'
            trx.execute(stmt, iuid=note['iuid'])
            stmt = 'MATCH (:Note {iuid:{iuid}})-[o]-(:User) DELETE o'
            trx.execute(stmt, iuid=iuid)
            stmt = 'MATCH (n:Note {iuid:{iuid}})-[t]-() DELETE n,t'
            trx.execute(stmt, iuid=iuid)