#!/usr/bin/env python
# Copyright (c) 2014,2016 - Adjacent Link LLC, Bridgewater, New Jersey
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#  
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
#  * Neither the name of Adjacent Link LLC nor the names of its
#    contributors may be used to endorse or promote products derived
#    from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# See toplevel COPYING for more information.
#

import sqlite3
import sys
import struct
import re
import os

from optparse import OptionParser

usage = """%prog [OPTION]... LOGFILE PROBENAME [PROBENAME]...

  LOGFILE      File containing probe data in probe stream format.

  PROBENAME    OpenTestPoint probe name. 

  SQLite probes table schema:

   CREATE TABLE probes (time INT,uuid TEXT,probe TEXT,tag TEXT,
                        pindex INT,offset INT, size INT,
                        PRIMARY KEY (time,uuid,probe,tag,pindex));
"""

description="""Filer one or more probes from a probe data log file in probe stream
format using a probe data SQLite DB. Unless otherwise specified, the
probe data SQLite DB is named LOGFILE.db. All probe data is output in
probe stream format."""

epilog="""Probe stream format uses length prefix framing, where the length of
the message is output as an unsigned 32-bit integer value (4 bytes) in
network byte order preceding the output of the serialized message. All
probe messages are serialized OpenTestPopint::ProbeReport protobuf
messages. OpenTestPoint probe name format consists of a tree like
naming convention where each element in the name tree is separated by
a '.'. The more elements in a probe name, the more specific the probe
name. For example, a probe named A.B.C.D may belong to a family of
probes consisting of A.B.C.D, A.B.C.E and A.B.C.F. Specifying a probe
named A.B.C.D will only match that single probe. Specifying A.B.C will
match A.B.C.D, A.B.C.E and A.B.C.F. Likewise, specifying just A will
match all probes that start with A."""

optionParser = OptionParser(usage=usage,
                            description=description,
                            epilog=epilog)

optionParser.add_option("--dbfile",
                        type="string",
                        dest="dbfile",
                        help="sqlite db associated with LOGFILE [Default: LOGFILE.db]")

optionParser.add_option("-o",
                        "--outfile",
                        type="string",
                        dest="outfile",
                        help="write output to specified file")

(options, args) = optionParser.parse_args()

if len(args) < 2:
  print "invalid usage"
  exit(1)

if options.dbfile:
  dbfile = options.dbfile
else:
  dbfile = args[0] + '.db'

if options.outfile:
  ofd = open(options.outfile,"w")
else:
  ofd = sys.stdout

if not os.path.isfile(dbfile):
  print >>sys.stderr, "db does not exist or is not a file:",dbfile
  exit(1)

conn = sqlite3.connect(dbfile)

def regexp(expr, item):
    reg = re.compile(expr)
    return reg.search(item) != None

conn.create_function("REGEXP", 2, regexp)

ifd = open(args[0],"r");

sql="SELECT offset,size FROM probes WHERE";

i=len(args[1:]);

while(i):
  sql += " probe REGEXP ?"

  if i > 1:
    sql += " OR"

  i -= 1

sql += " ORDER BY time ASC;"

try:
  for row in conn.execute(sql,[x.replace('.','\.') for x in args[1:]]):
    ifd.seek(row[0])
    msg=ifd.read(row[1])
    ofd.write(struct.pack("!L",len(msg)));
    ofd.write(msg)
    ofd.flush()

except KeyboardInterrupt:
  pass

finally:
  conn.close()
