from os import path
import os
import random
from time import sleep
import shutil
from builtins import property


from IReferans import IReferans

__author__ = 'CAM'

from IFikomObject import IFikomObject
from IParametreler import IParametreler
# from IDokuman import IDokuman
from IProductlar import IProductlar
from IPaylasilanlar import IPaylasilanlar
from IHareket import IHareket
from IYardimciSiniflar import XYZO
# import IFikoNumokrator
from win32com.client import CDispatch
from enum import Enum
from zipfile import ZipFile
from os.path import basename

# class IDokuman: pass


class FikoTedarikYontemi(Enum):
    Bilinmiyor = 0
    Yapilacak = 1
    Satin_Alinacak = 2

    def __str__(self):
        return str(self.name)


class FikoIsModu(Enum):
    Gecerli_Mod = 0,
    Gorsel_Mod = 1,
    Dizayn_Mod = 2


class FikoCiktiTuru(Enum):
    Txt = 0,
    Csv = 1,
    Html = 2


class FikoModelTuru(Enum):
    MT2d = 0,
    MT3d = 1,
    MTYazi = 2


class IProduct(IFikomObject):
    def __init__(self, obj: CDispatch, sahip: IFikomObject = None):

        super(IProduct, self).__init__(obj, sahip)
        self.sahip = sahip
        self.tipi = "IProduct"

    # --->Sabit Degiskenler

    def Ismi(self, val=None):
        if val == None:
            return self.catNesne.Name
        else:
            self.catNesne.Name = val

    def Analiz(self):
        pass

    @property
    def tanimlama(self):
        return self.catNesne.Definition

    @tanimlama.setter
    def tanimlama(self, value: str):
        self.catNesne.Definition = value

    @property
    def bilesenAciklamasi(self) -> str:
        return self.catNesne.DescriptionInst

    @bilesenAciklamasi.setter
    def bilesenAciklamasi(self, value: str):
        self.catNesne.DescriptionInst = value

    @property
    def referansAciklamasi(self) -> str:
        return self.catNesne.DescriptionRef

    @referansAciklamasi.setter
    def referansAciklamasi(self, value: str):
        self.catNesne.DescriptionRef = value

    @property
    def hareket(self) -> IHareket:
        return IHareket(obj=self.catNesne, sahip=self)

    @property
    def yayginIsmi(self) -> str:
        return self.catNesne.Nomenclature

    @yayginIsmi.setter
    def yayginIsmi(self, value: str):
        self.catNesne.Nomenclature = value

    @property
    def parametreler(self):
        return IParametreler(self.catNesne.Parameters, self)

    @property
    def parcaNumarasi(self) -> str:
        return self.catNesne.PartNumber

    @parcaNumarasi.setter
    def parcaNumarasi(self, value: str):
        self.catNesne.PartNumber = value

    @property
    def pozisyon(self):
        EvalCode = """
			Dim dirc(11)
			Product.Position.GetComponents dirc
			return = dirc
		"""
        rslt = self.anaProgram.eval(EvalCode, "Product", [self.catNesne])
        # --->
        return XYZO(X=[rslt[0], rslt[1], rslt[2]], Y=[rslt[3], rslt[4], rslt[5]],
                    Z=[rslt[6], rslt[7], rslt[8]], O=[rslt[9], rslt[10], rslt[11]])

    @pozisyon.setter
    def pozisyon(self, value):
        if not isinstance(value, XYZO):
            EvalCode = """
				Product.Position.SetComponents val
			"""
            rslt = self.anaProgram.eval(EvalCode, "Product, val", [self.catNesne, value])
        else:
            TEMPVAL = XYZO(X=[rslt[0], rslt[1], rslt[2]], Y=[rslt[3], rslt[4], rslt[5]],
                           Z=[rslt[6], rslt[7], rslt[8]], O=[rslt[9], rslt[10], rslt[11]])
            EvalCode = """
				Product.Position.SetComponents val
			"""
            rslt = self.anaProgram.eval(EvalCode, "Product, val", [self.catNesne, TEMPVAL])

    @property
    def productlar(self):
        return IProductlar(self.catNesne.Products, self)

    @property
    def paylasilanlar(self) -> IPaylasilanlar:
        return IPaylasilanlar(self.catNesne.Publications, self)

    @property
    def referansProduct(self):
        return IProduct(self.catNesne.ReferenceProduct, self)

    @property
    def kodlar(self):
        pass

    @property
    def revizyonNo(self) -> str:
        return self.catNesne.Revision

    @revizyonNo.setter
    def revizyonNo(self, value: str):
        self.catNesne.Revision = val

    @property
    def tedarikYontemi(self) -> FikoTedarikYontemi:
        return FikoTedarikYontemi(self.catNesne.Source).value

    @tedarikYontemi.setter
    def tedarikYontemi(self, value: FikoTedarikYontemi):
        self.catNesne.Source = value.value

    @property
    def kullaniciParametreleri(self):
        return IParametreler(self.catNesne.UserRefProperties, self)

    def GecerliModeliAktifEt(self):
        self.catNesne.ActivateDefaultShape()

    def ModeliAktifEt(self, ModelIsmi):
        self.catNesne.ActivateShape(ModelIsmi)

    def AnaModelEkle(self, AnaModelDosyaYolu):
        self.catNesne.AddMasterShapeRepresentation(AnaModelDosyaYolu)

    def ModelEkle(self, ModelDosyaYolu, iShapeName, iRepBehavior, iContext):
        self.catNesne.AddShapeRepresentation(ModelDosyaYolu, iShapeName, iRepBehavior, iContext)

    def isModuUygula(self, Mod: FikoIsModu):
        self.catNesne.ApplyWorkMode(Mod)

    @property
    def baglantilar(self):
        pass

    def isimdenReferansYarat(self, val):
        return IReferans(self.catNesne.CreateReferenceFromName(val), self)

    def gecerliModeliDeaktifEt(self):
        self.catNesne.DesactivateDefaultShape()

    def desactivateShape(self, ModelIsmi):
        self.catNesne.DesactivateShape(ModelIsmi)

    def malzemeListesiniCikar(self, ciktiTuru: FikoCiktiTuru, dosya: str):
        self.catNesne.ExtractBOM(ciktiTuru, dosya)

    @property
    def aktifModelIsmi(self):
        return self.catNesne.GetActiveShapeName()

    @property
    def tumModelIsimleri(self) -> list:
        EvalCode = """
			Dim dirc()
			Product.GetAllShapesNames dirc
			return = dirc
		"""
        rslt = self.anaProgram.eval(EvalCode, "Product", [self.catNesne])
        return rslt

    @property
    def gecerliModelIsmi(self):
        return self.catNesne.GetDefaultShapeName()

    @property
    def anaModelYolu(self):
        return self.catNesne.GetMasterShapeRepresentationPathName()

    @property
    def anaModel(self, iLoadIfNecessary):
        return self.catNesne.GetMasterShapeRepresentation(iLoadIfNecessary)

    @property
    def modelSayisi(self):
        return self.catNesne.GetNumberOfShapes()

    @property
    def modelYolu(self, iShapeName: str):
        return self.catNesne.GetShapePathName(iShapeName)

    @property
    def model(self, iLoadIfNecessary, iShapeName, iRepBehavior, iContext):
        return self.catNesne.GetShapeRepresentation(iLoadIfNecessary, iShapeName, iRepBehavior, iContext)

    @property
    def teknolojikObje(self, iApplicationType):  # str
        return self.GetTechnologicalObject(iApplicationType)

    @property
    def anaModelVarmi(self):
        return self.catNesne.HasAMasterShapeRepresentation()

    def modelVarmi(self, iShapeName, iRepBehavior, iContext):
        return self.catNesne.HasRepresentation(iShapeName, iRepBehavior, iContext)

    def anaModeliSil(self):
        self.catNesne.RemoveMasterShapeRepresentation()

    def modelSil(self, iShapeName, iRepBehavior, iContext):
        return self.catNesne.RemoveShapeRepresentation(iShapeName, iRepBehavior, iContext)

    def guncelle(self):
        self.catNesne.Update()

    @property
    def productMi(self):
        if self.productlar.sayisi > 0:
            return True
        else:
            return False

    @property
    def partMi(self) -> bool:
        if not self.productlar.sayisi > 0:
            return True
        else:
            return False

    @property
    def dokuman(self):
        Dkmn = IDokuman.IDokuman(self.catNesne.ReferenceProduct.Parent, self.anaProgram.dokumanlar)
        return Dkmn

    @property
    def toJson(self):
        sayac = { }

        def UstNumokratorDict(Product: IProduct):
            rslt = { }

            tmprPrdct = Product.productlar
            for x in range(tmprPrdct.sayisi):
                itm = tmprPrdct.item(x)
                if itm.productMi:
                    rslt[str(itm.Ismi())] = UstNumokratorDict(itm)
                else:
                    rslt[str(itm.ismi)] = { }

                if str(itm.parcaNumarasi) in sayac:
                    sayac[str(itm.parcaNumarasi)]["Sayisi"] = int(sayac[str(itm.parcaNumarasi)]["Sayisi"]) + 1
                else:
                    sayac[str(itm.parcaNumarasi)] = { }
                    sayac[str(itm.parcaNumarasi)]["Sayisi"] = 1
                    sayac[str(itm.parcaNumarasi)]["Tedarik Yontemi"] = str(FikoTedarikYontemi(itm.tedarikYontemi))
                    if itm.partMi:
                        sayac[str(itm.parcaNumarasi)]["Turu"] = "Part"
                    else:
                        sayac[str(itm.parcaNumarasi)]["Turu"] = "Product"
            return rslt

        sayac = { }
        tempDict = UstNumokratorDict(self)
        return { "Liste": tempDict, "Parcalar": sayac }

    @property
    def altObjeler(self):
        sayac = { }
        objeList = []

        def UstNumokratorObje(Product: IProduct):
            rslt = { }
            tmprPrdct = Product.productlar
            for x in range(tmprPrdct.sayisi):
                itm = tmprPrdct.item(x)
                if itm.productMi:
                    rslt[str(itm.ismi)] = UstNumokratorObje(itm)
                else:
                    rslt[str(itm.ismi)] = { }

                if str(itm.parcaNumarasi) in sayac:
                    sayac[str(itm.parcaNumarasi)]["Sayisi"] = int(sayac[str(itm.parcaNumarasi)]["Sayisi"]) + 1
                else:
                    sayac[str(itm.parcaNumarasi)] = { }
                    sayac[str(itm.parcaNumarasi)]["Sayisi"] = 1
                    objeList.append(itm)
            return objeList

        objeList = []
        rslt = UstNumokratorObje(self)
        return rslt, objeList, sayac

    @property
    def urunAgaci(self):
        def UstNumokratorObje(Product):
            rslt = { }
            tmprPrdct = Product.productlar
            for x in range(tmprPrdct.sayisi):
                itm = tmprPrdct.item(x)
                if itm.productMi:
                    rslt[str(itm.parcaNumarasi + "(" + itm.ismi + ")")] = UstNumokratorObje(itm)
                else:
                    rslt[str(itm.parcaNumarasi + "(" + itm.ismi + ")")] = { }
            return rslt

        # --->
        rslt = UstNumokratorObje(self)
        return rslt

    @property
    def urunAgaci(self):
        def UstNumokratorObje(Product):
            rslt = { }
            tmprPrdct = Product.productlar
            for x in range(tmprPrdct.sayisi):
                itm = tmprPrdct.item(x)
                if itm.productMi:
                    rslt[str(itm.parcaNumarasi + "(" + itm.ismi + ")")] = UstNumokratorObje(itm)
                else:
                    rslt[str(itm.parcaNumarasi + "(" + itm.ismi + ")")] = { }
            return rslt

        # --->
        rslt = UstNumokratorObje(self)
        return rslt

    def resimCek(self, Kamera=None, Klasor=None, DosyaIsmi=None):
        Doc = self.dokuman
        if Klasor == None:
            Klasor = Doc.klasoru + "\\"
        if Kamera == None:
            Kamera = 0
        if DosyaIsmi == None:
            DosyaIsmi = self.parcaNumarasi + ".jpg"

        # --->
        Doc.ac()
        Gosterim = Doc.gosterim
        # --->
        if Doc.kameralar.sayisi < 1:
            Gosterim.ekranaSigdir()
        else:
            Cam = Doc.kameralar.item(Kamera)
            Cam.goster()
        # --->

        print(Gosterim.resimDosyaya(path.join(Klasor,DosyaIsmi)))
        # Doc.kapat()
        return Klasor + DosyaIsmi

    def numokratorHazirla(self):
        Objeler, Liste, Sayilar = self.altObjeler
        AnaPrg = self.anaProgram
        __gen = AnaPrg.genislik
        __yuk = AnaPrg.yukseklik
        try:
            AnaPrg.genislik = 800
            AnaPrg.yukseklik = 600
            AnaPrg.hsoSenkronize = False
            AnaPrg.ekraniTazele = False
            # AnaPrg.gorunur=False
            for x in range(0, len(Objeler)):
                print(x)
                if Objeler[x].partMi:
                    if Objeler[x].dokuman.tamIsmi != self.dokuman.tamIsmi:
                        # print(Sayilar[Objeler[x].parcaNumarasi]["Sayisi"])
                        desktop = path.join(path.join(os.environ['USERPROFILE']), 'Desktop') 
                        os.makedirs(desktop, exist_ok=True)
                        Objeler[x].resimCek(Klasor=path.join(desktop, self.parcaNumarasi), DosyaIsmi=str(Objeler[x].parcaNumarasi)+".jpg")
                        Objeler[x].dokuman.kapat()

                        # sleep(2)
            # AnaPrg.gorunur=(True)
            AnaPrg.hsoSenkronize = (True)
            AnaPrg.ekraniTazele = (True)
            AnaPrg.genislik = __gen
            AnaPrg.yukseklik = __yuk

            with open(path.join(path.join(desktop, self.parcaNumarasi),"__fiko__.json"), 'w') as file:
                file.write(json.dumps(self.toJson["Parcalar"]))
            
            with ZipFile(path.join(desktop, self.parcaNumarasi+".FikoProjeX"), 'w') as zipObj:
                # Iterate over all the files in directory
                for folderName, subfolders, filenames in os.walk(path.join(desktop, self.parcaNumarasi)):
                    for filename in filenames:
                        #create complete filepath of file in directory
                        filePath = os.path.join(folderName, filename)
                        # Add file to zip
                        zipObj.write(filePath, basename(filePath))

            shutil.rmtree(path.join(desktop, self.parcaNumarasi), ignore_errors=True)
            
        except:
            # AnaPrg.gorunur=(True)
            AnaPrg.hsoSenkronize = (True)
            AnaPrg.ekraniTazele = (True)
            AnaPrg.genislik = __gen
            AnaPrg.yukseklik = __yuk

    # @property
    # def fikoNumokrator(self):
    #     Finum = IFikoNumokrator.IFikoNumokrator.IFikoNumokrator(obj=self, sahip=self)
    #     return Finum

    @property
    def toplamParcaSayisi(self):
        def UstNumokratorObje(Product: IProduct):
            rslt = 0
            tmprPrdct = Product.productlar
            for x in range(tmprPrdct.sayisi):
                itm = tmprPrdct.item(x)
                if itm.productMi:
                    rslt += UstNumokratorObje(itm)
                else:
                    rslt += 1

            return rslt

        rslt = UstNumokratorObje(self)
        return rslt

    @property
    def farkliParcaSayisi(self):
        sayac = { }
        obj = []

        def UstNumokratorObje(Product: IProduct):
            rslt = 0
            tmprPrdct = Product.productlar
            for x in range(tmprPrdct.sayisi):
                itm = tmprPrdct.item(x)
                if itm.productMi:
                    rslt += UstNumokratorObje(itm)
                else:
                    rslt += 1
                    try:
                        if itm.referansProduct.parcaNumarasi in sayac:
                            sayac[itm.referansProduct.parcaNumarasi] += 1
                        else:
                            sayac[itm.referansProduct.parcaNumarasi] = 1
                            obj.append(itm)
                    except:
                        pass
            return rslt

        rslt = UstNumokratorObje(self)
        return len(sayac)

    def partaCevir(self, partIsmi: str = None):
        rslt = self.catNesne.getitem("DECProductToPart")
        rslt.run()
        dnnObj = IDokuman.IPartDokuman(obj=rslt.GetResult(), sahip=self.anaProgram.dokumanlar)
        if partIsmi:
            dnnObj.asPartDokuman.product.referansProduct.parcaNumarasi = "FikoYT_" + partIsmi + "_Hepsi(" + str(
                    random.random()) + ")"
        return dnnObj

    def __str__(self):
        try:
            return repr(self.parcaNumarasi)
        except:
            return ""


import IDokuman
