# Copyright DataStax, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import unittest

from cassandra.util import OrderedMap, OrderedMapSerializedKey
from cassandra.cqltypes import EMPTY, UTF8Type, lookup_casstype
import six

class OrderedMapTest(unittest.TestCase):
    def test_init(self):
        a = OrderedMap(zip(['one', 'three', 'two'], [1, 3, 2]))
        b = OrderedMap([('one', 1), ('three', 3), ('two', 2)])
        c = OrderedMap(a)
        builtin = {'one': 1, 'two': 2, 'three': 3}
        self.assertEqual(a, b)
        self.assertEqual(a, c)
        self.assertEqual(a, builtin)
        self.assertEqual(OrderedMap([(1, 1), (1, 2)]), {1: 2})

        d = OrderedMap({'': 3}, key1='v1', key2='v2')
        self.assertEqual(d[''], 3)
        self.assertEqual(d['key1'], 'v1')
        self.assertEqual(d['key2'], 'v2')

        with self.assertRaises(TypeError):
            OrderedMap('too', 'many', 'args')

    def test_contains(self):
        keys = ['first', 'middle', 'last']

        om = OrderedMap()

        om = OrderedMap(zip(keys, range(len(keys))))

        for k in keys:
            self.assertTrue(k in om)
            self.assertFalse(k not in om)

        self.assertTrue('notthere' not in om)
        self.assertFalse('notthere' in om)

    def test_keys(self):
        keys = ['first', 'middle', 'last']
        om = OrderedMap(zip(keys, range(len(keys))))

        self.assertListEqual(list(om.keys()), keys)

    def test_values(self):
        keys = ['first', 'middle', 'last']
        values = list(range(len(keys)))
        om = OrderedMap(zip(keys, values))

        self.assertListEqual(list(om.values()), values)

    def test_items(self):
        keys = ['first', 'middle', 'last']
        items = list(zip(keys, range(len(keys))))
        om = OrderedMap(items)

        self.assertListEqual(list(om.items()), items)

    def test_get(self):
        keys = ['first', 'middle', 'last']
        om = OrderedMap(zip(keys, range(len(keys))))

        for v, k in enumerate(keys):
            self.assertEqual(om.get(k), v)
        
        self.assertEqual(om.get('notthere', 'default'), 'default')
        self.assertIsNone(om.get('notthere'))

    def test_equal(self):
        d1 = {'one': 1}
        d12 = {'one': 1, 'two': 2}
        om1 = OrderedMap({'one': 1})
        om12 = OrderedMap([('one', 1), ('two', 2)])
        om21 = OrderedMap([('two', 2), ('one', 1)])

        self.assertEqual(om1, d1)
        self.assertEqual(om12, d12)
        self.assertEqual(om21, d12)
        self.assertNotEqual(om1, om12)
        self.assertNotEqual(om12, om1)
        self.assertNotEqual(om12, om21)
        self.assertNotEqual(om1, d12)
        self.assertNotEqual(om12, d1)
        self.assertNotEqual(om1, EMPTY)

        self.assertFalse(OrderedMap([('three', 3), ('four', 4)]) == d12)

    def test_getitem(self):
        keys = ['first', 'middle', 'last']
        om = OrderedMap(zip(keys, range(len(keys))))

        for v, k in enumerate(keys):
            self.assertEqual(om[k], v)
        
        with self.assertRaises(KeyError):
            om['notthere']

    def test_iter(self):
        keys = ['first', 'middle', 'last']
        values = list(range(len(keys)))
        items = list(zip(keys, values))
        om = OrderedMap(items)

        itr = iter(om)
        self.assertEqual(sum([1 for _ in itr]), len(keys))
        self.assertRaises(StopIteration, six.next, itr)

        self.assertEqual(list(iter(om)), keys)
        self.assertEqual(list(six.iteritems(om)), items)
        self.assertEqual(list(six.itervalues(om)), values)

    def test_len(self):
        self.assertEqual(len(OrderedMap()), 0)
        self.assertEqual(len(OrderedMap([(1, 1)])), 1)

    def test_mutable_keys(self):
        d = {'1': 1}
        s = set([1, 2, 3])
        om = OrderedMap([(d, 'dict'), (s, 'set')])

    def test_strings(self):
        # changes in 3.x
        d = {'map': 'inner'}
        s = set([1, 2, 3])
        self.assertEqual(repr(OrderedMap([('two', 2), ('one', 1), (d, 'value'), (s, 'another')])),
                         "OrderedMap([('two', 2), ('one', 1), (%r, 'value'), (%r, 'another')])" % (d, s))

        self.assertEqual(str(OrderedMap([('two', 2), ('one', 1), (d, 'value'), (s, 'another')])),
                         "{'two': 2, 'one': 1, %r: 'value', %r: 'another'}" % (d, s))

    def test_popitem(self):
        item = (1, 2)
        om = OrderedMap((item,))
        self.assertEqual(om.popitem(), item)
        self.assertRaises(KeyError, om.popitem)

    def test_delitem(self):
        om = OrderedMap({1: 1, 2: 2})

        self.assertRaises(KeyError, om.__delitem__, 3)

        del om[1]
        self.assertEqual(om, {2: 2})
        del om[2]
        self.assertFalse(om)

        self.assertRaises(KeyError, om.__delitem__, 1)


class OrderedMapSerializedKeyTest(unittest.TestCase):
    def test_init(self):
        om = OrderedMapSerializedKey(UTF8Type, 2)
        self.assertEqual(om, {})

    def test_normalized_lookup(self):
        key_type = lookup_casstype('MapType(UTF8Type, Int32Type)')
        protocol_version = 3
        om = OrderedMapSerializedKey(key_type, protocol_version)
        key_ascii = {'one': 1}
        key_unicode = {u'two': 2}
        om._insert_unchecked(key_ascii, key_type.serialize(key_ascii, protocol_version), object())
        om._insert_unchecked(key_unicode, key_type.serialize(key_unicode, protocol_version), object())

        # type lookup is normalized by key_type
        # PYTHON-231
        self.assertIs(om[{'one': 1}], om[{u'one': 1}])
        self.assertIs(om[{'two': 2}], om[{u'two': 2}])
        self.assertIsNot(om[{'one': 1}], om[{'two': 2}])
