# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# Copyright (C) 2012 David Planella <david.planella@ubuntu.com>
# This program is free software: you can redistribute it and/or modify it 
# under the terms of the GNU General Public License version 3, as published 
# by the Free Software Foundation.
# 
# This program is distributed in the hope that it will be useful, but 
# WITHOUT ANY WARRANTY; without even the implied warranties of 
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
# PURPOSE.  See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along 
# with this program.  If not, see <http://www.gnu.org/licenses/>.
### END LICENSE

# VCARD reference http://tools.ietf.org/html/rfc6350

# TODO:
# PHOTO, BDAY, LABEL, MAILER, TZ, GEO, LOGO, AGENT,
# REV, SOUND, UID, VERSION, KEY
# X-ABUID, X-ANNIVERSARY, X-ASSISTANT, X-MANAGER
# X-SPOUSE, X-GENDER, X-AIM, X-ICQ, X-JABBER, X-MSN,
# X-YAHOO, X-TWITTER, X-SKYPE, X-SKYPE-USERNAME,
# X-GADUGADU, X-GROUPWISE, X-MS-IMADDRESS, X-MS-CARDPICTURE
# X-PHONETIC-FIRST-NAME, X-PHONETIC-LAST-NAME
# X-MOZILLA-HTML, X-MOZILLA-PROPERTY, X-EVOLUTION-ANNIVERSARY
# X-EVOLUTION-ASSISTANT ,X-EVOLUTION-BLOG-URL, X-EVOLUTION-FILE-AS
# X-EVOLUTION-MANAGER, X-EVOLUTION-SPOUSE, X-EVOLUTION-VIDEO-URL
# X-EVOLUTION-CALLBACK, X-EVOLUTION-RADIO, X-EVOLUTION-TELEX
# X-EVOLUTION-TTYTDD, X-KADDRESSBOOK-BlogFeed, X-KADDRESSBOOK-X-Anniversary
# X-KADDRESSBOOK-X-AssistantsName, X-KADDRESSBOOK-X-IMAddress,
# X-KADDRESSBOOK-X-ManagersName, X-KADDRESSBOOK-X-Office
# X-KADDRESSBOOK-X-Profession, X-KADDRESSBOOK-X-SpouseName

from .GtkHelpers import clear_text_entry, show_clear_icon
from gi.repository import Gtk, GObject
from qreator_lib.helpers import get_data_file
from qreator_lib.i18n import _
import vobject


ENTRY_TYPES = [(_("E-mail"), "email"),
               (_("Phone"), "tel"),
               (_("Address"), "adr"),
               (_("Website"), "url"),
               (_("Nickname"), "nickname"),
               (_("Title"), "title"),
               (_("Role"), "role"),
               (_("Note"), "note"),
               #(_("Organization"), "org"), # python-vobject/+bug/1010104
               ]

# TRANSLATORS:
# text: Indicates that the telephone number supports text messages (SMS).
# voice: Indicates a voice telephone number.
# fax: Indicates a facsimile telephone number.
# cell: Indicates a cellular or mobile telephone number.
# video: Indicates a video conferencing telephone number.
# pager: Indicates a paging device telephone number.
# textphone: Indicates a telecommunication device for people with
# hearing or speech difficulties.
PHONE_TYPES = [(_("Cell"), "cell"),
               (_("Voice"), "voice"),
               (_("Fax"), "fax"),
               (_("Video"), "video"),
               (_("Text"), "text"),
               (_("Pager"), "pager"),
               (_("Textphone"), "textphone"),
               ]

USAGE_TYPES = [(_("Home"), "home"),
               (_("Work"), "work")]


def on_icon(widget=None, icon=None, button=None):
    clear_text_entry(widget, icon)


class VCardEntry(object):
    """The class gets two variables:
    instances and row

    instances acts as a registry of elements in the vcard object
    and row will keep track of the latest position to add elements
    to the grid
    grid is a variable that is populated by the individual
    VCardEntry objects.
    """
    instances = []

    def __init__(self, entry_id, get_widget, widget_name):
        self.entry_id = entry_id
        self.entry_field = ENTRY_TYPES[entry_id][1]
        self.entry_text = ENTRY_TYPES[entry_id][0]
        self.grid = get_widget(widget_name)
        VCardEntry.instances.append(self)

    def add_sep(self, on_changed):
        """Attaches a separator and a removal button to the grid.
        The grid assumes that there are 3 columns:
        label, main stuff, removalbutton
        Returns the removal button and the new number of rows
        """
        sep = Gtk.Separator()
        sep.set_margin_top(3)
        sep.set_margin_bottom(3)
        sep.set_margin_right(6)
        sep.show()
        self.grid.attach(sep, 0, VCardEntry.row, 3, 1)

        image = Gtk.Image()
        image.set_from_icon_name(
                'edit-delete-symbolic', Gtk.IconSize.BUTTON)
        image.show()
        remove_button = Gtk.Button()
        remove_button.add(image)
        remove_button.set_margin_right(6)
        self.grid.attach(
            remove_button, 2, VCardEntry.row + 1, 1, 1)
        remove_button.set_tooltip_text(_('Remove this field'))
        remove_button.show()
        remove_button.connect("clicked", self.remove_me)
        remove_button.connect("clicked", on_changed)

        label = Gtk.Label(self.entry_text + ":")
        label.set_alignment(0, 0.5)
        #label.set_margin_top(3)
        label.set_margin_right(6)
        label.set_margin_left(3)
        label.show()
        self.grid.attach(
            label, 0, VCardEntry.row + 1, 1, 1)

        self.to_remove = [sep, label, remove_button]
        VCardEntry.row += 1

    def remove_me(self, widget):
        for i in self.to_remove:
            self.grid.remove(i)
        VCardEntry.instances.remove(self)

    def create_widget(self, on_changed):
        self.add_sep(on_changed)
        self.entry = Gtk.Entry()
        self.entry.set_hexpand(True)
        self.entry.set_margin_right(6)
        self.entry.set_margin_left(6)
        self.entry.connect("changed", on_changed)
        self.entry.connect("icon-press", on_icon)
        self.entry.show()
        self.grid.attach(
            self.entry, 1, VCardEntry.row, 1, 1)
        VCardEntry.row += 1
        self.to_remove.append(self.entry)

    def add_entries(self, card):
        text = self.entry.get_text()
        if text:
            card.add(self.entry_field).value = text
        return card


class GenericWithUsage(VCardEntry):
    """Adds a generic field with a label, a usage type,
    and  a entry field to the grid.
    """
    def create_widget(self, on_changed):
        self.add_sep(on_changed)
        self.box = Gtk.Box(False)
        self.box.set_orientation(Gtk.Orientation.HORIZONTAL)

        self.entry = Gtk.Entry()
        self.entry.set_hexpand(True)
        self.entry.set_margin_right(6)
        self.entry.set_margin_left(6)
        self.entry.connect("changed", on_changed)
        self.entry.connect("icon-press", on_icon)
        self.box.pack_end(self.entry, True, True, 0)

        self.usagecombo = Gtk.ComboBoxText()
        for t in USAGE_TYPES:
            self.usagecombo.append_text(t[0])
        self.usagecombo.set_active(0)
        self.usagecombo.connect("changed", on_changed)
        self.box.pack_end(self.usagecombo, False, False, 0)

        self.box.show_all()
        self.grid.attach(
            self.box, 1, VCardEntry.row, 1, 1)
        VCardEntry.row += 1
        self.to_remove.append(self.box)

    def add_entries(self, card):
        text = self.entry.get_text()
        if text:
            card.add(self.entry_field).value = text
            getattr(card,
                    self.entry_field).type_param = USAGE_TYPES[
                self.usagecombo.get_active()][1]
        return card


class Phone(VCardEntry):
    """Adds a phone field with a label, a usage type,
    a phone type and  a entry field to the grid.
    """
    def create_widget(self, on_changed):
        self.add_sep(on_changed)
        self.box = Gtk.Box(False)
        self.box.set_orientation(Gtk.Orientation.HORIZONTAL)

        self.entry = Gtk.Entry()
        self.entry.set_hexpand(True)
        self.entry.set_margin_right(6)
        self.entry.set_margin_left(6)
        self.entry.connect("changed", on_changed)
        self.entry.connect("icon-press", on_icon)
        self.box.pack_end(self.entry, True, True, 0)

        self.usagecombo = Gtk.ComboBoxText()
        for t in USAGE_TYPES:
            self.usagecombo.append_text(t[0])
        self.usagecombo.set_active(0)
        self.usagecombo.connect("changed", on_changed)
        self.box.pack_end(self.usagecombo, False, False, 0)

        self.phonecombo = Gtk.ComboBoxText()
        for t in PHONE_TYPES:
            self.phonecombo.append_text(t[0])
        self.phonecombo.set_active(0)
        self.phonecombo.connect("changed", on_changed)
        self.box.pack_end(self.phonecombo, False, False, 0)

        self.box.show_all()
        self.grid.attach(
            self.box, 1, VCardEntry.row, 1, 1)
        VCardEntry.row += 1
        self.to_remove.append(self.box)

    def add_entries(self, card):
        text = self.entry.get_text()
        if text:
            card.add(self.entry_field).value = text
            tp = [USAGE_TYPES[self.usagecombo.get_active()][1],
                  PHONE_TYPES[self.phonecombo.get_active()][1]]
            getattr(card,
                    self.entry_field).type_param = tp
        return card


class Address(VCardEntry):
    def create_widget(self, on_changed):
        self.add_sep(on_changed)

        self.street = Gtk.Entry()
        self.street.set_margin_right(6)
        self.street.set_margin_left(6)
        self.street.set_margin_top(3)
        self.street.set_margin_bottom(3)
        self.postbox = Gtk.Entry()
        self.postbox.set_margin_right(6)
        self.postbox.set_margin_left(6)
        self.postbox.set_margin_top(3)
        self.postbox.set_margin_bottom(3)
        self.city = Gtk.Entry()
        self.city.set_margin_right(6)
        self.city.set_margin_left(6)
        self.city.set_margin_top(3)
        self.city.set_margin_bottom(3)
        self.region = Gtk.Entry()
        self.region.set_margin_right(6)
        self.region.set_margin_left(6)
        self.region.set_margin_top(3)
        self.region.set_margin_bottom(3)
        self.code = Gtk.Entry()
        self.code.set_margin_right(6)
        self.code.set_margin_left(6)
        self.code.set_margin_top(3)
        self.code.set_margin_bottom(3)
        self.country = Gtk.Entry()
        self.country.set_margin_right(6)
        self.country.set_margin_left(6)
        self.country.set_margin_top(3)
        self.country.set_margin_bottom(3)

        grid = Gtk.Grid()
        grid.set_hexpand(True)
        for n, item  in enumerate([(self.street, _("Street")),
                                   (self.city, _("City")),
                                   (self.region, _("Region")),
                                   (self.code, _("Zip code")),
                                   (self.country, _("Country")),
                                   (self.postbox, _("Postbox"))]):
            e, t = item
            #e.set_placeholder_text('[{}]'.format(t))
            e.connect("changed", on_changed)
            e.connect("icon-press", on_icon)
            e.set_hexpand(True)
            label = Gtk.Label(t + ": ")
            label.set_alignment(0, 0.5)
            label.set_margin_right(6)
            label.set_margin_left(6)
            label.set_margin_top(3)
            label.set_margin_bottom(3)
            grid.attach(label, 1, n, 1, 1)
            grid.attach(e, 2, n, 1, 1)
            self.grid.attach(
                grid, 1, VCardEntry.row, 1, 1)
            self.to_remove.append(grid)

        self.usagecombo = Gtk.ComboBoxText()
        for t in USAGE_TYPES:
            self.usagecombo.append_text(t[0])
        self.usagecombo.set_active(0)
        self.usagecombo.connect("changed", on_changed)
        grid.attach(self.usagecombo, 0, 0, 1, 1)
        grid.show_all()
        VCardEntry.row += 6

    def add_entries(self, card):
        street = self.street.get_text()
        city = self.city.get_text()
        region = self.region.get_text()
        code = self.code.get_text()
        country = self.country.get_text()
        postbox = self.postbox.get_text()
        if street or city or region or code or country or postbox:
            card.add("adr")
            card.adr.value = vobject.vcard.Address(
                street, city,
                region, code,
                country, postbox)
            getattr(card,
                    self.entry_field).type_param = USAGE_TYPES[
                        self.usagecombo.get_active()][1]

        return card


class QRCodeVCardGtk(object):
    def __getitem__(self, itemname):
        return self.builder.get_object(itemname)

    def __init__(self, qr_code_update_func):
        self.qr_code_update_func = qr_code_update_func
        self.builder = Gtk.Builder()

        self.builder.add_from_file(
            get_data_file('ui', '%s.ui' % ('QrCodeVCard',)))
        self.builder.connect_signals(self)
        # TRANSLATORS: This refers to the most likely family name {0} -
        # given name {1} order in the language
        self.fullname_template = _("{1} {0}")
        self['entry1'].set_placeholder_text(
            _('[Required for a valid business card]'))
        self['entry2'].set_placeholder_text(
            _('[Required for a valid business card]'))
        for t in ENTRY_TYPES:
            self["comboboxtext1"].append_text(t[0])
        self["comboboxtext1"].set_active(0)
        self["entry1"].connect("icon-press", on_icon)
        self["entry2"].connect("icon-press", on_icon)
        VCardEntry.row = 3
        self.grid = self['qr_code_vcard']

    def create_vcard(self):
        self.j = vobject.vCard()
        self.j.add("n")
        f = self['entry2'].get_text()
        g = self['entry1'].get_text()
        self.j.n.value = vobject.vcard.Name(
            family=f, given=g)
        self.j.add("fn")
        self.j.fn.value = self.fullname_template.format(f, g)

        for e in VCardEntry.instances:
            self.j = e.add_entries(self.j)
        #print self.j.serialize()
        if f:
            self['image2'].set_from_icon_name(
                'object-select-symbolic', Gtk.IconSize.BUTTON)
        else:
            self['image2'].set_from_icon_name(
                'action-unavailable-symbolic', Gtk.IconSize.BUTTON)
        if g:
            self['image1'].set_from_icon_name(
                'object-select-symbolic', Gtk.IconSize.BUTTON)
        else:
            self['image1'].set_from_icon_name(
                'action-unavailable-symbolic', Gtk.IconSize.BUTTON)

    def on_activated(self):
        pass

    def on_prepared(self):
        pass

    def on_fullname_switch(self, widget, data=None):
        if self.fullname_template == "{0} {1}":
            self.fullname_template = "{1} {0}"
        else:
            self.fullname_template = "{0} {1}"
        self.on_changed(None)

    def on_changed(self, widget):
        if type(widget) == Gtk.Entry:
            show_clear_icon(widget)
        elif type(widget) == Gtk.ComboBoxText:
            try:
                show_clear_icon(widget.get_child())
            except:
                pass
        g = self['entry1'].get_text()
        f = self['entry2'].get_text()
        self['label4'].set_text(self.fullname_template.format(f, g))
        self.create_vcard()
        self.qr_code_update_func(self.j.serialize())
        return True

    def on_add_entry(self, widget):
        e_id = self['comboboxtext1'].get_active()
        entry_type = ENTRY_TYPES[e_id][1]
        #text = ENTRY_TYPES[e_id][0]
        if entry_type in ["email", "url"]:
            GenericWithUsage(e_id, self.builder.get_object,
                             "grid1").create_widget(self.on_changed)
        elif entry_type == "tel":
            Phone(e_id, self.builder.get_object,
                  "grid1").create_widget(self.on_changed)
        elif entry_type == "adr":
            Address(e_id, self.builder.get_object,
                    "grid1").create_widget(self.on_changed)
        elif entry_type in ["title", "org", "role", "nickname", "note"]:
            VCardEntry(e_id, self.builder.get_object,
                       "grid1").create_widget(self.on_changed)
        def update_scroll():
            self["scrolledwindow1"].get_vadjustment().set_value(
                self["scrolledwindow1"].get_vadjustment().get_upper())

        GObject.idle_add(update_scroll)
