# 
#  Copyright (C) 2010-2011,2016,2019,2021  Smithsonian Astrophysical Observatory
#
#
#  This program is free 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; either version 3 of the License, or
#  (at your option) any later version.
#
#  This program 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.
#
#  You should have received a copy of the GNU General Public License along
#  with this program; if not, write to the Free Software Foundation, Inc.,
#  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

from pycrates.crateutils import *
import pycrates.io as io
import hashlib

class CrateKey:

    def __init__(self, input=None):
        """
        Initializes the CrateKey object.

        Parameters
        ----------
           tuple  :  (name, value, unit, desc, [groups])
                     default = None

        Returns
        -------
            None

        """
        self.__clear__()

        if input is None:
            return
        
        # if input is a tuple
        if isinstance(input, tuple):
            if len(input) == 5 :
                self.name, self.value, self.unit, self.desc, self.groups = input
            elif len(input) > 0 :
                for ii in range( len(input) ) :
                    if ii == 0:
                        self.name = input[ii]
                    if ii == 1:
                        self.value = input[ii]
                    if ii == 2:
                        self.unit = input[ii]
                    if ii == 3:
                        self.desc = input[ii]
                    if ii == 4:
                        self.groups = input[ii]
                    
        else:
            backend = io.select( input )
            if (backend is not None ):
                backend.load(self, input) 
 
            else:
                raise AttributeError("Unable to populate CrateKey object from input.")


    def __clear__(self):
        """
        Clears the CrateKey object.
        """
        self._name = ""
        self._desc = ""
        self._unit = ""
        self._value = 0
        self._groups = []
        self.__signature = ""

    def __del__(self):
        """
        Clears and closes the CrateKey object.
        """
        self.__clear__()


    def __str__(self):
        """
        Returns a formatted string representation of the CrateKey object.
        """
        return self.__repr__()


    def __repr__(self):
        """
        Returns a formatted string representation of the CrateKey object.
        """
        retstr =  "   Name:   " + self.name  + "\n"
        retstr += "   Value:  " + str(self.value) + "\n"
        retstr += "   Unit:   " + self.unit  + "\n"
        retstr += "   Desc:   " + self.desc  + "\n"
        retstr += "   Groups: " + str(self.groups)  + "\n"
        return retstr


    def get_value(self):
        return self._value

    def _set_value(self, in_value):
        """
        Sets the value of the CrateKey object.
        """
        in_value = convert_2_str(in_value)
        self._value = in_value
 
    value = property(get_value, _set_value)


    def get_name(self):
        return self._name

    def _set_name(self, in_name):
        """
        Sets the name of the CrateKey object.
        """
        in_name = convert_2_str(in_name)
        self._name = in_name
 
    name = property(get_name, _set_name)

    def get_unit(self):
        return self._unit

    def _set_unit(self, in_unit):
        """
        Sets the unit of the CrateKey object.
        """
        if in_unit is None:
            in_unit = ""
        in_unit = convert_2_str(in_unit)
        self._unit = in_unit
 
    unit = property(get_unit, _set_unit)


    def get_desc(self):
        return self._desc

    def _set_desc(self, in_desc):
        """
        Sets the description of the CrateKey object.
        """
        if in_desc is None:
            in_desc = "";
        in_desc = convert_2_str(in_desc)
        self._desc = in_desc

    desc = property(get_desc, _set_desc)



    def get_groups(self):
        return self._groups

    def _set_groups(self, in_groups):
        """
        Sets the groups of the CrateKey object.
        """
        if in_groups is None or (isinstance(in_groups, (list,str)) and len(in_groups) == 0):
            self._groups = []
        else:
            self._groups = parse_groupings(in_groups)

    groups = property(get_groups, _set_groups)



    def is_modified(self):
        current_sig = self.__calculate_signature()

        if current_sig != self.get_signature():
            return True
        return False


    def __calculate_signature(self):
        sigstr = self.__str__()
        return hashlib.sha256( sigstr.encode('utf-8') ).hexdigest()


    def get_signature(self):
        """
        Retrieves the stored checksum of the CrateKey.
        """
        
        if len(self.__signature) == 0:
            self.update_signature()
        return self.__signature


    def update_signature(self):
        """
        Recalculates and stores the new checksum.
        """
        self.__signature = self.__calculate_signature()
        
