#!/usr/bin/env python
'''
    Metadata anonymisation toolkit - CLI edition
'''

import sys
import xml.sax
import optparse
import os

import hachoir_core

from MAT import mat
from MAT import strippers
from MAT import archive


def parse():
    ''' Get, and parse options passed to the program
    '''
    parser = optparse.OptionParser(usage='%prog [options] files\n\
The default behaviour is to clean files given in argument')
    options = optparse.OptionGroup(parser, 'Options')
    options.add_option('--add2archive', '-a', action='store_true',
        default=False, help='Add to output archive non-supported filetypes (Off by default)')
    options.add_option('--backup', '-b', action='store_true', default=False,
        help='Keep a backup copy')
    options.add_option('--low-pdf-quality', '-L', action='store_true', default=False,
        help='Produces a lighter, but lower quality PDF')
    info = optparse.OptionGroup(parser, 'Informations')
    info.add_option('--check', '-c',  action='store_true', default=False,
        help='Check if a file is free of harmful metadatas')
    info.add_option('--display', '-d', action='store_true', default=False,
        help='List all the harmful metadata of a file without removing them')
    info.add_option('--list', '-l', action='store_true', default=False,
        help='List all supported fileformat')
    info.add_option('--version', '-v', action='callback',
        callback=display_version, help='Display version and exit')
    parser.add_option_group(options)
    parser.add_option_group(info)

    values, arguments = parser.parse_args()
    if not arguments and not values.list:
        # if no argument and no files are passed,
        # print help and exit
        parser.print_help()
    return values, arguments


def display_version(*_):
    ''' Display the program's version, and exit
    '''
    print('Metadata Anonymisation Toolkit %s' % mat.__version__)
    print('Hachoir %s' % hachoir_core.__version__)
    sys.exit(0)


def list_meta(class_file, filename, add2archive):
    ''' Print all the metadata of 'filename' on stdout
    '''
    print('[+] File %s :' % filename)
    if class_file.is_clean():
        print('No harmful metadata found')
    else:
        print ('Harmful metadata found:')
        meta = class_file.get_meta()
        if meta:
            for key, value in class_file.get_meta().iteritems():
                print('\t%s: %s' % (key, value))
    return 0


def is_clean(class_file, filename, add2archive):
    ''' Tell if 'filename' is clean or not '''
    if class_file.is_clean():
        print('[+] %s is clean' % filename)
    else:
        print('[+] %s is not clean' % filename)
    return 0


def clean_meta(class_file, filename, add2archive):
    ''' Clean the file 'filename' '''
    if not class_file.is_writable:
        print('[-] %s is not writable' % filename)
        return 1
    print('[*] Cleaning %s' % filename)
    if not add2archive:
        is_archive = isinstance(class_file, archive.GenericArchiveStripper)
        is_terminal = isinstance(class_file, archive.TerminalZipStripper)
        if is_archive and not is_terminal:
            unsupported_list = class_file.list_unsupported()
            if type(unsupported_list) == list and unsupported_list:
                print('[-] Can not clean: %s.'\
                'It contains unsupported filetypes:' % filename)
                for i in unsupported_list:
                    print('- %s' % i)
                return 1
    if class_file.remove_all():
        print('[+] %s cleaned!' % filename)
    else:
        print('[-] Unable to clean %s', filename)
        return 1
    return 0


def list_supported():
    ''' Print all supported fileformat, and exit '''
    for item in mat.list_supported_formats():
        print('%s (%s)' % (item['name'], item['extension']))
        print('\tsupport : %s' % item['support'])
        print('\tmetadata : %s' % item['metadata'])
        print('\tmethod : %s' % item['method'])
        print('\tremaining : %s' % item['remaining'])
        print('\n')
    sys.exit(0)


def main():
    ''' Main function : get args and launch the appropriate function '''
    args, filenames = parse()

    #func receives the function corresponding to the options given as parameters
    if args.display:  # only print metadatas
        func = list_meta
    elif args.check:  # only check if the file is clean
        func = is_clean
    elif args.list:  # print the list of all supported format
        list_supported()
    else:  # clean the file
        func = clean_meta

    ret = 0
    while filenames:
        filename = filenames.pop()
        if os.path.isdir(filename):
            for root, sub, files in os.walk(filename):
                for file in files:
                    filenames.append(os.path.join(root, file))
            continue

        class_file = mat.create_class_file(filename, args.backup,
            add2archive=args.add2archive, low_pdf_quality=args.low_pdf_quality)
        if class_file:
            ret += func(class_file, filename, args.add2archive)
        else:
            ret = 1
            print('[-] Unable to process %s' % filename)
    sys.exit(ret)

if __name__ == '__main__':
    main()
