import pythoncom
from win32com.server import util
from win32com.server import exception

VT_EMPTY = pythoncom.VT_EMPTY


class Bag:
    _public_methods_ = ["Read", "Write"]
    _com_interfaces_ = [pythoncom.IID_IPropertyBag]

    def __init__(self):
        self.data = {}

    def Read(self, propName, varType, errorLog):
        print("read: name=", propName, "type=", varType)
        if propName not in self.data:
            if errorLog:
                hr = 0x80070057
                exc = pythoncom.com_error(0, "Bag.Read", "no such item", None, 0, hr)
                errorLog.AddError(propName, exc)
            raise exception.Exception(scode=hr)
        return self.data[propName]

    def Write(self, propName, value):
        print("write: name=", propName, "value=", value)
        self.data[propName] = value


class Target:
    _public_methods_ = ["GetClassID", "InitNew", "Load", "Save"]
    _com_interfaces_ = [pythoncom.IID_IPersist, pythoncom.IID_IPersistPropertyBag]

    def GetClassID(self):
        raise exception.Exception(scode=0x80004005)  # E_FAIL

    def InitNew(self):
        pass

    def Load(self, bag, log):
        print(bag.Read("prop1", VT_EMPTY, log))
        print(bag.Read("prop2", VT_EMPTY, log))
        try:
            print(bag.Read("prop3", VT_EMPTY, log))
        except exception.Exception:
            pass

    def Save(self, bag, clearDirty, saveAllProps):
        bag.Write("prop1", "prop1.hello")
        bag.Write("prop2", "prop2.there")


class Log:
    _public_methods_ = ["AddError"]
    _com_interfaces_ = [pythoncom.IID_IErrorLog]

    def AddError(self, propName, excepInfo):
        print("error: propName=", propName, "error=", excepInfo)


def test():
    bag = Bag()
    target = Target()
    log = Log()

    target.Save(bag, 1, 1)
    target.Load(bag, log)

    comBag = util.wrap(bag, pythoncom.IID_IPropertyBag)
    comTarget = util.wrap(target, pythoncom.IID_IPersistPropertyBag)
    comLog = util.wrap(log, pythoncom.IID_IErrorLog)

    comTarget.Save(comBag, 1, 1)
    comTarget.Load(comBag, comLog)


if __name__ == "__main__":
    test()
