import wx
import os
os.environ["OPENCV_IO_ENABLE_OPENEXR"]="1"
import shutil
from modules.gui.scene_load.panel_menu_caption import PanelMenuCaption
from modules.gui.scene_load.panel_scene_select import PanelSceneSelect
from modules.gui.dialog_new_scene import DialogNewScene
from modules.gui.dialog_confirm_overwrite import DialogConfirmOverwrite
from modules.scene.scene import Scene
import wx.lib.agw.flatmenu as FM
import wx.aui as aui
from modules.gui.panel_button import Button
from modules.gui.frame_main import FrameMainExtended
from modules.viewport.splat_showbase import SplatShowbase
from modules.gui.dialog_server_setup import DialogServerSetup

from pathlib import Path
from multiprocessing import Process, Queue

class DataProcessingThread():
  def __init__(self, dir, name, result_queue) -> None:
    super().__init__()
    self.dir = dir
    self.name = name
    self.result_queue = result_queue
    self.process = None

  def run_processing(self) -> None:
    self.process = Process(target=process_data, args=(self.name, self.dir, self.result_queue))
    self.process.start()

  def stop(self) -> None:
    if self.process is not None:
      self.process.terminate()
      self.process.join()
      self.process = None
  
  def is_running(self) -> bool:
    return self.process is not None

def process_data(scene_name, scene_dir, result_queue):
    to_create = Scene()
    scene_path = to_create.instantiate_scene_with_arkit(scene_name, scene_dir, result_queue)
    result_queue.put(scene_path)
    result_queue.put(None)


class FrameLoad(wx.Frame):
  def __init__(self, parent, id = wx.ID_ANY, size=wx.Size(1000, 800)):
    super().__init__(parent, id=id, size=size, style = wx.DEFAULT_FRAME_STYLE)
    self.SetDoubleBuffered(True)
    self.background =  wx.Colour(33, 33, 33)
    self.SetBackgroundColour(self.background)
    self.m_mgr = aui.AuiManager(self)
    self.panel_top_bar = PanelMenuCaption(self)
    self.panel_scene_list = PanelSceneSelect(self, self.background)
    self.set_buttons()
    self.set_menubar()
    self.m_mgr.AddPane(self.panel_top_bar, aui.AuiPaneInfo().Top().CloseButton(False).BestSize(wx.Size(1000,60)).CaptionVisible(False).PaneBorder(False).Fixed())
    self.m_mgr.AddPane(self.panel_buttons, aui.AuiPaneInfo().Left().CloseButton(False).CaptionVisible(False).PaneBorder(False).BestSize(wx.Size(200, -1)).Fixed())
    self.m_mgr.AddPane(self.panel_scene_list, aui.AuiPaneInfo().CenterPane().CloseButton(False).CaptionVisible(False).PaneBorder(False).Fixed())

    
    self.m_mgr.Update()
    self.Center()
    self.button_open_scene.Bind(wx.EVT_LEFT_UP, self.on_open_scene)
    self.button_new_scene.Bind(wx.EVT_LEFT_UP, self.on_new_scene)
    self.Bind(wx.EVT_SIZE, self.on_size)
    self.Bind(wx.EVT_CLOSE, self.on_close)
    
  def on_close(self, event):
    self.panel_scene_list.on_close()
    event.Skip()

  def on_new_scene(self, event):
    dir_dialog = DialogNewScene(self)
    if dir_dialog.ShowModal() == wx.ID_OK:
      scene_name = dir_dialog.get_name()
      scene_dir = dir_dialog.get_scene_dir()
      
      if os.path.exists(scene_dir) and not os.path.exists(scene_dir + "/raw_images"):
        dia = DialogServerSetup(self, scene_dir)

        if dia.ShowModal() != wx.ID_OK:
          dia.Destroy()
          return
        dia.Destroy()

      processing_dialog = wx.ProgressDialog("Processing...", "Processing scene. Please wait...", maximum=100, parent=None, style=wx.PD_APP_MODAL|wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
      processing_dialog.Show()
      result_queue = Queue()
      self.data_thread = DataProcessingThread(scene_dir, scene_name, result_queue)
      self.data_thread.run_processing()

      while True:
        result = result_queue.get()
        if result is None:
          break
        prev_result = result
        if isinstance(prev_result, tuple):
          processing_dialog.Update(prev_result[0], prev_result[1])

      
      self.data_thread.stop()
      processing_dialog.Destroy()

      self.panel_scene_list.open_scene(str(prev_result))
      self.start_main(prev_result)

    dir_dialog.Destroy()

  def on_open_scene(self, event):
    open_dialog = wx.FileDialog(self, "Open Scene", "", "", "(*.qdb;)|*.qdb;", wx.FD_OPEN | wx.FD_FILE_MUST_EXIST)
    open_dialog_result = open_dialog.ShowModal()

    if open_dialog_result == wx.ID_CANCEL:
      return None
    
    if open_dialog_result == wx.ID_OK:
      self.panel_scene_list.open_scene(open_dialog.GetPath())

    self.start_main(open_dialog.GetPath())
    

  def start_main(self, path):
    import sys
    if sys.platform == 'win32':
      import ctypes
      ctypes.OleDLL('shcore').SetProcessDpiAwareness(1)
    self.Hide()
    frame = FrameMainExtended(None, True, path)
    viewport = SplatShowbase(frame.panel_viewport, wx.GetApp(), frame.scene.get_image_count())
    # frame.toggle_point = viewport.toggle_view
    # frame.insert_mesh = viewport.insert_mesh
    frame.get_export_data = viewport.get_export_data
    frame.unload_ert_viewport = viewport.unload
    frame.exit_panda = viewport.exit
    frame.load_recon_ert = viewport.load_recon
    frame.scale_model = viewport.scale_model
    frame.set_viewport_to_recon = viewport.recon_in_progress
    frame.update_loading_bar = viewport.update_loading_bar
    frame.export_model = viewport.export_ply
    frame.reset_cam = viewport.reset_cam
    # frame.toggle_measure_vieport = viewport.toggle_measure

    frame.Center()
    frame.load_recon()
    icon_path = "assets/Logos/Virtualize Icon.png"
    if getattr(sys, 'frozen', False):
      icon_path = "_internal/" + icon_path
    frame.SetIcon(wx.Icon(icon_path, wx.BITMAP_TYPE_ANY))
    frame.SetClientSize(frame.FromDIP(wx.Size(1280,720)))
    frame.Show()
    self.Close()
    app = wx.GetApp()
    app.ExitMainLoop()
 
    viewport.run()
   
  
  def on_size(self, event):
    size = self.GetSize()
    self.m_mgr.GetPane(self.panel_top_bar).BestSize(wx.Size(size[0],60))
    self.m_mgr.GetPane(self.panel_buttons).BestSize(wx.Size(200,size[1]))
    self.m_mgr.GetPane(self.panel_scene_list).BestSize(wx.Size(size[0],size[1]))
    self.m_mgr.Update()
    event.Skip()

  def set_buttons(self):
    self.panel_buttons = wx.Panel(self)
    self.buttons_sizer = wx.BoxSizer(wx.VERTICAL)
    button_font = wx.Font(12, wx.FONTFAMILY_SWISS, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, "Calibri" )
    
    self.button_open_scene = Button(parent = self.panel_buttons,
                                    label = "Open Scene",
                                    background= self.background,
                                    font = button_font,
                                    radius = 10,
                                    id = wx.ID_ANY,
                                    pos = wx.DefaultPosition,
                                    size = wx.Size(150,30),
                                    color=4,
                                    font_color=[0, 0, 0])
    self.button_new_scene = Button(parent = self.panel_buttons,
                                   label = "New Scene",
                                   background = self.background,
                                   font = button_font, 
                                   radius = 10, 
                                   id = wx.ID_ANY, 
                                   pos = wx.DefaultPosition, 
                                   size = wx.Size(150,30), 
                                   color=2, 
                                   font_color=[0, 0, 0])
    
    self.buttons_sizer.Add((0, 10), 0, wx.ALL, 5 )
    self.buttons_sizer.Add(self.button_open_scene, 0, wx.ALIGN_CENTER_HORIZONTAL, 5)
    self.buttons_sizer.Add((0, 2), 0, wx.EXPAND|wx.ALL, 5 )
    self.buttons_sizer.Add(self.button_new_scene, 0, wx.ALIGN_CENTER_HORIZONTAL, 5)
    self.buttons_sizer.Add((0, 0), 1, wx.EXPAND|wx.ALL, 5 )
    self.panel_buttons.SetSizer(self.buttons_sizer)

  def set_menubar(self):
    self.menubar = FM.FlatMenuBar(self, wx.ID_ANY)
    self.menubar.SetBackgroundColour(wx.Colour(116,116,116))
    self.menubar.ShowCustomize(False)

    self.file_menu = FM.FlatMenu(self)
    self.edit_menu = FM.FlatMenu(self)
    self.file_menu.SetForegroundColour(wx.Colour(255,255,255))
    self.menubar.Append(self.file_menu, "&File")
    self.menubar.Append(self.edit_menu, "&Edit")

    self.menubar.SetMargin(5)
    self.menubar.SetBarHeight()
    self.menubar.PositionAUI(self.m_mgr, True)