#
#
#
import os
import argparse
import logging
from subprocess import Popen, PIPE, check_call
# our libs
from libs import android
from libs.toolbox import ToolBox
from libs.fingerprint import FingerprintDB
from libs.fingerprint_index import FingerprintIndex

BASE_DIR    = "data"
FP_BASE_DIR = "fingerprints"


def main():
  parseArgs()

#
def compareFingerprint(filein, filejson):
  db = FingerprintDB()
  db.scanDBFile(filein)
  percent = db.compareDB(filejson)
  print "Percent match: {}".format(str(percent))

#
def createFingerprint(filein, verbose, app_name, app_ver, notes):
  db = FingerprintDB()
  retVal = db.scanDBFile(filein)
  if (retVal > 0):
    if verbose:
      db.debugFingerprint()
    if app_name:
      db.setAppName(app_name)
    if app_ver:
      db.setAppVer(app_ver)
    if notes:
      db.setNotes(notes)
    db.writeFingerprint()
  else:
    print db.getErrorString(retVal)

#
def indexFingerprints(fp_dir):
  logging.info("fp_dir=={}".format(fp_dir))
  db = FingerprintDB()
  fp = FingerprintIndex()
  fp.openIndex(fp_dir)

#
def compareFingerprintDir(file_in, fp_dir):
  db = FingerprintDB()
  fp = FingerprintIndex()

#
def androidPull():
  ap = android.AndroidAppPull()
  isRoot = ap.isADBRoot();
  if (not isRoot):
    print "ERROR: adb is not running as root, exec 'adb root'"
    return

  if (not mkdir(BASE_DIR)):
    logging.error("ERROR creating directory: {}".format(BASE_DIR))
    return
  if (not mkdir(FP_BASE_DIR)):
    logging.error("ERROR creating directory: {}".format(FP_BASE_DIR))
    return

  dir_names = ap.getAppsDir()
  for dir_name in dir_names:
    fq_dir = BASE_DIR + os.path.sep + dir_name
    ap.pullApp(BASE_DIR, dir_name)
    __createFingerprint(fq_dir, FP_BASE_DIR, dir_name)

#
def androidData(data_dir):
  dir_names = []
  try:
    dirs = os.listdir(data_dir)
  except:
    return

  out_dir = FP_BASE_DIR + "_" + ToolBox.getTimestampStr()
  if (not mkdir(out_dir)):
    logging.error("ERROR creating directory: {}".format(FP_BASE_DIR))
    return

  for ddir in dirs:
    in_dir = data_dir + os.path.sep + ddir
    __createFingerprint(in_dir, out_dir, ddir)

# in_dir:  fully qualified directory path to find sqlite files
def __createFingerprint(in_dir, out_dir, dir_name):
  try:
    db_dir = in_dir + os.path.sep + "databases"
    logging.info("in_dir=={}".format(db_dir))
    files = os.listdir(db_dir)
  except:
    # not finding a databases folder is normal, not all apps use sqlite
    return
  db = FingerprintDB()
  for filein in files:
    ddir = db_dir + os.path.sep + filein
    logging.info('Parsing file "{}"'.format(ddir))
    retVal = db.scanDBFile(ddir)
    if (retVal > 0):
      fname = dir_name + "__" + filein + "__dbfp" + ".json"
      fq_name = out_dir + os.path.sep + fname
      db.setAppName(dir_name)
      db.writeFingerprintFile(fq_name)

#
def __getFileName():
  '''standardize on a file name, use timestamp? '''
  pass

#
def mkdir(fdir):
  retval = False
  try:
    check_call(["mkdir", fdir])
    retval = True
  except:
    logging.error('ERROR: problem creating directory "{}"'.format(fdir))
  return retval

#
def parseArgs():
  print '***** ***** ***** *****'
  print '   DB Fingerprint'
  print '***** ***** ***** *****\n'
  parser = argparse.ArgumentParser(description="Fingerprint a sqlite database based on its schema")
  parser.add_argument('-f', '--file', required=False, help="path to file to be fingerprinted")
  parser.add_argument('-fd', '--fpdir', required=False, help="path to directory of fingerprint files")
  parser.add_argument('-fp', '--fingerprint', required=False, help="fingerprint file to use in comparison")
  parser.add_argument('-dd', '--data_dir', required=False, help="path to a directory with sqlite files")
  parser.add_argument('-idx', '--index_fingerprints', required=False, help="path to a directory with sqlite files")
  parser.add_argument('-an', '--app_name',  required=False)
  parser.add_argument('-av', '--app_version', required=False)
  parser.add_argument('-n', '--notes', required=False)
  parser.add_argument('-pull', required=False, action='store_true', help="automated pull of applications from a physical android phone")
  parser.add_argument('-v', '--verbose', action='store_true', help="will set logging level to DEBUG")
  parser.add_argument('-l', '--logging', action='store_true', help="will supercede the -v option and send all logging to a file, logging.DEBUG")
  # parser.add_argument('-t', '--title', required=False)
  args = parser.parse_args()

  if (args.logging):
    logging.basicConfig(filename='dbfp.log', level=logging.DEBUG)

  if (args.verbose):
    logging.basicConfig(level=logging.DEBUG)
  else:
    logging.basicConfig(level=logging.CRITICAL)
  
  if (args.file and args.fingerprint):
    compareFingerprint(args.file, args.fingerprint)      
  elif (args.file and args.fpdir):
    compareFingerprintDir(args.file, args.fpdir)
  elif (args.data_dir):
    androidData(args.data_dir)
  elif (args.index_fingerprints):
    indexFingerprints(args.index_fingerprints)
  elif (args.pull):
    androidPull()    
  elif (args.file):
    createFingerprint(args.file, args.verbose, args.app_name, args.app_version, args.notes)
  else:
    parser.print_help()



if __name__ == "__main__":
  main()
