#!/usr/bin/python
# License: MIT or GPL2+, your choice.

import sqlite3
import sys

def load(filename):
    connection = sqlite3.connect(filename)
    cursor = connection.cursor()
    data = []
    people = list(cursor.execute("SELECT _id, name, notes, times_contacted, last_time_contacted, starred, primary_phone, primary_organization, primary_email, photo_version, custom_ringtone, send_to_voicemail, phonetic_name FROM people"))
    for people_id, name, notes, times_contacted, last_time_contacted, starred, primary_phone_id, primary_organization_id, primary_email_id, photo_version, custom_ringtone, send_to_voicemail, phonetic_name \
            in people:
        person = {
            'name': name,
            'notes': notes,
            'times_contacted': times_contacted,
            'last_time_contacted': last_time_contacted,
            'starred': starred,
            'photo_version': photo_version,
            'custom_ringtone': custom_ringtone,
            'send_to_voicemail': send_to_voicemail,
            'phonetic_name': phonetic_name,
        }
        # primary_phone_id
        # primary_organization_id
        # primary_email_id
        phones = list(cursor.execute("SELECT type, number, label from phones where person=?", (people_id,)))
        #print phones
        person['phones'] = []
        for phone_type, phone_number, label in phones:
            if not label:
                label = {
                    0: 'Home',
                    1: 'Mobile',
                    2: 'Work',
                    3: 'Work-Fax',
                    4: 'Home-Fax',
                    5: 'Pager',
                    6: 'Other',
                }[phone_type]
            person['phones'].append({
                'number': phone_number,
                'label': label,
            })
        data.append(person)
    return data


def norm_phone_number(phone_number):
    phone_number = phone_number.replace('-', '')
    if not phone_number.startswith('+'):
        phone_number = phone_number[-10:]
    phone_number = '-'.join(part for part in (
        phone_number[:-10],
        phone_number[-10:-7],
        phone_number[-7:-4],
        phone_number[-4:],
        ) if part)
    return phone_number


def clean_data(data):
    """Cleans phone data *in-place*"""
    # Coallesce "John Doe" and "John Doe1" into one contact
    names = [c['name'] for c in data]
    assert len(names) == len(set(names))
    by_name = dict((c['name'], c) for c in data)
    bad_names = [n for n in names if n.endswith('1')]
    for bad_name in bad_names:
        name = bad_name.rstrip('1')
        bad_contact = by_name[bad_name]
        if name in by_name:
            contact = by_name[name]
            data.remove(bad_contact)
            contact['phones'].extend(bad_contact['phones'])
            if bad_contact['notes']:
                if contact['notes']:
                    contact['notes'] += '\n'
                contact['notes'] += bad_contact['notes']
        else:
            bad_contact['name'] = name

    # Clean up duplicate phone numbers and labels
    for contact in data:
        phones = contact['phones']
        new_phones = []
        new_numbers = set()
        new_labels = set()
        for phone in contact['phones']:
            phone_number = norm_phone_number(phone['number'])
            if phone_number in new_numbers:
                continue # skip duplicates
            proposed_label = phone['label']
            n=2
            while proposed_label in new_labels:
                proposed_label = "%s%s" % (phone['label'], n)
                n += 1
            new_numbers.add(phone_number)
            new_labels.add(proposed_label)
            new_phones.append({'label': proposed_label, 'number': phone_number})
        contact['phones'] = new_phones


def as_vcard(contact):
    if not contact['phones']:
        sys.stderr.write("no phone: %s\n" % contact['name'])
    name_parts = contact['name'].split()
    if len(name_parts) == 2:
        first_name = name_parts[0]
        last_name = name_parts[1]
    else:
        first_name = contact['name']
        last_name = ''
    card_lines = [
        "BEGIN:VCARD",
        "VERSION:2.1",
        "N:%s;%s;;;" % (last_name, first_name),
        "FN:%s" % contact['name'],
    ]
    for phone in contact['phones']:
        card_lines.append("TEL;X-%s:%s" % (phone['label'], phone['number']))
    if contact['notes']:
        notes = contact['notes']
        if '\n' in notes:
            sys.stderr.write("multiline note is: %r\n" % notes)
            notes = notes.replace("\n", ".  ").strip()
        card_lines.append("NOTE:%s" % notes)
    card_lines.append("END:VCARD")
    return "\n".join(card_lines)


def as_vcards(contacts):
    return "\n".join(as_vcard(c) for c in contacts if c['phones'])


def main(argv):
    filename = argv[1]
    data = load(filename)
    clean_data(data)
    print as_vcards(data)


if __name__ == '__main__':
    sys.exit(main(sys.argv))
