#! /usr/bin/env python
"""An abstract base class for all Dakota experiments."""

from abc import ABCMeta, abstractmethod
import types
import yaml


class DakotaBase(object):

    """Describe features common to all Dakota experiments."""

    __metaclass__ = ABCMeta

    @abstractmethod
    def __init__(self,
                 component=None,
                 template_file=None,
                 method=None,
                 configuration_file='config.yaml',
                 run_directory='.',
                 input_files=None,
                 data_file='dakota.dat',
                 variable_type='continuous_design',
                 variable_descriptors=None,
                 interface='direct',
                 analysis_driver='rosenbrock',
                 is_objective_function=False,
                 response_descriptors=(),
                 response_files=None,
                 response_statistics=None,
                 **kwargs):
        """Create a set of default experiment parameters."""
        self.component = component
        self.configuration_file = configuration_file
        self.run_directory = run_directory
        self.template_file = template_file
        self.input_files = input_files
        self.data_file = data_file
        self.method = method
        self.variable_type = variable_type
        self.variable_descriptors = [] if variable_descriptors is None \
                                    else variable_descriptors
        self.interface = interface
        self.analysis_driver = analysis_driver
        self.parameters_file = 'params.in'
        self.results_file = 'results.out'
        self.is_objective_function = is_objective_function
        self._response_descriptors = response_descriptors
        self.response_files = response_files
        self.response_statistics = response_statistics

    @property
    def response_descriptors(self):
        """Labels attached to Dakota responses."""
        return self._response_descriptors

    @response_descriptors.setter
    def response_descriptors(self, value):
        """Set labels for Dakota responses.

        Parameters
        ----------
        value : list or tuple of str
          The new response labels.

        """
        if not isinstance(value, (tuple, list)):
            raise TypeError("Descriptor must be a tuple or a list")
        self._response_descriptors = value

    @classmethod
    def from_file_like(cls, file_like):
        """Create a DakotaBase instance from a file-like object.

        Parameters
        ----------
        file_like : file_like
            Input parameter file.

        Returns
        -------
        DakotaBase
            A new DakotaBase instance.

        """
        config = {}
        if isinstance(file_like, types.StringTypes):
            with open(file_like, 'r') as fp:
                config = yaml.load(fp.read())
        else:
            config = yaml.load(file_like)
        return cls(**config)

    def environment_block(self):
        """Define the environment block of a Dakota input file."""
        s = '# Dakota input file\n' \
            + 'environment\n' \
            + '  tabular_data\n' \
            + '    tabular_data_file = {!r}\n\n'.format(self.data_file)
        return(s)

    @abstractmethod
    def method_block(self):
        """Define the method block of a Dakota input file."""
        s = 'method\n' \
            + '  {}\n\n'.format(self.method)
        return(s)

    def variables_block(self):
        """Define the variables block of a Dakota input file."""
        s = 'variables\n' \
            + ' {0} = {1}\n'.format(self.variable_type,
                                    len(self.variable_descriptors))
        s += '    descriptors ='
        for vd in self.variable_descriptors:
            s += ' {!r}'.format(vd)
        s += '\n\n'
        return(s)

    def interface_block(self):
        """Define the interface block of a Dakota input file."""
        s = 'interface\n' \
            + '  {}\n'.format(self.interface) \
            + '  analysis_driver = {!r}\n'.format(self.analysis_driver)
        if self.component is not None:
            s += '  analysis_components = {!r}\n'.format(self.configuration_file)
        if self.interface is not 'direct':
            s += '  parameters_file = {!r}\n'.format(self.parameters_file) \
                 + '  results_file = {!r}\n'.format(self.results_file) \
                 + '  work_directory\n' \
                 + '    named \'run\'\n' \
                 + '    directory_tag\n' \
                 + '    directory_save\n' \
                 + '  file_save\n'
        s += '\n'
        return(s)

    def responses_block(self):
        """Define the responses block of a Dakota input file."""
        n_responses = len(self.response_descriptors)
        s = 'responses\n'
        if self.is_objective_function:
            s += '  objective_functions = {}\n'.format(n_responses)
        else:
            s += '  response_functions = {}\n'.format(n_responses)
        s += '    response_descriptors ='
        for rd in self.response_descriptors:
            s += ' {!r}'.format(rd)
        s += '\n' \
             + '  no_gradients\n' \
             + '  no_hessians\n'
        return(s)

@@ -656,20 +656,18 @@
 riptors=
-None
+()
 ,%0A      
@@ -1327,32 +1327,33 @@
 pe%0A        self.
+_
 variable_descrip
@@ -1362,86 +1362,8 @@
 rs =
- %5B%5D if variable_descriptors is None %5C%0A                                    else
  var
@@ -1705,24 +1705,24 @@
 ponse_files%0A
-
         self
@@ -1765,16 +1765,566 @@
 istics%0A%0A
+    @property%0A    def variable_descriptors(self):%0A        %22%22%22Labels attached to Dakota variables.%22%22%22%0A        return self._variable_descriptors%0A%0A    @variable_descriptors.setter%0A    def variable_descriptors(self, value):%0A        %22%22%22Set labels for Dakota variables.%0A%0A        Parameters%0A        ----------%0A        value : list or tuple of str%0A          The new variables labels.%0A%0A        %22%22%22%0A        if not isinstance(value, (tuple, list)):%0A            raise TypeError(%22Descriptor must be a tuple or a list%22)%0A        self._variable_descriptors = value%0A%0A
     @pro

Make variable_descriptors a property