#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
ElementContainerMatrixをPythonのSerialize機能を使用し、シリアライズする
v03: ECA and EC can be serialized at 2010.01.19
v02: pickle -> cPickle at 2010.01.18
v01:start development at 2009.12.20
"""
from __future__ import print_function

import Manyo as mm
try:
    import cPickle as pickle
except ImportError:
    import pickle

################################
#      ECMSerialize
################################


class ECMSerialize(object):
    """
    ElementContainer,-Array,-Matrixのシリアライズ
    """

    def __init__(self):
        self.CommentHeader = "ECMSerialize>>> "

    def Encode(self, dat=None, filename=None):
        """
        Encode
        ElementConainer,-Array,-Matrixをシリアライズ
        @param dat      (ElementContainer or -Array or -Matrix) Data
        @param filename (string) File name
        @retval None
        """
        if (dat is None) or (filename is None):
            print(self.CommentHeader + "You must set EC,ECA,ECM and filename.")
            print(">>> ECMSerialize.Encode(ecm,filename)")
            return

        # if (type(dat)==type(mm.ElementContainerMatrix())):
        if isinstance(dat, mm.ElementContainerMatrix):
            obj = self._SerializeECM(dat)
        # elif (type(dat)==type(mm.ElementContainerArray())):
        elif isinstance(dat, mm.ElementContainerArray):
            obj = self._SerializeECA(dat)
        # elif (type(dat)==type(mm.ElementContainer())):
        elif isinstance(dat, mm.ElementContainer):
            obj = self._SerializeEC(dat)

        try:
            file = open(filename, "wb")
        except PermissionError:
            err_message = "Cannot open file.{}".format(filename)
            raise UserWarning(err_message)

        pickle.dump(obj, file, 2)
        file.close()
        del obj

    def Decode(self, filename=None):
        """
        Decode
        シリアライズされたファイルを読み込みElementContainer,-Array,-Matixを構築
        @param filename (string) File name
        @retval ElementContainer,-Array,-Matrix
        """
        if filename is None:
            print(self.CommentHeader + "You must set filename.")
            print(">>> dat = ECMSerialize.Decode(filename)")
            return

        try:
            file = open(filename, "rb")
        except PermissionError:
            err_message = "cannot open file. {}".format(filename)
            raise UserWarning(err_message)
            # return

        obj = pickle.load(file)

        file.close()

        ret = None
        if len(obj) == 4:
            print(self.CommentHeader + "This object is ElementContainer.")
            ret = self._DeSerializeEC(obj)
        elif len(obj) == 2:
            child_obj = obj[1][0]
            if len(child_obj) == 4:
                print(self.CommentHeader + "This object is ElementContainerArray.")
                ret = self._DeSerializeECA(obj)
            elif len(child_obj) == 2:
                gran_child_obj = child_obj[1][0]
                if len(gran_child_obj) == 4:
                    print(self.CommentHeader + "This object is ElementContainerMatrix.")
                    ret = self._DeSerializeECM(obj)

        del obj

        if ret is None:
            err_message = self.CommentHeader + "Decoded object is invalid."
            raise UserWarning(err_message)

        return ret

    def _SerializeEC(self, ec):
        """
        Prepare list object for serialize of ElementContainer

        @param ec    (ElementContainer) Data
        @retval List object
        """
        hh = ec.PutHeader().DumpToString()
        Keys = []
        Keys.append(ec.PutXKey())
        Keys.append(ec.PutYKey())
        Keys.append(ec.PutEKey())

        key_vec = ec.PutKeys()
        for i in range(key_vec.size()):
            if key_vec[i] in Keys:
                pass
            else:
                Keys.append(key_vec[i])

        Units = []
        for key in Keys:
            Units.append(ec.PutUnit(key))

        XYE = []
        # XYE.append( ec.PutXList() )
        # XYE.append( ec.PutYList() )
        # XYE.append( ec.PutEList() )
        for key in Keys:
            # XYE.append( ec.PutList(key) )
            v = ec.Put(key)
            ll = []
            for i in range(v.size()):
                ll.append(v[i])
            XYE.append(ll)

        return [hh, Keys, Units, XYE]

    def _SerializeECA(self, eca):
        """
        Prepare list object for serialize of ElementContainerArray

        @param eca    (ElementContainerArray) Data
        @retval List object
        """
        hh = eca.PutHeader().DumpToString()
        S_eca = []
        for pixel in range(eca.PutTableSize()):
            S_eca.append(self._SerializeEC(eca(pixel)))

        return [hh, S_eca]

    def _SerializeECM(self, ecm):
        """
        Prepare list object for serialize of ElementContainerMatrix

        @param ecm    (ElementContainerMatrix) Data
        @retval List object
        """
        hh = ecm.PutHeader().DumpToString()
        S_ecm = []
        for psd in range(ecm.PutTableSize()):
            S_ecm.append(self._SerializeECA(ecm(psd)))

        return [hh, S_ecm]

    def _DeSerializeEC(self, obj):
        """
        Return ElementContainer from decoded list object

        @param  obj    (List object) Decoded list object
        @retval ElementContainer
        """
        if not (isinstance(obj, list) and (len(obj) == 4)):
            print(self.CommentHeader + "This object is not for ElementContainer.")
            return

        hh = mm.HeaderBase()
        hh.InputString(str(obj[0]))
        ec = mm.ElementContainer(hh)
        Keys = obj[1]
        Units = obj[2]
        XYE = obj[3]

        # for i in range(3):
        #    ec.Add(Keys[i],XYE[i],Units[i])
        for i in range(len(Keys)):
            ec.Add(str(Keys[i]), XYE[i], str(Units[i]))

        ec.SetKeys(str(Keys[0]), str(Keys[1]), str(Keys[2]))

        return ec

    def _DeSerializeECA(self, obj):
        """
        Return ElementContainerArray from decoded list object

        @param  obj    (List object) Decoded list object
        @retval ElementContainerArray
        """
        if not (isinstance(obj, list) and (len(obj) == 2)):
            print(self.CommentHeader + "This object is not for ElementContainer.")
            return

        hh = mm.HeaderBase()
        hh.InputString(str(obj[0]))
        eca = mm.ElementContainerArray(hh)
        list_ec = obj[1]
        for ec_obj in list_ec:
            ec = self._DeSerializeEC(ec_obj)
            if ec is not None:
                eca.Add(ec)

        return eca

    def _DeSerializeECM(self, obj):
        """
        Return ElementContainerMatrix from decoded list object

        @param  obj    (List object) Decoded list object
        @retval ElementContainerMatrix
        """
        if not (isinstance(obj, list) and (len(obj) == 2)):
            print(self.CommentHeader + "This object is not for ElementContainer.")
            return

        hh = mm.HeaderBase()
        hh.InputString(str(obj[0]))
        ecm = mm.ElementContainerMatrix(hh)

        eca_list = obj[1]
        for eca_obj in eca_list:
            eca = self._DeSerializeECA(eca_obj)
            if eca is not None:
                ecm.Add(eca)

        return ecm
