from collections import OrderedDict
import numpy as np
from scipy.sparse import csr_matrix
from nose.tools import raises
from numpy.testing import assert_allclose, assert_equal

from menpo.landmark import LandmarkManager
from menpo.shape import PointCloud, LabelledPointUndirectedGraph
from menpo.testing import is_same_array


points = np.ones((10, 3))
adjacency_matrix = csr_matrix((10, 10))
mask_dict = OrderedDict([('all', np.ones(10, dtype=np.bool))])


def test_LandmarkManager_set_LabelledPointUndirectedGraph():
    lgroup = LabelledPointUndirectedGraph(points, adjacency_matrix, mask_dict)

    man = LandmarkManager()
    man['test_set'] = lgroup
    assert not is_same_array(man['test_set'].points,
                             lgroup.points)
    assert man['test_set']._labels_to_masks is not lgroup._labels_to_masks


@raises(ValueError)
def test_LandmarkManager_set_None_key():
    lgroup = LabelledPointUndirectedGraph.init_with_all_label(points, adjacency_matrix)

    man = LandmarkManager()
    man[None] = lgroup


def test_LandmarkManager_set_pointcloud():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud

    new_pcloud = man['test_set']
    assert new_pcloud is not pcloud
    assert isinstance(new_pcloud, PointCloud)


def test_LandmarkManager_copy_method():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud
    man_copy = man.copy()

    assert man_copy['test_set'] is not man['test_set']
    assert not is_same_array(man_copy['test_set'].points,
                             man['test_set'].points)


def test_LandmarkManager_set_PointCloud_not_copy_target():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud
    assert not is_same_array(man['test_set'].points,
                             pcloud.points)
    assert_allclose(man['test_set'].points, np.ones([10, 3]))


def test_LandmarkManager_iterate():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud
    man['test_set2'] = pcloud
    man['test_set3'] = pcloud

    for l in man:
        assert not is_same_array(man[l].points, pcloud.points)
    assert len(man) == 3


def test_LandmarkManager_get():
    lgroup = LabelledPointUndirectedGraph(points, adjacency_matrix, mask_dict)

    man = LandmarkManager()
    man._landmark_groups['test_set'] = lgroup

    assert(man['test_set'] is lgroup)
    assert is_same_array(man['test_set'].points, lgroup.points)


def test_LandmarkManager_set():
    lgroup = LabelledPointUndirectedGraph(points, adjacency_matrix, mask_dict)

    man = LandmarkManager()
    man['test_set'] = lgroup

    assert_allclose(man._landmark_groups['test_set'].points,
                    lgroup.points)
    assert man._landmark_groups['test_set'].n_labels == 1


def test_LandmarkManager_del():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud

    del man['test_set']

    assert man.n_groups == 0


def test_LandmarkManager_group_order():
    points = np.ones((10, 3))
    pcloud = PointCloud(points, copy=False)
    target = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud.copy()
    man['abc'] = pcloud.copy()
    man['def'] = pcloud.copy()
    assert_equal(list(man._landmark_groups.keys()), ['test_set', 'abc', 'def'])
    # check that after deleting and inserting the order will remain the same.
    del man['test_set']
    man['tt'] = pcloud.copy()
    assert_equal(list(man._landmark_groups.keys()), ['abc', 'def', 'tt'])


def test_LandmarkManager_in():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud

    assert 'test_set' in man


def test_LandmarkManager_str():
    pcloud = PointCloud(points)

    man = LandmarkManager()
    man['test_set'] = pcloud

    out_str = man.__str__()
    assert len(out_str) > 0
