class Context(ContextBase):
    """A context class that holds the data for every reportable element in the ODM response"""

    def __init__(self, study_oid, subcategory, metadata_version):
        self.study_oid = study_oid
        self.subcategory = subcategory
        self.metadata_version = metadata_version
        self.subject = None
        self.event = None
        self.form = None
        self.itemgroup = None
        self.item = None
        self.audit_record = AuditRecord()
        self.query = None
        self.protocol_deviation = None
        self.comment = None
        self.review = None
        self.signature = Signature() class Subject(ContextBase):
    def __init__(self, key, name, status, transaction_type):
        self.key = key
        self.name = name
        self.status = status
        self.transaction_type = transaction_type class Event(ContextContainer):
    def __init__(self, oid, repeat_key, transaction_type, instance_name, instance_overdue, instance_id):
        ContextContainer.__init__(self, oid, repeat_key, transaction_type)
        self.instance_name = instance_name
        self.instance_overdue = instance_overdue
        self.instance_id = instance_id class Form(ContextContainer):
    def __init__(self, oid, repeat_key, transaction_type, datapage_name, datapage_id):
        ContextContainer.__init__(self, oid, repeat_key, transaction_type)
        self.datapage_name = datapage_name
        self.datapage_id = datapage_id class ItemGroup(ContextContainer):
    def __init__(self, oid, repeat_key, transaction_type, record_id):
        ContextContainer.__init__(self, oid, repeat_key, transaction_type)
        self.record_id = record_id class Item(ContextBase):
    def __init__(self, oid, value, specify_value, signature_broken, freeze, verify, lock, transaction_type):
        self.oid = oid
        self.value = value
        self.specify_value = specify_value
        self.signature_broken = signature_broken
        self.freeze = freeze
        self.verify = verify
        self.lock = lock
        self.transaction_type = transaction_type class Query(ContextBase):
    """Query related attributes"""

    def __init__(self, repeat_key, status, response, recipient, value):
        self.repeat_key = repeat_key
        self.status = status
        self.response = response
        self.recipient = recipient
        self.value = value class Review(ContextBase):
    """Review related attributes"""

    def __init__(self, group_name, reviewed):
        self.group_name = group_name
        self.reviewed = reviewed class Comment(ContextBase):
    """Review related attributes"""

    def __init__(self, repeat_key, value, transaction_type):
        self.repeat_key = int(repeat_key) if repeat_key else repeat_key
        self.value = value
        self.transaction_type = transaction_type class ProtocolDeviation(ContextBase):
    """Protocol Deviation related attributes"""

    def __init__(self, repeat_key, code, klass, status, value, transaction_type):
        self.repeat_key = repeat_key
        self.code = code
        self.klass = klass
        self.status = status
        self.value = value
        self.transaction_type = transaction_type
import six
import datetime
from lxml import etree
from rwslib.extras.audit_event.context import (Context, Subject, Event,
                                                Form, ItemGroup, Item,
                                                Query, Review, Comment,
                                                ProtocolDeviation)
A_CLASS = 'Class'  # PV
A_CODE = 'Code'  # PV
A_REVIEWED = 'Reviewed'  # Reviews
A_GROUP_NAME = 'GroupName'
A_COMMENT_REPEAT_KEY = 'CommentRepeatKey'
A_INSTANCE_ID = mdsol('InstanceId')
A_INSTANCE_NAME = mdsol('InstanceName')
A_INSTANCE_OVERDUE = mdsol('InstanceOverdue')
A_DATAPAGE_NAME = mdsol('DataPageName')
A_DATAPAGE_ID = mdsol('DataPageId')
A_SIGNATURE_OID = 'SignatureOID'
A_SPECIFY_VALUE = mdsol('SpecifyValue')
A_SIGNATURE_BROKEN = mdsol('SignatureBroken')



# Elements
E_CLINICAL_DATA = odm('ClinicalData')
E_SUBJECT_DATA = odm('SubjectData')
E_USER_REF = odm('UserRef')
E_SOURCE_ID = odm('SourceID')
E_DATE_TIME_STAMP_ = odm('DateTimeStamp')
E_REASON_FOR_CHANGE = odm('ReasonForChange')
E_LOCATION_REF = odm('LocationRef')
E_STUDY_EVENT_DATA = odm('StudyEventData')
E_FORM_DATA = odm('FormData')
E_ITEM_GROUP_DATA = odm('ItemGroupData')
E_ITEM_DATA = odm('ItemData')
E_QUERY = mdsol('Query')
E_PROTOCOL_DEVIATION = mdsol('ProtocolDeviation')
E_REVIEW = mdsol('Review')
E_COMMENT = mdsol('Comment')
E_SIGNATURE = odm('Signature')
E_SIGNATURE_REF = odm('SignatureRef')

# Parser States
STATE_NONE = 0
STATE_SOURCE_ID = 1
STATE_DATETIME = 2
STATE_REASON_FOR_CHANGE = 3

# Signature elements have some of the same elements as Audits. Tells us which we are collecting
AUDIT_REF_STATE = 0
SIGNATURE_REF_STATE = 1


class ODMTargetParser(object):
    """A SAX-style lxml Target parser class"""

    def __init__(self, handler):

        # Handler, object that deals with emitting entries etc
        self.handler = handler

        # Context holds the current set of values we are building up, ready to emit
        self.context = None

        # State controls when we are looking for element text content what attribute to put it in
        self.state = STATE_NONE

        # Count of elements processed
        self.count = 0

        self.ref_state = AUDIT_REF_STATE

    def emit(self):
        """We are finished processing one element. Emit it"""

        self.count += 1

        # event_name = 'on_{0}'.format(self.context.subcategory.lower())
        event_name = self.context.subcategory
        if hasattr(self.handler, event_name):
            getattr(self.handler, event_name)(self.context)
        elif hasattr(self.handler, 'default'):
            self.handler.default(self.context)

    def start(self, tag, attrib):
        """On start of element tag"""
        if tag == E_CLINICAL_DATA:
            self.ref_state = AUDIT_REF_STATE
            self.context = Context(attrib[A_STUDY_OID],
                                   attrib[A_AUDIT_SUBCATEGORY_NAME],
                                   int(attrib[A_METADATA_VERSION_OID]))

        elif tag == E_SUBJECT_DATA:
            self.context.subject = Subject(
                attrib.get(A_SUBJECT_KEY),
                attrib.get(A_SUBJECT_NAME),
                attrib.get(A_SUBJECT_STATUS),
                attrib.get(A_TRANSACTION_TYPE, DEFAULT_TRANSACTION_TYPE),
            )
        elif tag == E_USER_REF:
            # Set the Signature or audit-record value depending on state
            self.get_parent_element().user_oid = attrib.get(A_USER_OID)

        elif tag == E_SOURCE_ID:
            self.state = STATE_SOURCE_ID

        elif tag == E_DATE_TIME_STAMP_:
            self.state = STATE_DATETIME

        elif tag == E_REASON_FOR_CHANGE:
            self.state = STATE_REASON_FOR_CHANGE

        elif tag == E_LOCATION_REF:
            # Set the Signature or audit-record value depending on state
            self.get_parent_element().location_oid = attrib.get(A_LOCATION_OID)

        elif tag == E_STUDY_EVENT_DATA:
            self.context.event = Event(
                attrib.get(A_STUDYEVENT_OID),
                attrib.get(A_STUDYEVENT_REPEAT_KEY),
                attrib.get(A_TRANSACTION_TYPE),
                attrib.get(A_INSTANCE_NAME),
                attrib.get(A_INSTANCE_OVERDUE),
                make_int(attrib.get(A_INSTANCE_ID), -1)
            )

        elif tag == E_FORM_DATA:

            self.context.form = Form(