# Path: narrative/models.py
# class Datum(models.Model):
#     # When was the datum created
#     timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
#     expiration_time = models.DateTimeField(null=True, blank=True, default=None)
#     # Origin of this datum; ie, what piece of software created it
#     origin = models.CharField(max_length=64)
#     datum_name = models.CharField(max_length=64)
# 
#     # Additional information about the datum; this is very datum specific
#     # This approach, storing json in a textfield and having an
#     # explicit accessor and mutator, is very ugly.  Really this is because
#     # we are storing non-structured/sparse data in a relational format.
#     datum_note_json = models.TextField(null=True, blank=True, default=None)
# 
#     # An ID to tie particular datums together
#     thread_id = models.CharField(max_length=36, null=True, blank=True)
# 
#     log_level = models.IntegerField(choices=DatumLogLevel.types, default=DatumLogLevel.INFO)
# 
#     objects = DatumManager()
# 
#     def __init__(self, *args, **kwargs):
#         if 'ttl' in kwargs:
#             kwargs['expiration_time'] = self.get_utc_now() + kwargs.pop('ttl')
# 
#         super(Datum, self).__init__(*args, **kwargs)
# 
#     def __str__(self):
#         note_snippet = self.datum_note_json[:50] if self.datum_note_json else ''
#         return 'origin:{0} datum_name:{1} note:{2}'.format(
#             self.origin, self.datum_name, note_snippet
#         )
# 
#     def get_note(self):
#         if self.datum_note_json:
#             return json.loads(self.datum_note_json)
#         else:
#             return []
# 
#     def set_note(self, note):
#         self.datum_note_json = json.dumps(note)
# 
#     def get_utc_now(self):
#         return utc_tz.localize(datetime.datetime.utcnow())
# 
#     @property
#     def timestamp_with_tz(self):
#         return utc_tz.localize(self.timestamp)
# 
#     def save(self, *args, **kwargs):
#         if None == self.thread_id:
#             self.thread_id = str(uuid.uuid4())
# 
#         super(Datum, self).save(*args, **kwargs)
# 
# Path: narrative/executor.py
# class Executor(object):
#     def get_action_handler(self, action_name):
#         return 'do_{0}'.format(action_name)
# 
#     def can_execute(self, action_sequence):
#         """"
#         Examine all of the steps in an action sequence and verify
#         that they are supported by the Executor.
#         """
#         for step in action_sequence:
#             action, kwargs = step
# 
#             if not hasattr(self, self.get_action_handler(action)):
#                 return (False, step)
#         else:
#             return (True, None)
# 
#     def execute(self, action_sequence):
#         for step in action_sequence:
#             action, kwargs = step
# 
#             getattr(self, self.get_action_handler(action))(**kwargs)
# 
#     # do_* methods for executing particular operations such as notifying individuals ---
#     def do_defer_to_admins(self, subject, message, message_html=None):
#         admin_group = Group.objects.get(name=settings.NARRATIVE_ADMIN_GROUP_NAME)
#         admins = admin_group.user_set.all()
# 
#         admin_emails = [admin.email for admin in admins]
# 
#         blast_email(subject, message, message_html, admin_emails)
# 
#     def do_defer_multiple_solutions_to_admins(self, resolution_steps, assertion_display_name):
#         subject = 'Impasse: "{0}" has Multiple resolution steps proposed'.format(
#             assertion_display_name)
# 
#         message_kwargs = {
#             'assertion_name': assertion_display_name,
#             'solution_count': len(resolution_steps),
#             'proposed_steps': resolution_steps,
#         }
# 
#         message = render_to_string(
#             'multiple_solution_impasse_message.txt',
#             message_kwargs)
#         message_html = render_to_string(
#             'multiple_solution_impasse_message.html',
#             message_kwargs)
# 
#         self.do_defer_to_admins(subject, message, message_html)
# 
#     def do_email(self, address, subject, message_txt, message_html):
#         blast_email(subject, message_txt, message_html, [address])


import abc
import copy
import datetime
import json
import six
from narrative.models import Datum
from narrative.executor import Executor


class Event(six.with_metaclass(abc.ABCMeta, object)):

    def __init__(self, event_meta):
        self.event_meta = event_meta

    @property
    def args(self):
        return self.event_meta.get_args()

    @abc.abstractmethod
    def detect(self, *args, **kwargs):
        pass

    @abc.abstractmethod
    def instance_summary(self, *args, **kwargs):
        """
        Return any additional information we want to associate with this
        occurrence of this event; this is needed to separate this occurrence
        from other occurrences of the same event.
        """
        return {}

    @property
    def summary_datum_ttl(self):
        return None

    @property
    def executor(self):

# Path: narrative/models.py
# class Datum(models.Model):
#     # When was the datum created
#     timestamp = models.DateTimeField(auto_now_add=True, db_index=True)
#     expiration_time = models.DateTimeField(null=True, blank=True, default=None)
#     # Origin of this datum; ie, what piece of software created it
#     origin = models.CharField(max_length=64)
#     datum_name = models.CharField(max_length=64)
# 
#     # Additional information about the datum; this is very datum specific
#     # This approach, storing json in a textfield and having an
#     # explicit accessor and mutator, is very ugly.  Really this is because
#     # we are storing non-structured/sparse data in a relational format.
#     datum_note_json = models.TextField(null=True, blank=True, default=None)
# 
#     # An ID to tie particular datums together
#     thread_id = models.CharField(max_length=36, null=True, blank=True)
# 
#     log_level = models.IntegerField(choices=DatumLogLevel.types, default=DatumLogLevel.INFO)
# 
#     objects = DatumManager()
# 
#     def __init__(self, *args, **kwargs):
#         if 'ttl' in kwargs:
#             kwargs['expiration_time'] = self.get_utc_now() + kwargs.pop('ttl')
# 
#         super(Datum, self).__init__(*args, **kwargs)
# 
#     def __str__(self):
#         note_snippet = self.datum_note_json[:50] if self.datum_note_json else ''
#         return 'origin:{0} datum_name:{1} note:{2}'.format(
#             self.origin, self.datum_name, note_snippet
#         )
# 
#     def get_note(self):
#         if self.datum_note_json:
#             return json.loads(self.datum_note_json)
#         else:
#             return []
# 
#     def set_note(self, note):
#         self.datum_note_json = json.dumps(note)
# 
#     def get_utc_now(self):
#         return utc_tz.localize(datetime.datetime.utcnow())
# 
#     @property
#     def timestamp_with_tz(self):
#         return utc_tz.localize(self.timestamp)
# 
#     def save(self, *args, **kwargs):
#         if None == self.thread_id:
#             self.thread_id = str(uuid.uuid4())
# 
#         super(Datum, self).save(*args, **kwargs)
# 
# Path: narrative/executor.py
# class Executor(object):
#     def get_action_handler(self, action_name):
#         return 'do_{0}'.format(action_name)
# 
#     def can_execute(self, action_sequence):
#         """"
#         Examine all of the steps in an action sequence and verify
#         that they are supported by the Executor.
#         """
#         for step in action_sequence:
#             action, kwargs = step
# 
#             if not hasattr(self, self.get_action_handler(action)):
#                 return (False, step)
#         else:
#             return (True, None)
# 
#     def execute(self, action_sequence):
#         for step in action_sequence:
#             action, kwargs = step
# 
#             getattr(self, self.get_action_handler(action))(**kwargs)
# 
#     # do_* methods for executing particular operations such as notifying individuals ---
#     def do_defer_to_admins(self, subject, message, message_html=None):
#         admin_group = Group.objects.get(name=settings.NARRATIVE_ADMIN_GROUP_NAME)
#         admins = admin_group.user_set.all()
# 
#         admin_emails = [admin.email for admin in admins]
# 
#         blast_email(subject, message, message_html, admin_emails)
# 
#     def do_defer_multiple_solutions_to_admins(self, resolution_steps, assertion_display_name):
#         subject = 'Impasse: "{0}" has Multiple resolution steps proposed'.format(
#             assertion_display_name)
# 
#         message_kwargs = {
#             'assertion_name': assertion_display_name,
#             'solution_count': len(resolution_steps),
#             'proposed_steps': resolution_steps,
#         }
# 
#         message = render_to_string(
#             'multiple_solution_impasse_message.txt',
#             message_kwargs)
#         message_html = render_to_string(
#             'multiple_solution_impasse_message.html',
#             message_kwargs)
# 
#         self.do_defer_to_admins(subject, message, message_html)
# 
#     def do_email(self, address, subject, message_txt, message_html):
#         blast_email(subject, message_txt, message_html, [address])


# Path: narrative/events.py
import abc
import copy
import datetime
import json
import six
from narrative.models import Datum
from narrative.executor import Executor



class Event(six.with_metaclass(abc.ABCMeta, object)):

    def __init__(self, event_meta):
        self.event_meta = event_meta

    @property
    def args(self):
        return self.event_meta.get_args()

    @abc.abstractmethod
    def detect(self, *args, **kwargs):
        pass

    @abc.abstractmethod
    def instance_summary(self, *args, **kwargs):
        """
        Return any additional information we want to associate with this
        occurrence of this event; this is needed to separate this occurrence
        from other occurrences of the same event.
        """
        return {}

    @property
    def summary_datum_ttl(self):
        return None

    @property
    def executor(self):

        return Executor()