#!/usr/bin/env python

##############################################################################
##
## This file is part of Sardana
##
## http://www.tango-controls.org/static/sardana/latest/doc/html/index.html
##
## Copyright 2011 CELLS / ALBA Synchrotron, Bellaterra, Spain
##
## Sardana is free software: you can redistribute it and/or modify
## it under the terms of the GNU Lesser General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## Sardana 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 Lesser General Public License for more details.
##
## You should have received a copy of the GNU Lesser General Public License
## along with Sardana.  If not, see <http://www.gnu.org/licenses/>.
##
##############################################################################

"""Tests for list macros"""

import time
from taurus.external import unittest
from sardana.macroserver.macros.test import (RunMacroTestCase, testRun,
                                             SarDemoEnv)


class LsTest(RunMacroTestCase):

    """Base class for testing macros used to list elements.
    See :class:`.RunMacroTestCase` for requirements.
    LsTest use the lists of elem_type generated by :class:`.SarDemoEnv` as
    reference for compare with the output of the tested ls macro.

    LsTest provide the class member:
        - elem_type (str): Type of the element to validate (mandatory).
                           Must be a valid type for :class:`.SarDemoEnv` class.

    It provides the helper method:
      - :meth:`check_elements`
    """

    elem_type = None

    def check_elements(self, list1, list2):
        """ A helper method to evaluate if all elements of list1 are in list2.
           :params list1: (seq<str>) List of elements to evaluate.
           :params list2: (seq<str>) List of elements for validate.
        """
        for elem in list1:
            msg = "{0} does not contain {1}".format(self.macro_name, elem)
            self.assertTrue(elem in list2, msg)

    def macro_runs(self, **kwargs):
        """ Reimplementation of macro_runs method for ls macros.
            It verifies that elements (elem_type) gotten by parsing the
            macro executor log output are in the correspondent
            list (elem_type) of SardanaEnv.
        """
        RunMacroTestCase.macro_runs(self, **kwargs)
        self.log_output = self.macro_executor.getLog("output")
        msg = "generic ls macro does not contain elements"
        self.assertTrue(len(self.log_output) > 0, msg)

        if (self.elem_type is not None):
            list_sardemo = SarDemoEnv().getElements(self.elem_type)
        else:
            raise Exception("element_type cannot be None")

        #parsing log output to get all elements
        header_rows = 2
        names_column_index = 0
        macro_output = []
        for row, in self.log_output[header_rows:]:
            macro_output.append(row.split()[names_column_index])
        # Evaluate if element of A are in B
        if len(macro_output) >= len(list_sardemo):
            self.check_elements(list_sardemo, macro_output)
        else:
            self.check_elements(macro_output, list_sardemo)


@testRun(macro_params=['l.*'])
@testRun
class LsmTest(LsTest, unittest.TestCase):

    """Class used for testing the 'lsm' macro.
       It verifies that all motors created by sar_demo are listed after
       execution of the macro 'lsm'.
    """
    macro_name = "lsm"
    elem_type = "moveable"


@testRun
class LspmTest(LsTest, unittest.TestCase):

    """Class used for testing the 'lspm' macro.
       It verifies that all pseudomotors created by sar_demo are listed after
       execution of the macro 'lspm'.
    """
    macro_name = "lspm"
    elem_type = "pseudomotor"


@testRun
class LsctrlTest(LsTest, unittest.TestCase):

    """Class used for testing the 'lsctrl' macro.
       It verifies that all controllers created by sar_demo are listed after
       execution of the macro 'lsctrl'.
    """
    macro_name = "lsctrl"
    elem_type = "controller"


@testRun
class LsctTest(LsTest, unittest.TestCase):

    """Class used for testing the 'lsct' macro.
       It verifies that all ct created by sar_demo are listed after
       execution of the macro 'lsct'.
    """
    macro_name = "lsct"
    elem_type = "ctexpchannel"


@testRun
class Ls0dTest(LsTest, unittest.TestCase):

    """Class used for testing the 'ls0d' macro.
       It verifies that all 0d created by sar_demo are listed after
       execution of the macro 'ls0d'.
    """
    macro_name = "ls0d"
    elem_type = "zerodexpchannel"


@testRun
class Ls1dTest(LsTest, unittest.TestCase):

    """Class used for testing the 'ls1d' macro.
       It verifies that all 1d created by sar_demo are listed after
       execution of the macro 'ls1d'.
    """
    macro_name = "ls1d"
    elem_type = "onedexpchannel"


@testRun
class Ls2dTest(LsTest, unittest.TestCase):

    """Class used for testing the 'ls2d' macro.
       It verifies that all 2d created by sar_demo are listed after
       execution of the macro 'ls2d'.
    """
    macro_name = "ls2d"
    elem_type = "twodexpchannel"
