#
#  --------------------------------------------------------------------------
#   Gurux Ltd
#
#
#
#  Filename: $HeadURL$
#
#  Version: $Revision$,
#                   $Date$
#                   $Author$
#
#  Copyright (c) Gurux Ltd
#
# ---------------------------------------------------------------------------
#
#   DESCRIPTION
#
#  This file is a part of Gurux Device Framework.
#
#  Gurux Device Framework is Open Source software; you can redistribute it
#  and/or modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; version 2 of the License.
#  Gurux Device Framework 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 General Public License for more details.
#
#  More information of Gurux products: http://www.gurux.org
#
#  This code is licensed under the GNU General Public License v2.
#  Full text may be retrieved at http://www.gnu.org/licenses/gpl-2.0.txt
# ---------------------------------------------------------------------------
from .GXDLMSObject import GXDLMSObject
from .IGXDLMSBase import IGXDLMSBase
from ..enums import ErrorCode
from ..internal._GXCommon import _GXCommon
from ..GXByteBuffer import GXByteBuffer
from ..enums import ObjectType, DataType
from .GXDLMSSpecialDay import GXDLMSSpecialDay

# pylint: disable=too-many-instance-attributes
class GXDLMSSpecialDaysTable(GXDLMSObject, IGXDLMSBase):
    """
    Online help:
    http://www.gurux.fi/Gurux.DLMS.Objects.GXDLMSSpecialDaysTable
    """

    def __init__(self, ln="0.0.11.0.0.255", sn=0):
        """
        Constructor.

        ln : Logical Name of the object.
        sn : Short Name of the object.
        """
        super(GXDLMSSpecialDaysTable, self).__init__(ObjectType.SPECIAL_DAYS_TABLE, ln, sn)
        # Special day entries.
        self.entries = list()

    #
    # Inserts a new entry in the table
    # If a special day with the same index or with the same date as an
    #      already
    # defined day is inserted, the old entry will be overwritten.
    #
    # @param client
    # DLMS Client.
    # @param entries
    # Inserted special day entries.
    # Generated byte array.
    def insert(self, client, entries):
        bb = GXByteBuffer()
        bb.setUInt8(DataType.ARRAY)
        _GXCommon.setObjectCount(len(entries), bb)
        for entry in entries:
            bb.setUInt8(DataType.STRUCTURE)
            bb.setUInt8(3)
            _GXCommon.setData(None, bb, DataType.UINT16, entry.index)
            _GXCommon.setData(None, bb, DataType.OCTET_STRING, entry.date)
            _GXCommon.setData(None, bb, DataType.UINT8, entry.dayId)
        return client.method(self, 1, bb.array(), DataType.ARRAY)

    #
    # Deletes an entry in the table.
    #
    # @param client
    # DLMS Client.
    # @param entry
    # Deleted special day item.
    # Generated byte array.
    def delete(self, client, entry):
        return client.method(self, 2, entry.index, DataType.UINT16)

    def getValues(self):
        return [self.logicalName,
                self.entries]

    def getAttributeIndexToRead(self, all_):
        attributes = list()
        #  LN is static and read only once.
        if all_ or not self.logicalName:
            attributes.append(1)
        #  Entries
        if all_ or not self.isRead(2):
            attributes.append(2)
        return attributes

    #
    # Returns amount of attributes.
    #
    def getAttributeCount(self):
        return 2

    #
    # Returns amount of methods.
    #
    def getMethodCount(self):
        return 2

    def getDataType(self, index):
        if index == 1:
            return DataType.OCTET_STRING
        if index == 2:
            return DataType.ARRAY
        raise ValueError("getDataType failed. Invalid attribute index.")

    #
    # Returns value of given attribute.
    #
    def getValue(self, settings, e):
        if e.index == 1:
            return _GXCommon.logicalNameToBytes(self.logicalName)
        if e.index == 2:
            data = GXByteBuffer()
            data.setUInt8(DataType.ARRAY)
            if not self.entries:
                _GXCommon.setObjectCount(0, data)
            else:
                cnt = len(self.entries)
                #  Add count
                _GXCommon.setObjectCount(cnt, data)
                for it in self.entries:
                    data.setUInt8(DataType.STRUCTURE)
                    data.setUInt8(3)
                    #  Count
                    _GXCommon.setData(settings, data, DataType.UINT16, it.index)
                    _GXCommon.setData(settings, data, DataType.OCTET_STRING, it.date)
                    _GXCommon.setData(settings, data, DataType.UINT8, it.dayId)
            return data
        e.error = ErrorCode.READ_WRITE_DENIED
        return None

    #
    # Set value of given attribute.
    #
    def setValue(self, settings, e):
        if e.index == 1:
            self.logicalName = _GXCommon.toLogicalName(e.value)
        elif e.index == 2:
            self.entries = []
            if e.value:
                for item in e.value:
                    it = GXDLMSSpecialDay()
                    it.index = item[0]
                    it.date = _GXCommon.changeType(settings, item[1], DataType.DATE)
                    it.dayId = item[2]
                    self.entries.append(it)
        else:
            e.error = ErrorCode.READ_WRITE_DENIED

    def invoke(self, settings, e):
        if e.index != 1 and e.index != 2:
            e.error = ErrorCode.READ_WRITE_DENIED
        else:
            items = list()
            if self.entries:
                items.append(self.entries)
            if e.index == 1:
                item = e.parameters
                it = GXDLMSSpecialDay()
                it.index = item[0]
                it.date = _GXCommon.changeType(settings, item[1], DataType.DATE)
                it.dayId = item[2]
                for item2 in items:
                    if item2.index == it.index:
                        items.remove(item2)
                        break
                items.append(it)
            elif e.index == 2:
                index = e.parameters
                for item in items:
                    if item.index == index:
                        items.remove(item)
                        break
            self.entries = items

    def load(self, reader):
        self.entries = []
        if reader.isStartElement("Entries", True):
            while reader.isStartElement("Entry", True):
                it = GXDLMSSpecialDay()
                it.index = reader.readElementContentAsInt("Index")
                it.date = reader.readElementContentAsDate("Date")
                it.dayId = reader.readElementContentAsInt("DayId")
                self.entries.append(it)
            reader.readEndElement("Entries")

    def save(self, writer):
        if self.entries:
            writer.writeStartElement("Entries")
            for it in self.entries:
                writer.writeStartElement("Entry")
                writer.writeElementString("Index", it.index)
                writer.writeElementString("Date", it.date)
                writer.writeElementString("DayId", it.dayId)
                writer.writeEndElement()
            writer.writeEndElement()
