#!/usr/bin/env python

import argparse
import email
from os import listdir
from os.path import isfile, join, basename
import kolabformat



def check_file(filename, messageType, objectType, verbose):
    if filename.endswith(args.fileType):
        if verbose:
            print("NAME %s" % filename)

    if messageType == 'mime':
        f = open(filename, "r")
        msg = email.message_from_string(f.read())

        kolabType = msg.get('X-Kolab-Type')
        if not kolabType:
            print("Missing kolab type X-Kolab-Type")
        elif verbose:
            print("Found X-Kolab-Type ", kolabType)

        version = msg.get('X-Kolab-Mime-Version')
        if not version:
            print("Missing kolab type X-Kolab-Mime-Version")
        elif verbose:
            print("Found X-Kolab-Mime-Version ", version)

        for part in msg.walk():
            if part.get_content_type() in [
                    'application/calendar+xml',
                    'application/vcard+xml',
                    'application/vnd.kolab+xml',
                    'application/x-vnd.kolab.contact.distlist',
                    'application/x-vnd.kolab.contact']:
                xml = part.get_payload(decode=True)
                try:
                    xml = xml.decode('utf-8')
                except UnicodeDecodeError as err:
                    print("Failed to decode as utf-8", err, filename, xml)
                    print()
                    try:
                        xml = xml.decode('cp1252')
                        print("cp1252 fallback worked", err, filename, xml)
                    except UnicodeDecodeError as err:
                        print("Failed to decode as cp1252", err, filename, xml)
                        print()
                        # Final fallback, just replace the characters we fail to decode
                        xml = xml.decode('utf-8', "replace")

                if verbose:
                    print("Content type of part is ", part.get_content_type())
                    print("Filename of part is ", part.get_filename())
                    print("Found xml \n%s" % xml)

        isPath = False
    else:
        xml = filename
        isPath = True

    if objectType == 'auto':
        if kolabType is None:
            raise Exception("Failed to detect the object type")
        elif 'event' in kolabType:
            objectType = 'event'
        elif 'todo' in kolabType:
            objectType = 'todo'
        elif 'contact' in kolabType:
            objectType = 'contact'
        elif 'note' in kolabType:
            objectType = 'note'
        elif 'journal' in kolabType:
            objectType = 'journal'
        elif 'configuration' in kolabType:
            objectType = 'configuration'
        else:
            raise Exception("Invalid object type")


    if objectType == 'event':
        kolabObject = kolabformat.readEvent(xml, isPath)
        if verbose:
            print("Event uid is: %s" % kolabObject.uid())
            print("Event is valid: %s" % kolabObject.isValid())
            print("Event start_date is valid: %s" % kolabObject.start().isValid())
            print("Event end_date is valid: %s" % kolabObject.end().isValid())
            print("Event URL is: %s" % kolabObject.url())
            print("Event summary is: %s" % kolabObject.summary())
            print("Event description is: %s" % kolabObject.description())
            print("Event comment is: %s" % kolabObject.comment())
    elif objectType == 'todo':
        kolabObject = kolabformat.readTodo(xml, isPath)
    elif objectType == 'contact':
        kolabObject = kolabformat.readContact(xml, isPath)
    elif objectType == 'journal':
        kolabObject = kolabformat.readJournal(xml, isPath)
    elif objectType == 'distlist':
        kolabObject = kolabformat.readDistlist(xml, isPath)
    elif objectType == 'note':
        kolabObject = kolabformat.readNote(xml, isPath)
    elif objectType == 'configuration':
        kolabObject = kolabformat.readConfiguration(xml, isPath)
    elif objectType == 'file':
        kolabObject = kolabformat.readFile(xml, isPath)
    else:
        print("Unknown object type", objectType, filename)
        raise Exception("Unknown object type")

    if kolabformat.error():
        raise Exception(kolabformat.errorMessage())

    print("Successfully parsed file %s with kolab object %s" %
        (basename(filename), kolabObject.uid())
    )


parser = argparse.ArgumentParser(description='Check kolab xml objects.')

parser.add_argument('--messagetype', '-m',
        dest='messageType',
        choices=['xml', 'mime'],
        required=True,
        help='The type of the object to parse')
parser.add_argument('--kolabtype', '-k',
        dest='kolabType',
        choices=['event', 'todo', 'contact', 'journal', 'distlist', 'note', 'configuration', 'file', 'auto'],
        required=True,
        help='The type of the object to parse ("auto" only for mime messages)')
parser.add_argument('--verbose', '-v',
        dest='verbose',
        default=False,
        action='store_true',
        help='Verbose output')
parser.add_argument('-p', '--path',
        dest='path',
        required=True,
        help='The file to read')
parser.add_argument('-f', '--filetype',
        dest='fileType',
        default='',
        help='Pattern for file name/type matching in directory')

args = parser.parse_args()

if isfile(args.path):
    filenames = [args.path]
else:
    filenames = [join(args.path, fn) for fn in listdir(args.path)]

for filename in filenames:
    try:
        check_file(filename, args.messageType, args.kolabType, args.verbose)
    except Exception as e:
        print("There was an error while parsing ", e, filename)
