import elasticsearch as es
import elasticsearch_dsl as es_dsl
import re
import json

from lobster.util import Configurable


class ElkInterface(Configurable):
    """
    Enables ELK stack monitoring using an existing Elasticsearch instance
    for the current Lobster run.

    Parameters
    ----------
        host : str
            Host running Elasticsearch cluster.
        port : int
            Port number running Elasticsearch HTTP service.
        user : str
            User ID to label Elasticsearch indices and Kibana objects.
        project : str
            Project ID to label Elasticsearch indices and Kibana objects.
        modules : list
            List of modules to include from the Kibana templates. Defaults to
            including only the core templates.
    """
    _mutable = {}

    def __init__(self, host, port, user, project, modules=None):
        self.host = host
        self.port = port
        self.user = user
        self.project = project
        self.modules = modules or ['core']
        self.client = es.Elasticsearch([{'host': self.host,
                                         'port': self.port}])
        self.generate_kibana_objects()

    def __getstate__(self):
        state = {'host': self.host,
                 'port': self.port,
                 'user': self.user,
                 'project': self.project,
                 'modules': self.modules}
        return state

    def __setstate__(self, state):
        self.host = state['host']
        self.port = state['port']
        self.user = state['user']
        self.project = state['project']
        self.modules = state['modules']
        self.client = es.Elasticsearch([{'host': self.host,
                                         'port': self.port}])

    def generate_kibana_objects(self):
        temp_prefix = '[template]'
        new_prefix = '[' + self.user + '_' + self.project + ']'
        other_prefix = re.compile('\[.*\]')

        search_index = es_dsl.Search(using=self.client, index='.kibana') \
            .filter('prefix', _id=temp_prefix) \
            .filter('match', _type='index-pattern')
        response_index = search_index.execute()

        for index in response_index:
            index.meta.id = index.meta.id.replace(temp_prefix, new_prefix, 1)
            index.title = index.title.replace(temp_prefix, new_prefix, 1)
            self.client.index(index='.kibana', doc_type=index.meta.doc_type,
                              id=index.meta.id, body=index.to_dict())

        for module in self.modules:
            temp_mod_prefix = temp_prefix + '[' + module + ']'
            new_mod_prefix = new_prefix + '[' + module + ']'

            search_vis = es_dsl.Search(using=self.client, index='.kibana') \
                .filter('prefix', _id=temp_mod_prefix) \
                .filter('match', _type='visualization')

            search_dash = es_dsl.Search(using=self.client, index='.kibana') \
                .filter('prefix', _id=temp_mod_prefix) \
                .filter('match', _type='dashboard')

            response_vis = search_vis.execute()
            response_dash = search_dash.execute()

            for vis in response_vis:
                vis.meta.id = vis.meta.id.replace(temp_mod_prefix,
                                                  new_mod_prefix, 1)
                vis.title = vis.title.replace(temp_mod_prefix,
                                              new_mod_prefix, 1)

                source = json.loads(vis.kibanaSavedObjectMeta.searchSourceJSON)
                source['index'] = other_prefix.sub(new_prefix, source['index'])
                vis.kibanaSavedObjectMeta.searchSourceJSON = json.dumps(source)

                self.client.index(index='.kibana', doc_type=vis.meta.doc_type,
                                  id=vis.meta.id, body=vis.to_dict())

            for dash in response_dash:
                dash.meta.id = dash.meta.id.replace(temp_mod_prefix,
                                                    new_mod_prefix, 1)
                dash.title = dash.title.replace(temp_mod_prefix,
                                                new_mod_prefix, 1)

                dash_panels = json.loads(dash.panelsJSON)
                for panel in dash_panels:
                    panel['id'] = panel['id'].replace(temp_mod_prefix,
                                                      new_mod_prefix, 1)
                dash.panelsJSON = json.dumps(dash_panels)

                self.client.index(index='.kibana', doc_type=dash.meta.doc_type,
                                  id=dash.meta.id, body=dash.to_dict())

@@ -1019,16 +1019,81 @@
 'core'%5D%0A
+        self.prefix = '%5B' + self.user + '_' + self.project + '%5D'%0A
         
@@ -1206,16 +1206,585 @@
 port%7D%5D)%0A
+%0A        indices = self.client.indices.get_aliases().keys()%0A        if any(self.prefix in s for s in indices):%0A            raise AttributeError(%22Elasticsearch indices with prefix %22 +%0A                                 self.prefix + %22 already exist.%22)%0A%0A        search = es_dsl.Search(using=self.client, index='.kibana') %5C%0A                 .filter('prefix', _id=self.prefix)%0A        response = search.execute()%0A        if len(response) %3E 0:%0A            raise AttributeError(%22Kibana objects with prefix %22 +%0A                                 self.prefix + %22 already exist.%22)%0A%0A
         
@@ -2033,16 +2033,56 @@
 .modules
+,%0A                 'prefix': self.prefix
 %7D%0A      
@@ -2314,16 +2314,54 @@
 dules'%5D%0A
+        self.prefix = state%5B'prefix'%5D%0A
         
@@ -2557,20 +2557,21 @@
         
-new_
+self.
 prefix =
@@ -2976,36 +2976,37 @@
 ce(temp_prefix, 
-new_
+self.
 prefix, 1)%0A     
@@ -3059,20 +3059,21 @@
 prefix, 
-new_
+self.
 prefix, 
@@ -3351,20 +3351,21 @@
 refix = 
-new_
+self.
 prefix +
@@ -4296,20 +4296,42 @@
 fix.sub(
-new_
+%0A                    self.
 prefix, 

Throw exception if Elasticsearch indices or Kibana objects already exist.