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 = None
        self.__tipi = None
        # --->
        self.__catMarshall = None
        self.__marshallVerildi = False
        #--->

    @property
    def obj(self) -> CDispatch:
        return self.__obj

    @obj.setter
    def obj(self, val):
        self.__obj = val
        self.__catNesne = val

    @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:
            # print(ReferenceError("Catia Nesnesine Isim Verilemedi"))
            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:
        return IFikatia.IFikatia(self.obj.Application) if self.__anaProgram == None else self.__anaProgram

    @anaProgram.setter
    def anaProgram(self, value):
        self.__anaProgram = value

    @property
    def catNesne(self) -> CDispatch:
        return self.__catNesne if self.__catNesne != None else self.__obj

    @catNesne.setter
    def catNesne(self, value:CDispatch):
        self.__catNesne = value
        self.__obj = value
        self.__marshallReferans = pythoncom.CoMarshalInterThreadInterfaceInStream(pythoncom.IID_IDispatch, self.__obj)

    @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)
        return self.__catMarshall

    @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

from IParametreler import IParametreler