import pytest

from pandas.util import testing as tm

from pandas.io.formats.css import CSSResolver, CSSWarning


def assert_resolves(css, props, inherited=None):
    resolve = CSSResolver()
    actual = resolve(css, inherited=inherited)
    assert props == actual


def assert_same_resolution(css1, css2, inherited=None):
    resolve = CSSResolver()
    resolved1 = resolve(css1, inherited=inherited)
    resolved2 = resolve(css2, inherited=inherited)
    assert resolved1 == resolved2


@pytest.mark.parametrize('name,norm,abnorm', [
    ('whitespace', 'hello: world; foo: bar',
     ' \t hello \t :\n  world \n  ;  \n foo: \tbar\n\n'),
    ('case', 'hello: world; foo: bar', 'Hello: WORLD; foO: bar'),
    ('empty-decl', 'hello: world; foo: bar',
     '; hello: world;; foo: bar;\n; ;'),
    ('empty-list', '', ';'),
])
def test_css_parse_normalisation(name, norm, abnorm):
    assert_same_resolution(norm, abnorm)


@pytest.mark.parametrize(
    'invalid_css,remainder', [
        # No colon
        ('hello-world', ''),
        ('border-style: solid; hello-world', 'border-style: solid'),
        ('border-style: solid; hello-world; font-weight: bold',
         'border-style: solid; font-weight: bold'),
        # Unclosed string fail
        # Invalid size
        ('font-size: blah', 'font-size: 1em'),
        ('font-size: 1a2b', 'font-size: 1em'),
        ('font-size: 1e5pt', 'font-size: 1em'),
        ('font-size: 1+6pt', 'font-size: 1em'),
        ('font-size: 1unknownunit', 'font-size: 1em'),
        ('font-size: 10', 'font-size: 1em'),
        ('font-size: 10 pt', 'font-size: 1em'),
    ])
def test_css_parse_invalid(invalid_css, remainder):
    with tm.assert_produces_warning(CSSWarning):
        assert_same_resolution(invalid_css, remainder)

    # TODO: we should be checking that in other cases no warnings are raised


@pytest.mark.parametrize(
    'shorthand,expansions',
    [('margin', ['margin-top', 'margin-right',
                 'margin-bottom', 'margin-left']),
     ('padding', ['padding-top', 'padding-right',
                  'padding-bottom', 'padding-left']),
     ('border-width', ['border-top-width', 'border-right-width',
                       'border-bottom-width', 'border-left-width']),
     ('border-color', ['border-top-color', 'border-right-color',
                       'border-bottom-color', 'border-left-color']),
     ('border-style', ['border-top-style', 'border-right-style',
                       'border-bottom-style', 'border-left-style']),
     ])
def test_css_side_shorthands(shorthand, expansions):
    top, right, bottom, left = expansions

    assert_resolves('{shorthand}: 1pt'.format(shorthand=shorthand),
                    {top: '1pt', right: '1pt',
                     bottom: '1pt', left: '1pt'})

    assert_resolves('{shorthand}: 1pt 4pt'.format(shorthand=shorthand),
                    {top: '1pt', right: '4pt',
                     bottom: '1pt', left: '4pt'})

    assert_resolves('{shorthand}: 1pt 4pt 2pt'.format(shorthand=shorthand),
                    {top: '1pt', right: '4pt',
                     bottom: '2pt', left: '4pt'})

    assert_resolves('{shorthand}: 1pt 4pt 2pt 0pt'.format(shorthand=shorthand),
                    {top: '1pt', right: '4pt',
                     bottom: '2pt', left: '0pt'})

    with tm.assert_produces_warning(CSSWarning):
        assert_resolves(
            '{shorthand}: 1pt 1pt 1pt 1pt 1pt'.format(shorthand=shorthand), {})


@pytest.mark.parametrize('style,inherited,equiv', [
    ('margin: 1px; margin: 2px', '',
     'margin: 2px'),
    ('margin: 1px', 'margin: 2px',
     'margin: 1px'),
    ('margin: 1px; margin: inherit', 'margin: 2px',
     'margin: 2px'),
    ('margin: 1px; margin-top: 2px', '',
     'margin-left: 1px; margin-right: 1px; ' +
     'margin-bottom: 1px; margin-top: 2px'),
    ('margin-top: 2px', 'margin: 1px',
     'margin: 1px; margin-top: 2px'),
    ('margin: 1px', 'margin-top: 2px',
     'margin: 1px'),
    ('margin: 1px; margin-top: inherit', 'margin: 2px',
     'margin: 1px; margin-top: 2px'),
])
def test_css_precedence(style, inherited, equiv):
    resolve = CSSResolver()
    inherited_props = resolve(inherited)
    style_props = resolve(style, inherited=inherited_props)
    equiv_props = resolve(equiv)
    assert style_props == equiv_props


@pytest.mark.parametrize('style,equiv', [
    ('margin: 1px; margin-top: inherit',
     'margin-bottom: 1px; margin-right: 1px; margin-left: 1px'),
    ('margin-top: inherit', ''),
    ('margin-top: initial', ''),
])
def test_css_none_absent(style, equiv):
    assert_same_resolution(style, equiv)


@pytest.mark.parametrize('size,resolved', [
    ('xx-small', '6pt'),
    ('x-small', '{pt:f}pt'.format(pt=7.5)),
    ('small', '{pt:f}pt'.format(pt=9.6)),
    ('medium', '12pt'),
    ('large', '{pt:f}pt'.format(pt=13.5)),
    ('x-large', '18pt'),
    ('xx-large', '24pt'),

    ('8px', '6pt'),
    ('1.25pc', '15pt'),
    ('.25in', '18pt'),
    ('02.54cm', '72pt'),
    ('25.4mm', '72pt'),
    ('101.6q', '72pt'),
    ('101.6q', '72pt'),
])
@pytest.mark.parametrize('relative_to',  # invariant to inherited size
                         [None, '16pt'])
def test_css_absolute_font_size(size, relative_to, resolved):
    if relative_to is None:
        inherited = None
    else:
        inherited = {'font-size': relative_to}
    assert_resolves('font-size: {size}'.format(size=size),
                    {'font-size': resolved}, inherited=inherited)


@pytest.mark.parametrize('size,relative_to,resolved', [
    ('1em', None, '12pt'),
    ('1.0em', None, '12pt'),
    ('1.25em', None, '15pt'),
    ('1em', '16pt', '16pt'),
    ('1.0em', '16pt', '16pt'),
    ('1.25em', '16pt', '20pt'),
    ('1rem', '16pt', '12pt'),
    ('1.0rem', '16pt', '12pt'),
    ('1.25rem', '16pt', '15pt'),
    ('100%', None, '12pt'),
    ('125%', None, '15pt'),
    ('100%', '16pt', '16pt'),
    ('125%', '16pt', '20pt'),
    ('2ex', None, '12pt'),
    ('2.0ex', None, '12pt'),
    ('2.50ex', None, '15pt'),
    ('inherit', '16pt', '16pt'),

    ('smaller', None, '10pt'),
    ('smaller', '18pt', '15pt'),
    ('larger', None, '{pt:f}pt'.format(pt=14.4)),
    ('larger', '15pt', '18pt'),
])
def test_css_relative_font_size(size, relative_to, resolved):
    if relative_to is None:
        inherited = None
    else:
        inherited = {'font-size': relative_to}
    assert_resolves('font-size: {size}'.format(size=size),
                    {'font-size': resolved}, inherited=inherited)
