# This file is part of Indico.
# Copyright (C) 2002 - 2015 European Organization for Nuclear Research (CERN).
#
# Indico 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.
#
# Indico 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 Indico; if not, see <http://www.gnu.org/licenses/>.

from __future__ import unicode_literals

import string
from collections import namedtuple

from sqlalchemy.ext.declarative import declared_attr

from indico.core.db import db


class ColorTuple(namedtuple('ColorTuple', ('text', 'background'))):
    """A tuple that contains text and background color.

    Both colors are unified to 'rrggbb' notation (in case 'rgb' is
    passed) and leading ``#`` is stripped.

    When a text/background color is specifie, the other color needs
    to be specified too.  If no color is specified, the ColorTuple
    is falsy.
    """

    def __new__(cls, text, background):
        colors = [text, background]
        for i, color in enumerate(colors):
            if color.startswith('#'):
                color = color[1:]
            if len(color) == 3:
                color = ''.join(x * 2 for x in color)
            colors[i] = color.lower()
        if any(colors):
            if not all(colors):
                raise ValueError('Both colors must be specified')
            if not all(len(x) == 6 for x in colors):
                raise ValueError('Colors must be be `rgb` or `rrggbb`')
            if not all(c in string.hexdigits for color in colors for c in color):
                raise ValueError('Colors must only use hex digits')
        return super(ColorTuple, cls).__new__(cls, *colors)

    def __nonzero__(self):
        return all(self)


class ColorMixin(object):
    """Mixin to store text+background colors in a model.

    For convenience (e.g. for WTForms integrations when selecting both
    colors at the same time from a palette or in a compound field) it
    provides a `colors` property which returns/accepts a `ColorTuple`
    holding text color and background color.
    """

    @declared_attr
    def text_color(cls):
        return db.Column(
            db.String,
            nullable=False,
            default=''
        )

    @declared_attr
    def background_color(cls):
        return db.Column(
            db.String,
            nullable=False,
            default=''
        )

    @property
    def colors(self):
        return ColorTuple(self.text_color, self.background_color)

    @colors.setter
    def colors(self, value):
        if value is None:
            value = '', ''
        self.text_color, self.background_color = value

@@ -1350,24 +1350,30 @@
 lors = %5Btext
+ or ''
 , background
@@ -1372,16 +1372,22 @@
 ckground
+ or ''
 %5D%0A      
@@ -2840,22 +2840,93 @@
         
-return
+%22%22%22The current set of colors or None if no colors are set%22%22%22%0A        colors =
  ColorTu
@@ -2968,16 +2968,46 @@
 d_color)
+%0A        return colors or None
 %0A%0A    @c

Make ColorTuple/ColorMixin more robust