"""SQLite parser plugin for Android text messages (SMS) database files."""

from plaso.containers import events
from plaso.parsers import sqlite
from plaso.parsers.sqlite_plugins import interface


class AndroidSMSEventData(events.EventData):
    """Android SMS event data.

    Attributes:
      address (str): phone number associated to the sender or receiver.
      creation_time (dfdatetime.DateTimeValues): creation date and time of
          the message.
      message_body (str): content of the SMS text message.
      offset (str): identifier of the row, from which the event data was
          extracted.
      query (str): SQL query that was used to obtain the event data.
      sms_read (int): message read status, either Read or Unread.
      sms_type (int): message type, either Sent or Received.
    """

    DATA_TYPE = "android:messaging:sms"

    def __init__(self):
        """Initializes event data."""
        super().__init__(data_type=self.DATA_TYPE)
        self.address = None
        self.creation_time = None
        self.message_body = None
        self.offset = None
        self.query = None
        self.sms_read = None
        self.sms_type = None


class AndroidSMSPlugin(interface.SQLitePlugin):
    """SQLite parser plugin for Android text messages (SMS) database files.

    The Android text messages (SMS) database file is typically stored in: mmssms.dbs
    """

    NAME = "android_sms"
    DATA_FORMAT = "Android text messages (SMS) SQLite database (mmssms.dbs) file"

    REQUIRED_STRUCTURE = {
        "sms": frozenset(["_id", "address", "date", "read", "type", "body"])
    }

    QUERIES = [
        ("SELECT _id AS id, address, date, read, type, body FROM sms", "ParseSmsRow")
    ]

    SCHEMAS = [
        {
            "addr": (
                "CREATE TABLE addr (_id INTEGER PRIMARY KEY, msg_id INTEGER, "
                "contact_id INTEGER, address TEXT, type INTEGER, charset INTEGER)"
            ),
            "android_metadata": ("CREATE TABLE android_metadata (locale TEXT)"),
            "attachments": (
                "CREATE TABLE attachments (sms_id INTEGER, content_url TEXT, offset "
                "INTEGER)"
            ),
            "canonical_addresses": (
                "CREATE TABLE canonical_addresses (_id INTEGER PRIMARY KEY "
                "AUTOINCREMENT, address TEXT)"
            ),
            "drm": ("CREATE TABLE drm (_id INTEGER PRIMARY KEY, _data TEXT)"),
            "part": (
                "CREATE TABLE part (_id INTEGER PRIMARY KEY AUTOINCREMENT, mid "
                "INTEGER, seq INTEGER DEFAULT 0, ct TEXT, name TEXT, chset INTEGER, "
                "cd TEXT, fn TEXT, cid TEXT, cl TEXT, ctt_s INTEGER, ctt_t TEXT, "
                "_data TEXT, text TEXT)"
            ),
            "pd": (
                "CREATE TABLE pdu (_id INTEGER PRIMARY KEY AUTOINCREMENT, thread_id "
                "INTEGER, date INTEGER, date_sent INTEGER DEFAULT 0, msg_box "
                "INTEGER, read INTEGER DEFAULT 0, m_id TEXT, sub TEXT, sub_cs "
                "INTEGER, ct_t TEXT, ct_l TEXT, exp INTEGER, m_cls TEXT, m_type "
                "INTEGER, v INTEGER, m_size INTEGER, pri INTEGER, rr INTEGER, rpt_a "
                "INTEGER, resp_st INTEGER, st INTEGER, tr_id TEXT, retr_st INTEGER, "
                "retr_txt TEXT, retr_txt_cs INTEGER, read_status INTEGER, ct_cls "
                "INTEGER, resp_txt TEXT, d_tm INTEGER, d_rpt INTEGER, locked "
                "INTEGER DEFAULT 0, seen INTEGER DEFAULT 0, text_only INTEGER "
                "DEFAULT 0)"
            ),
            "pending_msgs": (
                "CREATE TABLE pending_msgs (_id INTEGER PRIMARY KEY, proto_type "
                "INTEGER, msg_id INTEGER, msg_type INTEGER, err_type INTEGER, "
                "err_code INTEGER, retry_index INTEGER NOT NULL DEFAULT 0, due_time "
                "INTEGER, last_try INTEGER)"
            ),
            "rate": ("CREATE TABLE rate (sent_time INTEGER)"),
            "raw": (
                "CREATE TABLE raw (_id INTEGER PRIMARY KEY, date INTEGER, "
                "reference_number INTEGER, count INTEGER, sequence INTEGER, "
                "destination_port INTEGER, address TEXT, pdu TEXT)"
            ),
            "sms": (
                "CREATE TABLE sms (_id INTEGER PRIMARY KEY, thread_id INTEGER, "
                "address TEXT, person INTEGER, date INTEGER, date_sent INTEGER "
                "DEFAULT 0, protocol INTEGER, read INTEGER DEFAULT 0, status "
                "INTEGER DEFAULT -1, type INTEGER, reply_path_present INTEGER, "
                "subject TEXT, body TEXT, service_center TEXT, locked INTEGER "
                "DEFAULT 0, error_code INTEGER DEFAULT 0, seen INTEGER DEFAULT 0)"
            ),
            "sr_pending": (
                "CREATE TABLE sr_pending (reference_number INTEGER, action TEXT, "
                "data TEXT)"
            ),
            "threads": (
                "CREATE TABLE threads (_id INTEGER PRIMARY KEY AUTOINCREMENT, date "
                "INTEGER DEFAULT 0, message_count INTEGER DEFAULT 0, recipient_ids "
                "TEXT, snippet TEXT, snippet_cs INTEGER DEFAULT 0, read INTEGER "
                "DEFAULT 1, type INTEGER DEFAULT 0, error INTEGER DEFAULT 0, "
                "has_attachment INTEGER DEFAULT 0)"
            ),
            "words": (
                "CREATE VIRTUAL TABLE words USING FTS3 (_id INTEGER PRIMARY KEY, "
                "index_text TEXT, source_id INTEGER, table_to_use INTEGER)"
            ),
            "words_content": (
                "CREATE TABLE 'words_content'(docid INTEGER PRIMARY KEY, "
                "'c0_id', 'c1index_text', 'c2source_id', 'c3table_to_use')"
            ),
            "words_segdir": (
                "CREATE TABLE 'words_segdir'(level INTEGER, idx INTEGER, "
                "start_block INTEGER, leaves_end_block INTEGER, end_block INTEGER, "
                "root BLOB, PRIMARY KEY(level, idx))"
            ),
            "words_segments": (
                "CREATE TABLE 'words_segments'(blockid INTEGER PRIMARY KEY, block "
                "BLOB)"
            ),
        }
    ]

    def ParseSmsRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses an SMS row.

        Args:
          parser_mediator (ParserMediator): mediates interactions between parsers
              and other components, such as storage and dfVFS.
          query (str): query that created the row.
          row (sqlite3.Row): row.
        """
        query_hash = hash(query)

        event_data = AndroidSMSEventData()
        event_data.address = self._GetRowValue(query_hash, row, "address")
        event_data.creation_time = self._GetJavaTimeRowValue(query_hash, row, "date")
        event_data.message_body = self._GetRowValue(query_hash, row, "body")
        event_data.offset = self._GetRowValue(query_hash, row, "id")
        event_data.query = query
        event_data.sms_read = self._GetRowValue(query_hash, row, "read")
        event_data.sms_type = self._GetRowValue(query_hash, row, "type")

        parser_mediator.ProduceEventData(event_data)


sqlite.SQLiteParser.RegisterPlugin(AndroidSMSPlugin)
