1# -*- coding: utf-8 -*-
2#
3#   Copyright © 2010 Eugeniy Meshcheryakov <eugen@debian.org>
4#
5#   This program is free software: you can redistribute it and/or modify
6#   it under the terms of the GNU Lesser General Public License as published by
7#   the Free Software Foundation, either version 3 of the License, or
8#   (at your option) any later version.
9#
10#   This program is distributed in the hope that it will be useful,
11#   but WITHOUT ANY WARRANTY; without even the implied warranty of
12#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13#   GNU Lesser General Public License for more details.
14#
15#   You should have received a copy of the GNU Lesser General Public License
16#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
17"""
18:mod:`gdsii.structure` --- interface to a GDSII structure
19=========================================================
20
21This module contains class that represents a GDSII structure.
22
23.. moduleauthor:: Eugeniy Meshcheryakov <eugen@debian.org>
24"""
25from __future__ import absolute_import
26from . import elements, record, tags, _records
27from datetime import datetime
28
29_STRNAME = _records.StringRecord('name', tags.STRNAME)
30_BGNSTR = _records.TimestampsRecord('mod_time', 'acc_time', tags.BGNSTR)
31_STRCLASS = _records.SimpleOptionalRecord('strclass', tags.STRCLASS)
32
33class Structure(list):
34    """
35    GDSII structure class. This class is derived for :class:`list` and can
36    contain one or more elements from :mod:`gdsii.elements`.
37
38    GDS syntax for the structure:
39        .. productionlist::
40            structure: BGNSTR
41                     : STRNAME
42                     : [STRCLASS]
43                     : {`element`}*
44                     : ENDSTR
45    """
46    _gds_objs = (_BGNSTR, _STRNAME, _STRCLASS)
47
48    def __init__(self, name, mod_time=None, acc_time=None):
49        """
50        Initialize the structure.
51        `mod_time` and `acc_time` are set to current UTC time by default.
52        """
53        list.__init__(self)
54        self.name = name
55        self.mod_time = mod_time if mod_time is not None else datetime.utcnow()
56        self.acc_time = acc_time if acc_time is not None else datetime.utcnow()
57
58    def _init_optional(self):
59        """Initialize optional attributes to None."""
60        self.strclass = None
61
62    @classmethod
63    def _load(cls, gen):
64        self = cls.__new__(cls)
65        list.__init__(self)
66        self._init_optional()
67
68        for obj in self._gds_objs:
69            obj.read(self, gen)
70
71        # read elements till ENDSTR
72        while gen.current.tag != tags.ENDSTR:
73            self.append(elements._Base._load(gen))
74        return self
75
76    def _save(self, stream):
77        for obj in self._gds_objs:
78            obj.save(self, stream)
79        for elem in self:
80            elem._save(stream)
81        record.Record(tags.ENDSTR).save(stream)
82
83    def __repr__(self):
84        return '<Structure: %s>' % self.name.decode()
85