from builtins import object
#from future.utils import with_metaclass

#import abc


#class ConstructAccess(with_metaclass(abc.ABCMeta, object)):
class ConstructAccess(object):
    '''Mixin class for accessing an embedded `Constructs` object.

.. versionadded:: 1.7.0

    '''   
    def del_construct(self, key, default=ValueError()):
        '''Remove a metadata construct.

If a domain axis construct is selected for removal then it can't be
spanned by any metdata construct data, nor the field construct's
data; nor be referenced by any cell method constructs.

However, a domain ancillary construct may be removed even if it is
referenced by coordinate reference construct. In this case the
reference is replace with `None`.

.. versionadded:: 1.7.0

.. seealso:: `constructs`, `get_construct`, `has_construct`,
             `set_construct`

:Parameters:

    key: `str`, optional
        The key of the metadata construct to be removed.

        *Parameter example:*
          ``key='auxiliarycoordinate0'``
        
    default: optional
        Return the value of the *default* parameter if the construct
        can not be removed, or does not exist. If set to an
        `Exception` instance then it will be raised instead.

:Returns:

        The removed metadata construct.

**Examples:**

>>> f.del_construct('dimensioncoordinate1')
<DimensionCoordinate: grid_latitude(111) degrees>

        '''
        return self.constructs._del_construct(key, default=default)
    #--- End: def

    def get_construct(self, key, default=ValueError()):
        '''Return a metadata construct.

.. versionadded:: 1.7.0

.. seealso:: `constructs`, `del_construct`, `has_construct`,
             `set_construct`

:Parameters:

    key: `str`
        The key of the metadata construct.

        *Parameter example:*
          ``key='domainaxis1'``

    default: optional
        Return the value of the *default* parameter if the construct
        does not exist. If set to an `Exception` instance then it will
        be raised instead.

:Returns:

        The metadata construct.

**Examples:**

>>> f.constructs()
{'auxiliarycoordinate0': <AuxiliaryCoordinate: latitude(10, 9) degree_N>,
 'auxiliarycoordinate1': <AuxiliaryCoordinate: longitude(9, 10) degreeE>,
 'auxiliarycoordinate2': <AuxiliaryCoordinate: long_name:greek_letters(10) >,
 'coordinatereference1': <CoordinateReference: rotated_latitude_longitude>,
 'dimensioncoordinate1': <DimensionCoordinate: grid_latitude(10) degrees>,
 'dimensioncoordinate2': <DimensionCoordinate: grid_longitude(9) degrees>,
 'domainaxis1': <DomainAxis: 10>,
 'domainaxis2': <DomainAxis: 9>}
>>> f.get_construct('dimensioncoordinate1')
<DimensionCoordinate: grid_latitude(10) degrees>

        '''
        return self.constructs.filter_by_key(key).value(default=default)
    #--- End: def

    def has_construct(self, key):
        '''Whather a metadata construct exisits.

.. versionadded:: 1.7.0

.. seealso:: `constructs`, `del_construct`, `get_construct`,
             `set_construct`

:Parameters:

    key: `str`, optional
        The key of the metadata construct.

        *Parameter example:*
          ``key='auxiliarycoordinate0'``

:Returns:

    `bool` 
        True if the construct exisits, otherwise False.

**Examples:**

>>> f.has_construct('dimensioncoordinate1')
True

>>> f.has_construct('dimensioncoordinate99')
False

        '''
        return self.constructs._del_construct(key, default=default)
    #--- End: def

    def set_construct(self, construct, key=None, axes=None,
                      copy=True):
        '''Set a metadata construct.

.. versionadded:: 1.7.0

.. seealso:: `constructs`, `del_construct`, `get_construct`,
             `set_data_axes`

:Parameters:

    construct:
        The metadata construct to be inserted.

    key: `str`, optional
        The construct identifier to be used for the construct. If not
        set then a new, unique identifier is created automatically. If
        the identifier already exisits then the exisiting construct
        will be replaced.

        *Parameter example:*
          ``key='cellmeasure0'``

    axes: (sequence of) `str`, optional
        The construct identifiers of the domain axis constructs
        spanned by the data array. An exception is raised if used for
        a metadata construct that can not have a data array,
        i.e. domain axis, cell method and coordinate reference
        constructs.

        *Parameter example:*
          ``axes='domainaxis1'``
        
        *Parameter example:*
          ``axes=['domainaxis1']``
        
        *Parameter example:*
          ``axes=['domainaxis1', 'domainaxis0']``
        
    copy: `bool`, optional
        If True then set a copy of the construct. By default the
        construct is not copied.
      
:Returns:

     `str`
        The construct identifier for the construct.
    
**Examples:**

>>> key = f.set_construct(c)
>>> key = f.set_construct(c, copy=False)
>>> key = f.set_construct(c, axes='domainaxis2')
>>> key = f.set_construct(c, key='cellmeasure0')

        '''
        return self.constructs._set_construct(construct, key=key,
                                              axes=axes, copy=copy)
    #--- End: def

    def get_data_axes(self, key, default=ValueError):
        '''Return the keys of the domain axis constructs spanned by the data
of a metadata construct.

.. versionadded:: 1.7.0

.. seealso:: `del_data_axes`, `has_data_axes`, `set_data_axes`

:Parameters:

    key: `str`, optional
        Specify a metadata construct.

        *Parameter example:*
          ``key='auxiliarycoordinate0'``

    default: optional
        Return the value of the *default* parameter if the data axes
        have not been set. If set to an `Exception` instance then it
        will be raised instead.

:Returns:

    `tuple` 
        The keys of the domain axis constructs spanned by the data.

**Examples:**

>>> f.set_data_axes(['domainaxis0', 'domainaxis1'])
>>> f.get_data_axes()
('domainaxis0', 'domainaxis1')
>>> f.del_data_axes()
('domainaxis0', 'domainaxis1')
>>> print(f.del_dataxes(None))
None
>>> print(f.get_data_axes(default=None))
None

        '''
        try:
            return self.constructs.data_axes()[key]
        except KeyError:
            return self._default(default, message='2736492783 e28037 TODO')
    #--- End: def

    def del_data_axes(self, key, default=ValueError()):
        '''Remove the keys of the domain axis constructs spanned by the data
of a metadata construct.

.. versionadded:: 1.7.0

.. seealso:: `get_data_axes`, `has_data_axes`, `set_data_axes`

:Parameters:

    key: `str`, optional
        Specify a metadata construct, instead of the field construct.

        *Parameter example:*
          ``key='auxiliarycoordinate0'``

    default: optional
        Return the value of the *default* parameter if the data axes
        have not been set. If set to an `Exception` instance then it
        will be raised instead.

:Returns:

    `tuple` 
        The removed keys of the domain axis constructs spanned by the
        data.

**Examples:**

>>> f.del_data_axes(key='dimensioncoordinate2')
('domainaxis1',)

>>> f.has_data_axes(key='auxiliarycoordinate0')
False
>>> f.has_data_axes(key='auxiliarycoordinate0', default='no axes')
'no axes'

        '''   
        try:
            data_axes = self.constructs.data_axes()[key]
        except KeyError:
            return self._default(default, message='asd aosg8qwg dlb TODO')
        else:
            self.constructs._del_data_axes(key)
                
        return data_axes
    #--- End: def
    
    def has_data_axes(self, key=None):
        '''Whether the domain axis constructs spanned by the data of a
metadata construct have been set.

.. versionadded:: 1.7.0

.. seealso:: `del_data_axes`, `get_data_axes`, `set_data_axes`

:Parameters:

    key: `str`, optional
        Specify a metadata construct.

        *Parameter example:*
          ``key='domainancillary1'``

:Returns:

    `bool` 
        True if domain axis constructs that span the data been set,
        otherwise False.

**Examples:**

>>> f.set_data_axes(['domainaxis0', 'domainaxis1'])
>>> f.get_data_axes()
('domainaxis0', 'domainaxis1')
>>> f.del_data_axes()
('domainaxis0', 'domainaxis1')
>>> print(f.del_dataxes(None))
None
>>> print(f.get_data_axes(default=None))
None

        '''
        axes = self.get_data_axes(key, default=None)
        if axes is None:
            return False

        return True
    #--- End: def
    
    def set_data_axes(self, axes, key):
        '''Set the domain axis constructs spanned by the data of a metadata
construct.

.. versionadded:: 1.7.0

.. seealso:: `data`, `del_data_axes`, `get_data`, `get_data_axes`,
             `has_data_axes`

:Parameters:

     axes: sequence of `str`
        The identifiers of the domain axis constructs spanned by the
        data of the field or of a metadata construct.

        *Parameter example:*
          ``axes='domainaxis1'``

        *Parameter example:*
          ``axes=['domainaxis1']``

        *Parameter example:*
          ``axes=['domainaxis1', 'domainaxis0']``

     key: `str`, optional
        Specify a metadata construct.

        *Parameter example:*
          ``key='domainancillary1'``

:Returns:

    `None`

**Examples:**

>>> f.set_data_axes(['domainaxis0', 'domainaxis1'])
>>> f.get_data_axes()
('domainaxis0', 'domainaxis1')
>>> f.del_data_axes()
('domainaxis0', 'domainaxis1')
>>> print(f.del_dataxes(None))
None
>>> print(f.get_data_axes(None))
None

        '''
        self.constructs._set_construct_data_axes(key=key, axes=axes)
    #--- End: def

#--- End: class
