"""
DeepLabCut2.0 Toolbox (deeplabcut.org)
© A. & M. Mathis Labs
https://github.com/AlexEMG/DeepLabCut
Please see AUTHORS for contributors.

https://github.com/AlexEMG/DeepLabCut/blob/master/AUTHORS
Licensed under GNU Lesser General Public License v3.0

"""

import os
import platform
import pydoc
import subprocess
import sys
import webbrowser

import wx

import deeplabcut
from deeplabcut.utils import auxiliaryfunctions

media_path = os.path.join(deeplabcut.__path__[0], "gui", "media")
logo = os.path.join(media_path, "logo.png")


class Analyze_videos(wx.Panel):
    """
    """

    def __init__(self, parent, gui_size, cfg):
        """Constructor"""
        wx.Panel.__init__(self, parent=parent)
        # variable initilization
        self.filelist = []
        self.picklelist = []
        self.bodyparts = []
        self.config = cfg
        self.cfg = auxiliaryfunctions.read_config(self.config)
        self.draw = False
        # design the panel
        self.sizer = wx.GridBagSizer(5, 10)

        if self.cfg.get("multianimalproject", False):
            text = wx.StaticText(
                self, label="DeepLabCut - Step 7. Analyze Videos and Detect Tracklets"
            )
        else:
            text = wx.StaticText(self, label="DeepLabCut - Step 7. Analyze Videos ....")

        self.sizer.Add(text, pos=(0, 0), flag=wx.TOP | wx.LEFT | wx.BOTTOM, border=15)
        # Add logo of DLC
        icon = wx.StaticBitmap(self, bitmap=wx.Bitmap(logo))
        self.sizer.Add(
            icon, pos=(0, 8), flag=wx.TOP | wx.RIGHT | wx.ALIGN_RIGHT, border=5
        )

        line1 = wx.StaticLine(self)
        self.sizer.Add(
            line1, pos=(1, 0), span=(1, 8), flag=wx.EXPAND | wx.BOTTOM, border=10
        )

        self.cfg_text = wx.StaticText(self, label="Select the config file")
        self.sizer.Add(self.cfg_text, pos=(2, 0), flag=wx.TOP | wx.LEFT, border=10)

        if sys.platform == "darwin":
            self.sel_config = wx.FilePickerCtrl(
                self,
                path="",
                style=wx.FLP_USE_TEXTCTRL,
                message="Choose the config.yaml file",
                wildcard="*.yaml",
            )
        else:
            self.sel_config = wx.FilePickerCtrl(
                self,
                path="",
                style=wx.FLP_USE_TEXTCTRL,
                message="Choose the config.yaml file",
                wildcard="config.yaml",
            )

        self.sizer.Add(
            self.sel_config, pos=(2, 1), span=(1, 3), flag=wx.TOP | wx.EXPAND, border=5
        )
        self.sel_config.SetPath(self.config)
        self.sel_config.Bind(wx.EVT_FILEPICKER_CHANGED, self.select_config)

        self.vids = wx.StaticText(self, label="Choose the videos")
        self.sizer.Add(self.vids, pos=(3, 0), flag=wx.TOP | wx.LEFT, border=10)

        self.sel_vids = wx.Button(self, label="Select videos to analyze")
        self.sizer.Add(self.sel_vids, pos=(3, 1), flag=wx.TOP | wx.EXPAND, border=5)
        self.sel_vids.Bind(wx.EVT_BUTTON, self.select_videos)

        sb = wx.StaticBox(self, label="Attributes")
        boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)

        self.hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox3 = wx.BoxSizer(wx.HORIZONTAL)
        self.hbox4 = wx.BoxSizer(wx.HORIZONTAL)

        videotype_text = wx.StaticBox(self, label="Specify the videotype")
        videotype_text_boxsizer = wx.StaticBoxSizer(videotype_text, wx.VERTICAL)
        videotypes = [".avi", ".mp4", ".mov"]
        self.videotype = wx.ComboBox(self, choices=videotypes, style=wx.CB_READONLY)
        self.videotype.SetValue(".avi")
        videotype_text_boxsizer.Add(
            self.videotype, 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 5
        )

        shuffle_text = wx.StaticBox(self, label="Specify the shuffle")
        shuffle_boxsizer = wx.StaticBoxSizer(shuffle_text, wx.VERTICAL)
        self.shuffle = wx.SpinCtrl(self, value="1", min=0, max=100)
        shuffle_boxsizer.Add(self.shuffle, 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

        trainingset = wx.StaticBox(self, label="Specify the trainingset index")
        trainingset_boxsizer = wx.StaticBoxSizer(trainingset, wx.VERTICAL)
        self.trainingset = wx.SpinCtrl(self, value="0", min=0, max=100)
        trainingset_boxsizer.Add(self.trainingset, 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

        # if self.cfg.get("multianimalproject", False):
        # pass
        # else:
        # removing this as several downstream maDLC steps don't support dest_folder at this time:
        # destfolder_text = wx.StaticBox(self, label="Specify destination folder")
        # destfolderboxsizer = wx.StaticBoxSizer(destfolder_text, wx.VERTICAL)
        # self.change_workingdir = wx.CheckBox(
        #    self, label="optional destination folder"
        # )
        # self.hbox2.Add(self.change_workingdir)
        # self.change_workingdir.Bind(wx.EVT_CHECKBOX, self.activate_change_wd)
        # self.sel_wd = wx.Button(self, label="Browse")
        # self.sel_wd.Enable(False)
        # self.sel_wd.Bind(wx.EVT_BUTTON, self.select_destfolder)
        # self.hbox2.Add(self.sel_wd, 0, wx.ALL, -1)

        self.hbox1.Add(videotype_text_boxsizer, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
        self.hbox1.Add(shuffle_boxsizer, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
        self.hbox1.Add(trainingset_boxsizer, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

        boxsizer.Add(self.hbox1, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 10)
        boxsizer.Add(self.hbox2, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 10)

        # self.sizer.Add(boxsizer, pos=(4, 0), span=(1, 5),flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT , border=10)

        if self.cfg.get("multianimalproject", False):

            self.robust = wx.RadioBox(
                self,
                label="Use ffprobe to read video metadata (slow but robust)",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )
            self.robust.SetSelection(1)
            self.hbox1.Add(self.robust, 5, 5)
            # boxsizer.Add(self.hbox1,0, 5)

            self.create_video_with_all_detections = wx.RadioBox(
                self,
                label="Create video for checking detections",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )
            self.create_video_with_all_detections.SetSelection(1)
            self.hbox2.Add(
                self.create_video_with_all_detections,
                5,
                wx.EXPAND | wx.TOP | wx.BOTTOM,
                5,
            )

            tracker_text = wx.StaticBox(
                self, label="Specify the Tracker Method (you can try each)"
            )
            tracker_text_boxsizer = wx.StaticBoxSizer(tracker_text, wx.VERTICAL)
            trackertypes = ["skeleton", "box"]
            self.trackertypes = wx.ComboBox(
                self, choices=trackertypes, style=wx.CB_READONLY
            )
            self.trackertypes.SetValue("box")
            tracker_text_boxsizer.Add(
                self.trackertypes, 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 10
            )
            self.hbox2.Add(tracker_text_boxsizer, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

            self.overwrite = wx.RadioBox(
                self,
                label="Overwrite tracking files (set to yes if you edit inference parameters)",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )
            self.overwrite.SetSelection(1)
            self.hbox2.Add(self.overwrite, 5, 5)
            boxsizer.Add(self.hbox2, 0, 5)

        else:
            self.csv = wx.RadioBox(
                self,
                label="Want to save result(s) as csv?",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )
            self.csv.SetSelection(1)

            self.dynamic = wx.RadioBox(
                self,
                label="Want to dynamically crop bodyparts?",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )
            self.dynamic.SetSelection(1)

            self.filter = wx.RadioBox(
                self,
                label="Want to filter the predictions?",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )
            self.filter.SetSelection(1)

            self.trajectory = wx.RadioBox(
                self,
                label="Want to plot the trajectories?",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )

            self.showfigs = wx.RadioBox(
                self,
                label="Want plots to pop up?",
                choices=["Yes", "No"],
                majorDimension=1,
                style=wx.RA_SPECIFY_COLS,
            )

            self.trajectory.Bind(wx.EVT_RADIOBOX, self.chooseOption)
            self.trajectory.SetSelection(1)

            self.hbox2.Add(self.csv, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
            self.hbox2.Add(self.filter, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
            self.hbox2.Add(self.showfigs, 5, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

            self.hbox3.Add(self.dynamic, 10, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
            self.hbox3.Add(self.trajectory, 10, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

        config_file = auxiliaryfunctions.read_config(self.config)
        if config_file.get("multianimalproject", False):
            bodyparts = config_file["multianimalbodyparts"]
        else:
            bodyparts = config_file["bodyparts"]
        self.trajectory_to_plot = wx.CheckListBox(
            self, choices=bodyparts, style=0, name="Select the bodyparts"
        )
        self.trajectory_to_plot.Bind(wx.EVT_CHECKLISTBOX, self.getbp)
        self.trajectory_to_plot.SetCheckedItems(range(len(bodyparts)))
        self.trajectory_to_plot.Hide()

        self.draw_skeleton = wx.RadioBox(
            self,
            label="Include the skeleton in the video?",
            choices=["Yes", "No"],
            majorDimension=1,
            style=wx.RA_SPECIFY_COLS,
        )
        self.draw_skeleton.Bind(wx.EVT_RADIOBOX, self.choose_draw_skeleton_options)
        self.draw_skeleton.SetSelection(1)
        self.draw_skeleton.Hide()

        self.trail_points_text = wx.StaticBox(
            self, label="Specify the number of trail points"
        )
        trail_pointsboxsizer = wx.StaticBoxSizer(self.trail_points_text, wx.VERTICAL)
        self.trail_points = wx.SpinCtrl(self, value="1")
        trail_pointsboxsizer.Add(
            self.trail_points, 10, wx.EXPAND | wx.TOP | wx.BOTTOM, 10
        )
        self.trail_points_text.Hide()
        self.trail_points.Hide()

        self.hbox3.Add(self.trajectory_to_plot, 10, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
        boxsizer.Add(self.hbox3, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 10)

        self.hbox4.Add(self.draw_skeleton, 10, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
        self.hbox4.Add(trail_pointsboxsizer, 10, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
        boxsizer.Add(self.hbox4, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 10)
        self.sizer.Add(
            boxsizer,
            pos=(5, 0),
            span=(1, 10),
            flag=wx.EXPAND | wx.TOP | wx.LEFT | wx.RIGHT,
            border=10,
        )

        self.help_button = wx.Button(self, label="Help")
        self.sizer.Add(self.help_button, pos=(7, 0), flag=wx.LEFT, border=10)
        self.help_button.Bind(wx.EVT_BUTTON, self.help_function)

        self.ok = wx.Button(self, label="Step 1: Analyze Videos")
        self.sizer.Add(self.ok, pos=(7, 6), flag=wx.BOTTOM | wx.RIGHT, border=10)
        self.ok.Bind(wx.EVT_BUTTON, self.analyze_videos)

        if config_file.get("multianimalproject", False):
            self.ok = wx.Button(self, label="Step 2: Convert to Tracklets")
            self.sizer.Add(self.ok, pos=(7, 7), border=10)
            self.ok.Bind(wx.EVT_BUTTON, self.convert2_tracklets)

            self.inf_cfg_text = wx.Button(self, label="Edit inference_config.yaml")
            self.sizer.Add(self.inf_cfg_text, pos=(8, 7), border=10)
            self.inf_cfg_text.Bind(wx.EVT_BUTTON, self.edit_inf_config)

        self.reset = wx.Button(self, label="Reset")
        self.sizer.Add(
            self.reset, pos=(7, 1), span=(1, 1), flag=wx.BOTTOM | wx.RIGHT, border=10
        )
        self.reset.Bind(wx.EVT_BUTTON, self.reset_analyze_videos)

        self.edit_config_file = wx.Button(self, label="Edit config.yaml")
        self.sizer.Add(self.edit_config_file, pos=(8, 6))
        self.edit_config_file.Bind(wx.EVT_BUTTON, self.edit_config)

        self.sizer.AddGrowableCol(2)

        self.SetSizer(self.sizer)
        self.sizer.Fit(self)

    def edit_config(self, event):
        """
        """
        if platform.system() == "Darwin":
            self.file_open_bool = subprocess.call(["open", self.config])
            self.file_open_bool = True
        else:
            self.file_open_bool = webbrowser.open(self.config)
        if self.file_open_bool:
            self.pose_cfg = auxiliaryfunctions.read_config(self.config)
        else:
            raise FileNotFoundError("File not found!")

    def edit_inf_config(self, event):
        # Read the infer config file
        cfg = auxiliaryfunctions.read_config(self.config)
        trainingsetindex = self.trainingset.GetValue()
        trainFraction = cfg["TrainingFraction"][trainingsetindex]
        self.inf_cfg_path = os.path.join(
            cfg["project_path"],
            auxiliaryfunctions.GetModelFolder(
                trainFraction, self.shuffle.GetValue(), cfg
            ),
            "test",
            "inference_cfg.yaml",
        )
        # let the user open the file with default text editor. Also make it mac compatible
        if sys.platform == "darwin":
            self.file_open_bool = subprocess.call(["open", self.inf_cfg_path])
            self.file_open_bool = True
        else:
            self.file_open_bool = webbrowser.open(self.inf_cfg_path)
        if self.file_open_bool:
            self.inf_cfg = auxiliaryfunctions.read_config(self.inf_cfg_path)
        else:
            raise FileNotFoundError("File not found!")

    def activate_change_wd(self, event):
        """
        Activates the option to change the working directory
        """
        self.change_wd = event.GetEventObject()
        if self.change_wd.GetValue() == True:
            self.sel_wd.Enable(True)
        else:
            self.sel_wd.Enable(False)

    def help_function(self, event):

        filepath = "help.txt"
        f = open(filepath, "w")
        sys.stdout = f
        fnc_name = "deeplabcut.analyze_videos"
        pydoc.help(fnc_name)
        f.close()
        sys.stdout = sys.__stdout__
        help_file = open("help.txt", "r+")
        help_text = help_file.read()
        wx.MessageBox(help_text, "Help", wx.OK | wx.ICON_INFORMATION)
        os.remove("help.txt")

    def select_config(self, event):
        """
        """
        self.config = self.sel_config.GetPath()

    def convert2_tracklets(self, event):
        shuffle = self.shuffle.GetValue()
        trainingsetindex = self.trainingset.GetValue()
        if self.overwrite.GetStringSelection() == "Yes":
            overwrite = True
        else:
            overwrite = False
        deeplabcut.convert_detections2tracklets(
            self.config,
            self.filelist,
            videotype=self.videotype.GetValue(),
            shuffle=shuffle,
            trainingsetindex=trainingsetindex,
            edgewisecondition=True,
            overwrite=overwrite,
            track_method=self.trackertypes.GetValue(),
        )

    # def video_tracklets(self,event):
    #    shuffle = self.shuffle.GetValue()
    #    trainingsetindex = self.trainingset.GetValue()
    #    deeplabcut.create_video_from_pickled_tracks(self.filelist, picklefile, pcutoff=0.6)

    def select_videos(self, event):
        """
        Selects the videos from the directory
        """
        cwd = os.getcwd()
        dlg = wx.FileDialog(
            self, "Select videos to analyze", cwd, "", "*.*", wx.FD_MULTIPLE
        )
        if dlg.ShowModal() == wx.ID_OK:
            self.vids = dlg.GetPaths()
            self.filelist = self.filelist + self.vids
            self.sel_vids.SetLabel("Total %s Videos selected" % len(self.filelist))

    def choose_draw_skeleton_options(self, event):
        if self.draw_skeleton.GetStringSelection() == "Yes":
            self.draw = True
        else:
            self.draw = False

    def analyze_videos(self, event):

        shuffle = self.shuffle.GetValue()
        trainingsetindex = self.trainingset.GetValue()

        if self.cfg.get("multianimalproject", False):
            print("Analyzing ... ")
        else:
            if self.csv.GetStringSelection() == "Yes":
                save_as_csv = True
            else:
                save_as_csv = False
            if self.dynamic.GetStringSelection() == "No":
                dynamic = (False, 0.5, 10)
            else:
                dynamic = (True, 0.5, 10)
            if self.filter.GetStringSelection() == "No":
                filter = None
            else:
                filter = True

        if self.cfg["cropping"] == "True":
            crop = self.cfg["x1"], self.cfg["x2"], self.cfg["y1"], self.cfg["y2"]
        else:
            crop = None

        if self.cfg.get("multianimalproject", False):
            if self.robust.GetStringSelection() == "No":
                robust = False
            else:
                robust = True
            scorername = deeplabcut.analyze_videos(
                self.config,
                self.filelist,
                videotype=self.videotype.GetValue(),
                shuffle=shuffle,
                trainingsetindex=trainingsetindex,
                gputouse=None,
                cropping=crop,
                robust_nframes=robust,
            )
            if self.create_video_with_all_detections.GetStringSelection() == "Yes":
                trainFrac = self.cfg["TrainingFraction"][trainingsetindex]
                scorername, DLCscorerlegacy = auxiliaryfunctions.GetScorerName(
                    self.cfg, shuffle, trainFraction=trainFrac
                )
                print(scorername)
                deeplabcut.create_video_with_all_detections(
                    self.config, self.filelist, DLCscorername=scorername
                )

        else:
            scorername = deeplabcut.analyze_videos(
                self.config,
                self.filelist,
                videotype=self.videotype.GetValue(),
                shuffle=shuffle,
                trainingsetindex=trainingsetindex,
                gputouse=None,
                save_as_csv=save_as_csv,
                cropping=crop,
                dynamic=dynamic,
            )
            if self.filter.GetStringSelection() == "Yes":
                deeplabcut.filterpredictions(
                    self.config,
                    self.filelist,
                    videotype=self.videotype.GetValue(),
                    shuffle=shuffle,
                    trainingsetindex=trainingsetindex,
                    filtertype="median",
                    windowlength=5,
                    save_as_csv=True,
                )

            if self.trajectory.GetStringSelection() == "Yes":
                if self.showfigs.GetStringSelection() == "No":
                    showfig = False
                else:
                    showfig = True
                deeplabcut.plot_trajectories(
                    self.config,
                    self.filelist,
                    displayedbodyparts=self.bodyparts,
                    videotype=self.videotype.GetValue(),
                    shuffle=shuffle,
                    trainingsetindex=trainingsetindex,
                    filtered=True,
                    showfigures=showfig,
                )

    def reset_analyze_videos(self, event):
        """
        Reset to default
        """
        if self.cfg.get("multianimalproject", False):
            self.create_video_with_all_detections.SetSelection(1)
        else:
            self.csv.SetSelection(1)
            self.filter.SetSelection(1)
            self.trajectory.SetSelection(1)
            self.dynamic.SetSelection(1)
            # self.select_destfolder.SetPath("None")
        self.config = []
        self.sel_config.SetPath("")
        self.videotype.SetStringSelection(".avi")
        self.sel_vids.SetLabel("Select videos to analyze")
        self.filelist = []
        self.shuffle.SetValue(1)
        self.trainingset.SetValue(0)
        if self.draw_skeleton.IsShown():
            self.draw_skeleton.SetSelection(1)
            self.draw_skeleton.Hide()
            self.trail_points_text.Hide()
            self.trail_points.Hide()
            self.SetSizer(self.sizer)
            self.sizer.Fit(self)

    def chooseOption(self, event):
        if self.trajectory.GetStringSelection() == "Yes":
            self.trajectory_to_plot.Show()
            self.getbp(event)
        if self.trajectory.GetStringSelection() == "No":
            self.trajectory_to_plot.Hide()
            self.bodyparts = []
        self.SetSizer(self.sizer)
        self.sizer.Fit(self)

    def getbp(self, event):
        self.bodyparts = list(self.trajectory_to_plot.GetCheckedStrings())