# Kanbanara API Component
# Written by Rebecca Shalfield between 2013 and 2017
# Copyright (c) Rebecca Shalfield 2013-2017
# Released under the GNU AGPL v3

'''Kanbanara's API Component'''

import datetime
import json
import logging
import os
import re
import urllib.parse
import uuid
import cherrypy
from kanbanara import Kanbanara
from pymongo import MongoClient


class Api(Kanbanara):
    '''Kanbanara's API Component'''

    @cherrypy.expose
    def rest_api_get_project_members(self, token, project):
        """Get a list of a member's projects via the Rest API by passing in a token"""
        if project and token and token in self.rest_api_tokens:
            username = self.rest_api_tokens[token]
            members = set()
            for member_document in self.members_collection.find({'username': {'$exists': True,
                                                                              '$nin': ['', None]},
                                                                 'projects.project': project}):
                members.add(member_document['username'])

            members = list(members)
            members.sort()
            return '\n'.join(members)

        return

    @cherrypy.expose
    def rest_api_get_projects(self, token):
        """Get a list of a member's projects via the Rest API by passing in a token"""
        if token and token in self.rest_api_tokens:
            username = self.rest_api_tokens[token]
            member_document = self.members_collection.find_one({"username": username})
            projects = self.get_member_projects(member_document)
            return '\n'.join(projects)

        return

    @cherrypy.expose
    def rest_api_get_token(self, username, password):
        """Allows a user to log on to Kanbanara via the Rest API and receive a token"""
        if username and password:
            if self.vault_members_collection.find({'username': username,
                                                   'password': password}).count():
                token = uuid.uuid4().hex
                while token in self.rest_api_tokens:
                    token = uuid.uuid4().hex

                self.rest_api_tokens[token] = username
                return token

        return

    def __init__(self):
        """Initialisation"""
        self.component = 'api'

        Kanbanara.__init__(self)

        self.current_dir = os.path.dirname(os.path.abspath(__file__))

        logging.basicConfig(level=logging.DEBUG,
                            format='%(asctime)s - %(levelname)s - %(message)s',
                            filename=os.path.join(self.current_dir, '..', 'logs', 'kanbanara.log'),
                            filemode='w'
                           )

        self.rest_api_tokens = {}

        self.filter_bar_component_statistics = {'card':           ('Card',             'dynamic'),
                                                'category':       ('Category',         'dynamic'),
                                                'classofservice': ('Class Of Service', 'dynamic'),
                                                'columns':        ('Columns',          'static'),
                                                'customer':       ('Customer',         'dynamic'),
                                                'fontsize':       ('Font Size',        'dynamic'),
                                                'hashtag':        ('Hashtag',          'dynamic'),
                                                'iteration':      ('Iteration',        'dynamic'),
                                                'kanbanboard':    ('Kanban Board',     'static'),
                                                'priority':       ('Priority',         'dynamic'),
                                                'project':        ('Project',          'static'),
                                                'release':        ('Release',          'dynamic'),
                                                'severity':       ('Severity',         'dynamic'),
                                                'subteam':        ('Subteam',          'dynamic'),
                                                'swimlanes':      ('Swim Lanes',       'dynamic'),
                                                'teammember':     ('Team Member',      'static'),
                                                'type':           ('Type',             'static')}

        Kanbanara.read_administrator_ini_file(self)

        # Initialisation Settings
        self.mongodb_host, self.mongodb_port, self.mongodb_username, self.mongodb_password, self.mongodb_bindir = Kanbanara.read_mongodb_ini_file(self)

        # Connect to MongoDB on given host and port
        if self.mongodb_username and self.mongodb_password:
            modified_username = urllib.parse.quote_plus(self.mongodb_username)
            modified_password = urllib.parse.quote_plus(self.mongodb_password)
            connection = MongoClient('mongodb://' + modified_username + ':' + modified_password +
                                     '@' + self.mongodb_host + ':' + str(self.mongodb_port))
        else:
            connection = MongoClient(self.mongodb_host, self.mongodb_port)

        # Connect to 'kanbanara' database, creating if not already exists
        kanbanara_db = connection['kanbanara']

        # Connect to 'projects' collection
        self.projects_collection = kanbanara_db['projects']
        for attribute in ['project']:
            self.projects_collection.create_index(attribute, unique=True, background=True)

        # Connect to 'sessions' collection
        self.sessions_collection = kanbanara_db['sessions']
        for attribute in ['session_id']:
            self.sessions_collection.create_index(attribute, unique=True, background=True)

        for attribute in ['lastaccess']:
            self.sessions_collection.create_index(attribute, unique=False, background=True)

        # Connect to 'members' collection
        self.members_collection = kanbanara_db['members']
        for attribute in ['username']:
            # TODO - username attribute should be unique but get error when unique=true set
            self.members_collection.create_index(attribute, unique=False, background=True)

        # Connect to 'cards' collection
        self.cards_collection = kanbanara_db['cards']
        for attribute in ['id']:
            self.cards_collection.create_index(attribute, unique=True, background=True)

        for attribute in ['description', 'iteration', 'project', 'release', 'state']:
            self.cards_collection.create_index(attribute, unique=False, background=True)

        # Connect to 'vault' database, creating if not already exists
        vault_db = connection['vault']

        # Connect to 'vault members' collection
        self.vault_members_collection = vault_db['members']

    @cherrypy.expose
    def index(self):
        """Redirects you to the kanban board"""
        raise cherrypy.HTTPRedirect("/kanban", 302)

    @cherrypy.expose
    def api_synchronise_card(self, data=""):
        """Called by slave end and run at master end to synchronise an individual card"""
        content = ""
        card_document_as_json = urllib.parse.unquote(data)
        slave_card_document = json.loads(card_document_as_json)
        if self.cards_collection.find({'id': slave_card_document['id']}).count():
            master_card_document = self.cards_collection.find_one({'id': slave_card_document['id']})
            if slave_card_document['lastchanged'] > master_card_document['lastchanged']:
                slave_card_document['_id'] = master_card_document['_id']
                self.cards_collection.save(slave_card_document)

        else:
            # TODO - Need to update temp id used by children and parent cards
            temp_id = slave_card_document['id']
            real_id = self.get_project_next_card_number(slave_card_document['project'], '')
            slave_card_document['id'] = real_id
            doc_id = self.cards_collection.insert(slave_card_document)
            self.save_card_as_json(slave_card_document)
            content = real_id

        return content

    @cherrypy.expose
    def api_synchronise_member(self, data=""):
        """Called by slave end and run at master end to synchronise an individual member"""
        # TODO - Also need an api_request_member(username) function
        content = ""
        member_document_as_json = urllib.parse.unquote(data)
        slave_member_document = json.loads(member_document_as_json)
        if self.members_collection.find({'username': slave_member_document['username']}).count():
            master_member_document = self.members_collection.find_one({'username': slave_member_document['username']})
            # TODO - Do member document have lastchanged attribute?
            if slave_member_document['lastchanged'] > master_member_document['lastchanged']:
                slave_member_document['_id'] = master_member_document['_id']
                self.members_collection.save(slave_member_document)

        else:
            self.members_collection.insert(slave_member_document)
            self.save_member_as_json(slave_member_document)

        return content

    @cherrypy.expose
    def tokens(self, adminusername="", adminpassword=""):
        username = Kanbanara.check_authentication(f'/{self.component}/tokens')
        session_id = Kanbanara.cookie_handling(self)
        session_document = self.sessions_collection.find_one({"session_id": session_id})
        content = []
        content.append(Kanbanara.header(self, "tokens", "Rest API Tokens"))
        content.append(Kanbanara.filter_bar(self, 'tokens'))
        content.append(Kanbanara.menubar(self))
        content.append('<div align="center">')
        content.append(self.insert_page_title_and_online_help(session_document, "tokens", "Rest API Tokens"))
        if adminusername and adminpassword:
            if adminusername == self.kanbanara_settings['admin_username'] and adminpassword == self.kanbanara_settings['admin_password']:
                content.append('<table class="sortable"><tr><th>Rest API Token</th><th>Username</th></tr>')
                for token in self.rest_api_tokens.keys():
                    content.append('<tr><td>'+token+'</td><td>'+self.rest_api_tokens[token]+'</td></tr>')

                content.append('</table>')
            else:
                raise cherrypy.HTTPError(401, 'Unauthorised')

        else:
            content.append('<form action="/api/tokens" method="post">')
            content.append('<table border="0"><tr><td align="right">Administrator Username</td><td>')
            content.append('<input type="password" size="40" name="adminusername" placeholder="Username">')
            content.append('</td></tr><tr><td align="right">Administrator Password</td><td><input type="password" size="40" name="adminpassword" placeholder="Password"></td></tr><tr><td align="center" colspan="2"><input class="button" type="submit" value="Enter"></td></tr></table></form>')

        content.append('</div>')
        content.append(Kanbanara.footer(self))
        return "".join(content)

CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))
conf = {'/': {'tools.staticdir.root':   CURRENT_DIR,
              'tools.sessions.on':      True,
              'tools.sessions.locking': 'explicit'
              }}
for directory in ['css', 'images']:
    if os.path.exists(CURRENT_DIR+os.sep+directory):
        conf['/'+directory] = {'tools.staticdir.on':  True,
                               'tools.staticdir.dir': directory}

cherrypy.tree.mount(Api(), '/api', config=conf)
