from typing import Generic, Any, Type, TypeVar

import pythoncom
from win32com.client import CDispatch, Dispatch

import IFikatia
from IFikoSinyaller.IFikoSinyaller import IFikoSinyaller
from IFikoSistem.IFikoToDic import fiko2Dict


globalSinyal = IFikoSinyaller()


class IParametreler:
    pass


class IFikoObject(object):
    def __init__(self, sahip=None, anaProgram=None):
        self.__ismi = None
        self.__sahip = sahip
        self.__anaProgram = anaProgram
        self.__tipi = "IFikoObject"
        # --->
        global globalSinyal
        self.__sinyaller = globalSinyal

    @property
    def ismi(self) -> str:
        return self.__ismi

    @ismi.setter
    def ismi(self, value: str):
        self.__ismi = value

    @property
    def tipi(self) -> str:
        return self.__tipi

    @tipi.setter
    def tipi(self, value: str):
        self.__tipi = value

    @property
    def sahip(self):
        return self.__sahip

    @sahip.setter
    def sahip(self, value):
        self.__sahip = value

    @property
    def anaProgram(self):
        return self.__anaProgram

    @anaProgram.setter
    def anaProgram(self, value):
        self.__anaProgram = value

    @property
    def fikoSinyaller(self) -> IFikoSinyaller:
        return self.__sinyaller

    @fikoSinyaller.setter
    def fikoSinyaller(self, value: IFikoSinyaller):
        self.__sinyaller = value


T = TypeVar("T")


class IFikomObject(object):
    """
    Genel Bir Object Sinifi-->Tum Alt Siniflarin Atasi

    Tum Alt Siniflar Icin Ata Sinif Olarak Kullanilacak.
    """

    def __init__(self, obj=None, sahip=None):
        # --> Com Obje Nesneleri
        self.__obj = obj
        self.__ismi = None
        self.__parent = None
        self.__sahip = sahip
        self.__anaProgram = None
        self.__catNesne = obj
        self.__tipi = None
        # --->
        self.__marshallReferansAnaProgram = None
        self.__marshallReferansAnaSahip = None
        self.__marshallReferans = None
        self.__catMarshall = None
        self.__marshallVerildi = False
        # self.marshalHazirla()
        # --->

    @property
    def obj(self) -> CDispatch:
        rslt = self.__obj
        if str(type(rslt)) == "<class 'PyIStream'>":
            rslt.Seek(0, 0)
            rslt = Dispatch(
                pythoncom.CoGetInterfaceAndReleaseStream(rslt, pythoncom.IID_IDispatch)
            )
        return rslt
        # return self.__obj

    @obj.setter
    def obj(self, val):
        self.__obj = val
        self.__catNesne = val
        self.__anaProgram = val.Application

    @property
    def ismi(self) -> str:
        if self.__ismi != None:
            return self.__ismi
        else:
            try:
                return self.__obj.Name
            except:
                print(ReferenceError("Catia Nesnesi Isim Desteklemiyor"))

    @ismi.setter
    def ismi(self, value) -> str:
        try:
            self.__catNesne.Name = value
            self.__ismi = value
        except Exception as e:
            print(e)
            self.__ismi = value

    @property
    def parent(self) -> CDispatch:
        return self.__parent if self.__parent != None else self.obj.parent

    @parent.setter
    def parent(self, value: CDispatch):
        self.__parent = value

    @property
    def sahip(self):
        return self.__sahip

    @sahip.setter
    def sahip(self, value):
        self.__sahip = value

    def sahipBulTipiyle(self, value: str):
        max = 100
        cur = 0
        temp = self
        while temp.tipi != value:
            temp = temp.sahip
            cur += 1
            if cur > max:
                print("Sonsuz Dongu Hatasi")
                return None
                break
        return temp

    @property
    def anaProgram(self) -> IFikatia:
        # print(getattr(self.catNesne, "_oleobj_", self.catNesne).GetTypeInfo().GetDocumentation(-1)[0])

        rslt = (
            self.__anaProgram
            if self.__anaProgram != None
            else self.catNesne.Application
        )

        if str(type(rslt)) == "<class 'PyIStream'>":
            rslt.Seek(0, 0)
            rslt = Dispatch(
                pythoncom.CoGetInterfaceAndReleaseStream(rslt, pythoncom.IID_IDispatch)
            )
        return IFikatia.IFikatia(rslt,rslt)
        print(type(self.catNesne))
        return (
            IFikatia.IFikatia(self.catNesne.Application)
            if self.__anaProgram == None
            else self.__anaProgram
        )

    @anaProgram.setter
    def anaProgram(self, value):
        self.__anaProgram = value

    @property
    def catNesne(self) -> CDispatch:
        rslt = self.__catNesne if self.__catNesne != None else self.__obj
        if str(type(rslt)) == "<class 'PyIStream'>":
            rslt.Seek(0, 0)
            rslt = Dispatch(
                pythoncom.CoGetInterfaceAndReleaseStream(rslt, pythoncom.IID_IDispatch)
            )
        return rslt

    @catNesne.setter
    def catNesne(self, value: CDispatch):
        self.__catNesne = value
        self.__obj = value
        self.__anaProgram = value.Application
        # self.__marshallReferans = pythoncom.CoMarshalInterThreadInterfaceInStream(
        #     pythoncom.IID_IDispatch, self.__obj
        # )
        # self.__marshallReferansAnaProgram = (
        #     pythoncom.CoMarshalInterThreadInterfaceInStream(
        #         pythoncom.IID_IDispatch, self.__obj.Application
        #     )
        # )

    @property
    def tipi(self) -> str:
        return self.__tipi

    @tipi.setter
    def tipi(self, value: str):
        self.__tipi = value

    @property
    def parametreler(self) -> IParametreler:
        return IParametreler(self.catNesne.Parameters, self)

    @property
    def catMarshall(self) -> CDispatch:
        if not self.__marshallReferans:
            self.__marshallReferans = pythoncom.CoMarshalInterThreadInterfaceInStream(
                pythoncom.IID_IDispatch, self.__obj
            )
        else:
            self.__marshallReferans.Seek(0, 0)
        if not self.__marshallReferansAnaProgram:
            self.__marshallReferansAnaProgram = (
                pythoncom.CoMarshalInterThreadInterfaceInStream(
                    pythoncom.IID_IDispatch, self.__obj.Application
                )
            )
        else:
            self.__marshallReferansAnaProgram.Seek(0, 0)
        self.__catNesne = self.__marshallReferans
        self.__obj = self.__marshallReferans
        self.__anaProgram = self.__marshallReferansAnaProgram
        return self.__marshallReferans

    @catMarshall.setter
    def catMarshall(self, value: CDispatch):
        if not self.__marshallVerildi:
            self.__catMarshall = Dispatch(
                pythoncom.CoGetInterfaceAndReleaseStream(
                    self.__marshallReferans, pythoncom.IID_IDispatch
                )
            )
            self.__marshallVerildi = True
            # self.catNesne = self.__catMarshall
            return self.__catMarshall
        else:
            return self.__catMarshall

    @property
    def fikoSinyaller(self) -> IFikoSinyaller:
        if not self.__sinyaller:
            global globalSinyal
            self.__sinyaller = globalSinyal
        return self.__sinyaller

    @fikoSinyaller.setter
    def fikoSinyaller(self, value: IFikoSinyaller):
        self.__sinyaller = value

    def asType(self, catTip: str, tip: Type[T] = None) -> T:
        EvalCode = (
            """
        			Dim myManufacturingTool As """
            + catTip
            + """
                    Set myManufacturingTool = Process
                    Set return = myManufacturingTool
        		"""
        )
        # --->Sabit Degiskenler
        obj1 = self.anaProgram.eval(EvalCode, "Process", [self.catNesne])
        if tip:
            return tip(obj=obj1, sahip=self.sahip)
        else:
            return obj1
    
    def marshalHazirla(self):
        if (not self.__marshallReferans):

            self.__marshallReferans = pythoncom.CoMarshalInterThreadInterfaceInStream(
                    pythoncom.IID_IDispatch, self.__obj
            )
        if (not self.__marshallReferansAnaProgram):
            self.__marshallReferansAnaProgram = (
                    pythoncom.CoMarshalInterThreadInterfaceInStream(
                        pythoncom.IID_IDispatch, self.__obj.Application
                )
            )


    def marshalOku(self):
        if (self.__marshallReferans):
            self.__marshallReferans.Seek(0, 0)
            self.__catNesne = Dispatch(
                    pythoncom.CoGetInterfaceAndReleaseStream(self.__marshallReferans, pythoncom.IID_IDispatch)
                )
            self.__obj=self.__catNesne,

        if(self.__marshallReferansAnaProgram):
            self.__marshallReferansAnaProgram.Seek(0, 0)
            self.__anaProgram = Dispatch(
                    pythoncom.CoGetInterfaceAndReleaseStream(self.__marshallReferansAnaProgram, pythoncom.IID_IDispatch)
            )

from IParametreler import IParametreler
