'''
Task Coach - Your friendly task manager
Copyright (C) 2004-2011 Task Coach developers <developers@taskcoach.org>
Copyright (C) 2010 Frank Niessink <frank@niessink.com>

Task Coach is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Task Coach is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY 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/>.
'''

from taskcoachlib.i18n import _
from taskcoachlib.widgets import datectrl
from taskcoachlib.syncml.notesource import NoteSource
from taskcoachlib.syncml.tasksource import TaskSource

import wx


class FieldMixin(object):
    def __init__(self, *args, **kwargs):
        self.callback = kwargs.pop('callback', None)

        super(FieldMixin, self).__init__(*args, **kwargs)

    def OnChange(self, event): # pylint: disable-msg=W0613
        if self.callback is not None:
            self.callback(self.GetId())


class OneLineTextField(FieldMixin, wx.TextCtrl):
    def __init__(self, *args, **kwargs):
        super(OneLineTextField, self).__init__(*args, **kwargs)

        wx.EVT_TEXT(self, wx.ID_ANY, self.OnChange)


class MultipleLinesTextField(OneLineTextField):
    def __init__(self, *args, **kwargs):
        kwargs['style'] = kwargs.get('style', 0) | wx.TE_MULTILINE

        super(MultipleLinesTextField, self).__init__(*args, **kwargs)


class IntegerField(FieldMixin, wx.SpinCtrl):
    def __init__(self, *args, **kwargs):
        super(IntegerField, self).__init__(*args, **kwargs)

        wx.EVT_SPINCTRL(self, wx.ID_ANY, self.OnChange)

    def ChangeValue(self, value):
        self.SetValue(value)


class DateTimeField(FieldMixin, datectrl.DateTimeCtrl):
    def __init__(self, parent, *args, **kwargs):
        super(DateTimeField, self).__init__(parent, None, self.OnChange, *args, **kwargs)

    def ChangeValue(self, value):
        # FIXME: under  WXGTK at  least (didn't try  other platforms),
        # checking/unchecking  the  check  box  does not  trigger  the
        # change event.
        self.SetValue(value)


class BaseConflictPanel(wx.Panel):
    def __init__(self, flags, local, remote, *args, **kwargs):
        super(BaseConflictPanel, self).__init__(*args, **kwargs)

        self.flags = flags
        self.local = local
        self.remote = remote

        self.fields = dict()
        self.sizer = wx.FlexGridSizer(0, 7)

        self.sizer.Add(wx.StaticText(self, wx.ID_ANY, _('Field name')), 0, wx.ALIGN_CENTRE|wx.ALL, 3)
        self.sizer.Add(wx.StaticText(self, wx.ID_ANY, _('Local')), 0, wx.ALIGN_CENTRE|wx.ALL, 3)
        self.sizer.Add((0, 0))
        self.sizer.Add(wx.StaticText(self, wx.ID_ANY, _('Remote')), 0, wx.ALIGN_CENTRE|wx.ALL, 3)
        self.sizer.Add((0, 0))
        self.sizer.Add(wx.StaticText(self, wx.ID_ANY, _('Fusion')), 0, wx.ALIGN_CENTRE|wx.ALL, 3)
        self.sizer.Add((0, 0))

        self.sizer.AddGrowableCol(1)
        self.sizer.AddGrowableCol(3)
        self.sizer.AddGrowableCol(5)

        self.SetSizer(self.sizer)

    def AddConflictItem(self, name, type_, local, remote, canMerge=True):
        id_ = wx.NewId()

        localWidget = type_(self, id_)
        localWidget.SetValue(local)
        localWidget.Enable(False)

        remoteWidget = type_(self, id_)
        remoteWidget.SetValue(remote)
        remoteWidget.Enable(False)

        fusionWidget = type_(self, id_, callback=self.OnFusionChanged)
        fusionWidget.SetValue(local)
        if not canMerge:
            fusionWidget.Enable(False)

        btnLocal = wx.RadioButton(self, id_, u'', style=wx.RB_GROUP)
        btnRemote = wx.RadioButton(self, id_, u'')
        btnFusion = wx.RadioButton(self, id_, u'') if canMerge else None

        wx.EVT_RADIOBUTTON(btnLocal, id_, self.OnLocalSelected)
        wx.EVT_RADIOBUTTON(btnRemote, id_, self.OnRemoteSelected)

        self.sizer.Add(wx.StaticText(self, wx.ID_ANY, name), 0, wx.ALIGN_CENTRE|wx.ALL, 3)
        self.sizer.Add(localWidget, 0, wx.EXPAND|wx.ALL, 3)
        self.sizer.Add(btnLocal)
        self.sizer.Add(remoteWidget, 0, wx.EXPAND|wx.ALL, 3)
        self.sizer.Add(btnRemote)
        self.sizer.Add(fusionWidget, 0, wx.EXPAND|wx.ALL, 3)
        self.sizer.Add(btnFusion if canMerge else (0, 0))

        self.fields[id_] = (localWidget, remoteWidget, fusionWidget, btnFusion)

        return id_

    def OnLocalSelected(self, evt):
        if self.fields.has_key(evt.GetId()):
            localWidget, dummy, fusionWidget, dummy = self.fields[evt.GetId()]
            fusionWidget.ChangeValue(localWidget.GetValue())

    def OnRemoteSelected(self, evt):
        if self.fields.has_key(evt.GetId()):
            dummy, remoteWidget, fusionWidget, dummy = self.fields[evt.GetId()]
            fusionWidget.ChangeValue(remoteWidget.GetValue())

    def OnFusionChanged(self, id_):
        if self.fields.has_key(id_):
            btnFusion = self.fields[id_][3]
            btnFusion.SetValue(True)


class NoteConflictPanel(BaseConflictPanel):
    def __init__(self, *args, **kwargs):
        super(NoteConflictPanel, self).__init__(*args, **kwargs)

        if self.flags & NoteSource.CONFLICT_SUBJECT:
            self.idSubject = self.AddConflictItem(_('Subject'),
                                                  OneLineTextField,
                                                  self.local.subject(),
                                                  self.remote.subject())
        if self.flags & NoteSource.CONFLICT_DESCRIPTION:
            self.idDescription = self.AddConflictItem(_('Description'),
                                                      MultipleLinesTextField,
                                                      self.local.description(),
                                                      self.remote.description())

    def getResolved(self):
        resolved = {}

        if self.flags & NoteSource.CONFLICT_SUBJECT:
            fusionWidget = self.fields[self.idSubject][2]
            resolved['subject'] = fusionWidget.GetValue()
        if self.flags & NoteSource.CONFLICT_DESCRIPTION:
            fusionWidget = self.fields[self.idDescription][2]
            resolved['description'] = fusionWidget.GetValue()

        return resolved


class TaskConflictPanel(BaseConflictPanel):
    def __init__(self, *args, **kwargs):
        super(TaskConflictPanel, self).__init__(*args, **kwargs)

        if self.flags & TaskSource.CONFLICT_SUBJECT:
            self.idSubject = self.AddConflictItem(_('Subject'),
                                                  OneLineTextField,
                                                  self.local.subject(),
                                                  self.remote.subject())
        if self.flags & TaskSource.CONFLICT_DESCRIPTION:
            self.idDescription = self.AddConflictItem(_('Description'),
                                                      MultipleLinesTextField,
                                                      self.local.description(),
                                                      self.remote.description())
        if self.flags & TaskSource.CONFLICT_STARTDATETIME:
            self.idStartDateTime = self.AddConflictItem(_('Start date'),
                                                        DateTimeField,
                                                        self.local.startDateTime(),
                                                        self.remote.startDateTime())
        if self.flags & TaskSource.CONFLICT_DUEDATETIME:
            self.idDueDateTime = self.AddConflictItem(_('Due date'),
                                                      DateTimeField,
                                                      self.local.dueDateTime(),
                                                      self.remote.dueDateTime())
        if self.flags & TaskSource.CONFLICT_COMPLETIONDATETIME:
            self.idCompletionDateTime = self.AddConflictItem(_('Completion date'),
                                                             DateTimeField,
                                                             self.local.completionDateTime(),
                                                             self.remote.completionDateTime())
        if self.flags & TaskSource.CONFLICT_PRIORITY:
            self.idPriority = self.AddConflictItem(_('Priority'),
                                                   IntegerField,
                                                   self.local.priority(),
                                                   self.remote.priority())
        if self.flags & TaskSource.CONFLICT_CATEGORIES:
            self.idCategories = self.AddConflictItem(_('Categories'),
                                                     OneLineTextField,
                                                     ','.join(map(unicode, self.local.categories())),
                                                     ','.join(map(unicode, self.remote.categories())),
                                                     False)

    def getResolved(self):
        resolved = {}

        if self.flags & TaskSource.CONFLICT_SUBJECT:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idSubject]
            resolved['subject'] = fusionWidget.GetValue()
        if self.flags & TaskSource.CONFLICT_DESCRIPTION:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idDescription]
            resolved['description'] = fusionWidget.GetValue()
        if self.flags & TaskSource.CONFLICT_STARTDATETIME:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idStartDateTime]
            resolved['startDateTime'] = fusionWidget.GetValue()
        if self.flags & TaskSource.CONFLICT_DUEDATETIME:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idDueDateTime]
            resolved['dueDateTime'] = fusionWidget.GetValue()
        if self.flags & TaskSource.CONFLICT_PRIORITY:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idPriority]
            resolved['priority'] = fusionWidget.GetValue()
        if self.flags & TaskSource.CONFLICT_CATEGORIES:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idCategories]
            resolved['categories'] = fusionWidget.GetValue()
        if self.flags & TaskSource.CONFLICT_COMPLETIONDATETIME:
            localWidget, remoteWidget, fusionWidget, btnFusion = self.fields[self.idCompletionDateTime]
            resolved['completionDateTime'] = fusionWidget.GetValue()

        return resolved


class ConflictDialog(wx.Dialog):
    def __init__(self, type_, flags, local, remote, *args, **kwargs):
        kwargs['style'] = kwargs.get('style', wx.CAPTION) | wx.RESIZE_BORDER

        super(ConflictDialog, self).__init__(*args, **kwargs)

        self.panel = type_(flags, local, remote, self, wx.ID_ANY)

        btnOK = wx.Button(self, wx.ID_ANY, _('OK'))

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.panel, 1, wx.EXPAND|wx.ALL, 3)
        sizer.Add(btnOK, 0, wx.ALL|wx.ALIGN_CENTRE, 3)

        self.SetSizer(sizer)
        self.Fit()

        wx.EVT_BUTTON(btnOK, wx.ID_ANY, self.OnOK)

    def OnOK(self, event): # pylint: disable-msg=W0613
        self.resolved = self.panel.getResolved() # pylint: disable-msg=W0201
        self.EndModal(wx.ID_OK)
