#!/usr/bin/env python3
# Qtvcp
#
# Copyright (c) 2017  Chris Morley <chrisinnanaimo@hotmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
###############################################################################

import os
import sys

from qtpy import QtCore

# Set up logging
from . import logger

LOG = logger.getLogger(__name__)


# Force the log level for this module
# LOG.setLevel(logger.DEBUG) # One of DEBUG, INFO, WARNING, ERROR, CRITICAL

# BASE is the absolute path to linuxcnc base
# LIBDIR is the path to qtvcp python files
# DATADIR is where the standard UI files are
# IMAGEDIR is for icons
class _PStat(object):
    def __init__(self):
        # only initialize once for all instances
        if self.__class__._instanceNum >= 1:
            return
        self.__class__._instanceNum += 1
        self.INI_PATH = None
        try:
            self.WORKINGDIR = os.getcwd()

            # widget directory
            here = os.path.dirname(os.path.realpath(__file__))
            self.LIBDIR = os.path.join(here,"lib")
            self.WIDGETDIR = os.path.join(here, "widgets")
            self.PLUGINDIR = os.path.join(here,"plugins")
            self.VISMACHDIR = os.path.join(self.LIBDIR, "qt_vismach")

            self.RIP_FLAG = bool(os.environ.get('LINUXCNC_RIP_FLAG', False))

            if self.RIP_FLAG:
                BASE = os.environ.get('EMC2_HOME', None)
            else:
                BASE = os.environ.get('LINUXCNC_HOME', None)
                # fallback until the RIP_FLAG is common
                if BASE is None:
                    BASE = os.environ.get('EMC2_HOME', None)

            # catch all
            if BASE is None:
                BASE = '/usr'

            LOG.debug('Linuxcnc Home directory found in environmental variable: {}'.format(BASE))

            # share directory moves when using RIP vrs installed
            self.SHAREDIR = os.path.join(BASE,"share", "qtvcp")

            self.IMAGEDIR = os.path.join(self.SHAREDIR,  "images")
            self.SCREENDIR = os.path.join(self.SHAREDIR, "screens")
            self.PANELDIR = os.path.join(self.SHAREDIR, "panels")
            self.WIDGETUI = os.path.join(self.SHAREDIR, "widgets_ui")

            # Linuxcnc project base directory moves when using RIP vrs installed
            try:
                self.BASEDIR = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), ".."))
            except:
                # TODO not sure if working directory is right - this is to fix an error with designer
                # loading widget libraries
                self.BASEDIR = self.WORKINGDIR
            self.RIPCONFIGDIR = os.path.join(self.BASEDIR, "configs", "sim", "qtvcp_screens")
            self.CONFIGPATH = self.WORKINGDIR
            # specific library paths
            self.TOUCHOFF_SUBPROGRAM = os.path.abspath(os.path.join(
                self.LIBDIR, 'touchoff_subprogram.py'))

            # python RIP library directory
            self.PYDIR = os.path.join(self.BASEDIR, "lib", "python")
            sys.path.insert(0, self.PYDIR)

        except Exception as e:
            print ('qt_Pstat:',e)
            pass

    def set_paths(self, filename='dummy', isscreen=False, INI=None):
        self.PREFS_FILENAME = None
        self.IS_SCREEN = isscreen
        self.QRC_IS_LOCAL = None
        self.QRCPY_IS_LOCAL = None
        self.INI_PATH = INI

        if isscreen:
            # path to the configuration the user requested
            try:
                self.CONFIGPATH = os.environ['CONFIG_DIR']
                sys.path.insert(0, self.CONFIGPATH)
            except:
                self.CONFIGPATH = self.WORKINGDIR
        else:
            # VCP panels don't usually have config paths but QTVCP looks for one.
            # TODO this fixes the error but maybe it should be something else
            self.CONFIGPATH = self.WORKINGDIR

        # record the original argument passed to us
        self.ARGUMENT = filename
        # PyQt's .ui file's basename
        self.BASENAME = os.path.splitext(os.path.basename(filename))[0]
        # base path (includes any extra path commands
        self.BASEPATH = os.path.splitext(filename)[0]
        LOG.debug('Passed name={}, BASENAME={} BASEPATH={}'.format(self.ARGUMENT, self.BASENAME, self.BASEPATH))
        LOG.verbose('Working directory: {}'.format(self.WORKINGDIR))

        # look for custom handler files:
        handler_fn = "{}_handler.py".format(self.BASEPATH)
        local = []
        if self.IS_SCREEN:
            # builtin screen folder
            self._default_handler_path = os.path.join(self.SCREENDIR, self.BASEPATH, handler_fn)
            # relative to configuration folder
            local.append( os.path.join(self.CONFIGPATH, handler_fn))
            # in standard folder
            local.append( os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH, handler_fn))
            # legacy standard folder
            local.append( os.path.join(self.CONFIGPATH, self.BASEPATH, handler_fn))
        else:
            # in standard folder
            local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',self.BASEPATH, handler_fn))
            # relative to configuration folder
            local.append( os.path.join(self.WORKINGDIR, handler_fn))
            # builtin panel folder
            self._default_handler_path = os.path.join(self.PANELDIR, self.BASEPATH, handler_fn)

        for local_handler_path in local:
            LOG.debug("Checking for handler file in: yellow<{}>".format(local_handler_path))
            if os.path.exists(local_handler_path):
                self.HANDLER = local_handler_path
                LOG.info("bggreen<Using LOCAL handler file path:> yellow<{}>".format(self.HANDLER))
                break
        # if no break
        else:
            LOG.debug("Checking for default handler file in: yellow<{}>".format(self._default_handler_path))
            if os.path.exists(self._default_handler_path):
                self.HANDLER = self._default_handler_path
                LOG.info("bggreen<Using DEFAULT handler file path:> yellow<{}>".format(self.HANDLER))
            else:
                self.HANDLER = None
                LOG.info("No handler file found.")
        if not self.HANDLER is None:
            self.HANDLERDIR = os.path.dirname(self.HANDLER)
        else:
            self.HANDLERDIR = None

        # look for custom ui file
        ui_fn = "{}.ui".format(self.BASEPATH)
        local = []
        if self.IS_SCREEN:
            defaultui = os.path.join(self.SCREENDIR, self.BASEPATH, ui_fn)
            local.append( os.path.join(self.CONFIGPATH, ui_fn))
            local.append( os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH, ui_fn))
            local.append( os.path.join(self.CONFIGPATH,self.BASEPATH, ui_fn))
        else:
            local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',self.BASEPATH, ui_fn))
            local.append( os.path.join(self.WORKINGDIR, ui_fn))
            defaultui = os.path.join(self.PANELDIR, self.BASEPATH, ui_fn)

        for localui in local:
            LOG.debug("Checking for .ui in: yellow<{}>".format(localui))
            if os.path.exists(localui):
                LOG.info("bggreen<Using LOCAL ui file from:> yellow<{}>".format(localui))
                self.XML = localui
                break
        # if no break
        else:
            LOG.debug("Checking for .ui in: yellow<{}>".format(defaultui))
            if os.path.exists(defaultui):
                LOG.info("bggreen<Using DEFAULT ui file from:> yellow<{}>".format(defaultui))
                self.XML = defaultui
            else:
                # error
                self.XML = None
                LOG.info("No ui file found.")

        if not self.HANDLER is None:
            self.XMLDIR = os.path.dirname(self.HANDLER)
        else:
            self.XMLDIR = None

        # check for qss file
        qss_fn = "{}.qss".format(self.BASEPATH)
        local = []
        if self.IS_SCREEN:
            defaultqss = os.path.join(self.SCREENDIR, self.BASEPATH, qss_fn)
            local.append( os.path.join(self.CONFIGPATH, qss_fn))
            local.append( os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH, qss_fn))
            local.append( os.path.join(self.CONFIGPATH, self.BASEPATH, qss_fn))
        else:
            local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',self.BASEPATH, qss_fn))
            local.append( os.path.join(self.WORKINGDIR, qss_fn))
            defaultqss = os.path.join(self.PANELDIR, self.BASEPATH, qss_fn)

        for localqss in local:
            LOG.debug("Checking for .qss in: yellow<{}>".format(localqss))
            if os.path.exists(localqss):
                LOG.info("bggreen<Using LOCAL qss file as default stylesheet:> yellow<{}>".format(localqss))
                self.QSS = localqss
                break
        # if no break
        else:
            LOG.debug("Checking for .qss in: yellow<{}>".format(defaultqss))
            if os.path.exists(defaultqss):
                LOG.debug("bggreen<Using DEFAULT qss file as default stylesheet:> yellow<{}>".format(defaultqss))
                self.QSS = defaultqss
            else:
                self.QSS = None
                LOG.info("No qss file found.")

        # check for qrc file
        qrc_fn = "{}.qrc".format(self.BASEPATH)
        local = []
        if self.IS_SCREEN:
            defaultqrc = os.path.join(self.SCREENDIR, self.BASEPATH, qrc_fn)
            local.append(os.path.join(self.CONFIGPATH, qrc_fn))
            local.append( os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH, qrc_fn))
            local.append(os.path.join(self.CONFIGPATH, self.BASEPATH, qrc_fn))
        else:
            local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',self.BASEPATH, qrc_fn))
            local.append( os.path.join(self.WORKINGDIR, qrc_fn))
            defaultqrc = os.path.join(self.PANELDIR, self.BASEPATH, qrc_fn)

        for localqrc in local:
            LOG.debug("Checking for .qrc in: yellow<{}>".format(localqrc))
            if os.path.exists(localqrc):
                LOG.info("bggreen<Using LOCAL qrc file from:> yellow<{}>".format(localqrc))
                self.QRC = localqrc
                self.QRC_IS_LOCAL = True
                break
        # if no break
        else:
            LOG.debug("Checking for .qrc in: yellow<{}>".format(defaultqrc))
            if os.path.exists(defaultqrc):
                LOG.debug("bggreen<Using DEFAULT qrc file from:> yellow<{}>".format(defaultqrc))
                self.QRC = defaultqrc
                self.QRC_IS_LOCAL = False
            else:
                self.QRC = None
                LOG.info("No qrc file found.")

        # check for qrcpy file
        qrcpy_fn = 'resources.py'
        self.QRCPY_IS_LOCAL = None
        if self.IS_SCREEN:
            localqrcpy = os.path.join(self.CONFIGPATH, 'qtvcp/screens', self.BASEPATH,qrcpy_fn)
        else:
            localqrcpy = os.path.join(self.WORKINGDIR, 'qtvcp/panels', qrcpy_fn)

        LOG.debug("Checking for resources.py in: yellow<{}>".format(localqrcpy))
        # if there is a local resource file or a QRC to compile it from:
        if os.path.exists(localqrcpy) or self.QRC is not None:
            if os.path.exists(localqrcpy):
                LOG.info("bggreen<Using LOCAL resources.py file from:> yellow<{}>".format(localqrcpy))
            else:
                LOG.info("Resources.py file needs to be compiled at: {}".format(localqrcpy))
            self.QRCPY = localqrcpy
            self.QRCPY_IS_LOCAL = True
        else:
            self.QRCPY = None
            LOG.info("No resources.py file found, no QRC file to compile one from.")

        # translation path
        lang = QtCore.QLocale.system().name().split('_')[0]
        qm_fn = "languages/{}_{}.qm".format(self.BASEPATH,lang)
        defaultqm = os.path.join(self.SCREENDIR, self.BASEPATH, qm_fn)
        local = []
        local.append( os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH, qm_fn))
        local.append( os.path.join(self.CONFIGPATH, self.BASEPATH, qm_fn))

        for localqm in local:
            LOG.debug("Checking for translation file in: yellow<{}>".format(localqm))
            if os.path.exists(localqm):
                LOG.info("bggreen<Using LOCAL translation file from:> yellow<{}>".format(localqm))
                self.LOCALEDIR = localqm
                break
        # if no break
        else:
            LOG.debug("Checking for translation file in: yellow<{}>".format(defaultqm))
            if os.path.exists(defaultqm):
                LOG.debug("bggreen<Using DEFAULT translation file from:> yellow<{}>".format(defaultqm))
                self.LOCALEDIR = defaultqm
            else:
                LOG.info("bggreen<Using no translations, default system locale is:> yellow<{}>".format(lang))
                self.LOCALEDIR = None

        # look for ABOUT files:
        about_fn = "{}_ABOUT".format(self.BASEPATH)
        local = []
        if self.IS_SCREEN:
            default_about_path = os.path.join(self.SCREENDIR, self.BASEPATH, about_fn)
            local.append(os.path.join(self.CONFIGPATH, about_fn))
            local.append(os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH, about_fn))
        else:
            local.append(os.path.join(self.WORKINGDIR, about_fn))
            local.append(os.path.join(self.WORKINGDIR, 'qtvcp/panels', about_fn))
            default_about_path = os.path.join(self.PANELDIR, self.BASEPATH, about_fn)

        for localabout in local:
            LOG.debug("Checking for LOCAL about file in: yellow<{}>".format(localabout))
            if os.path.exists(localabout):
                self.ABOUT = localabout
                LOG.info("bggreen<Using LOCAL about file path:> yellow<{}>".format(self.ABOUT))
                break
        else:
            LOG.debug("Checking for DEFAULT about file in: yellow<{}>".format(default_about_path))
            if os.path.exists(default_about_path):
                self.ABOUT = default_about_path
                LOG.debug("bggreen<Using DEFAULT about file path:> yellow<{}>".format(self.ABOUT))
            else:
                self.ABOUT = ""
                LOG.debug("No about file found.")

        if self.XML is None and self.HANDLER is None:
            LOG.critical("No UI or handler file found - Did you add the .ui name/path?")
            LOG.info('Available built-in Machine Control Screens:')
            for i in self.find_screen_dirs():
               print(('{}'.format(i)))
            print('')
            LOG.info('Available built-in VCP Panels:')
            for i in self.find_panel_dirs():
                print(('{}'.format(i)))
            print('')
            return True # error

    # search for local ui paths or default to standard
    def find_widget_path(self,uifile=''):
        try:
            local = os.path.join(self.CONFIGPATH, 'qtvcp/widgets_ui', uifile)
            LOG.verbose("Checking for widget file in: yellow<{}>".format(local))
            if os.path.exists(local):
                LOG.info("bggreen<Using LOCAL widget file from:> yellow<{}>".format(local))
                return local
        except:
            pass

        default = os.path.join(self.WIDGETUI,uifile)
        LOG.verbose("Checking for widget file in: yellow<{}>".format(default))
        if os.path.exists(default):
            LOG.verbose("bggreen<Using default widget file from:> yellow<{}>".format(default))
            return default

    # search for local widget path or default to standard
    def find_custom_widget_path(self,widfile,klass):
        try:
            local = os.path.join(self.CONFIGPATH, 'qtvcp/widgets', widfile)
            LOG.verbose("Checking for custom widget file in: yellow<{}>".format(local))
            if os.path.exists(local):
                LOG.info("bggreen<Using LOCAL custom widget file from:> yellow<{}>".format(local))
                import importlib
                sys.path.insert(0,  os.path.join(self.CONFIGPATH, 'qtvcp/widgets'))
                justname = widfile[:widfile.index('.')]
                print(justname)
                mod = importlib.import_module(justname, os.path.join(self.CONFIGPATH, 'qtvcp/widgets'))
                sys.path.remove(os.path.join(self.CONFIGPATH, 'qtvcp/widgets'))
                return getattr(mod, klass)
        except Exception as e:
            print('oops',e)
            pass

    # search for local image paths or default to standard
    def find_image_path(self,imagefile=''):
        try:
            local = os.path.join(self.CONFIGPATH, 'qtvcp/images', imagefile)
            LOG.verbose("Checking for images path in: yellow<{}>".format(local))
            if os.path.exists(local):
                LOG.info("bggreen<Using LOCAL images path from:> yellow<{}>".format(local))
                return local
        except:
            pass

        default = os.path.join(self.IMAGEDIR,imagefile)
        LOG.verbose("Checking for image path in: yellow<{}>".format(default))
        if os.path.exists(default):
            LOG.verbose("bggreen<Using default image path from:> yellow<{}>".format(default))
            return default

    def find_embed_panel_path(self, name):
        # look for custom ui file
        ui_fn = "{}.ui".format(name)
        local = []
        local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',name, ui_fn))
        local.append( os.path.join(self.WORKINGDIR, ui_fn))
        defaultui = os.path.join(self.PANELDIR, name, ui_fn)

        for localui in local:
            LOG.debug("(embed) Checking for .ui in: yellow<{}>".format(localui))
            if os.path.exists(localui):
                LOG.info("(embed) bggreen<Using LOCAL ui file from:> yellow<{}>".format(localui))
                XML = localui
                return XML
        # if no break
        else:
            LOG.debug("(embed) Checking for .ui in: yellow<{}>".format(defaultui))
            if os.path.exists(defaultui):
                LOG.info("(embed) bggreen<Using DEFAULT ui file from:> yellow<{}>".format(defaultui))
                XML = defaultui
                return XML
            else:
                # error
                LOG.critical("(embed) No UI file found - Did you add the .ui name/path?")
                return True # error

    def find_embed_handler_path(self, name):
        # look for custom handler files:
        handler_fn = "{}_handler.py".format(name)
        local = []
        # in standard folder
        local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',name, handler_fn))
        # relative to configuration folder
        local.append( os.path.join(self.WORKINGDIR, handler_fn))
        # builtin panel folder
        default_handler_path = os.path.join(self.PANELDIR, name, handler_fn)

        for local_handler_path in local:
            LOG.debug("(embed) Checking for handler file in: yellow<{}>".format(local_handler_path))
            if os.path.exists(local_handler_path):
                HANDLER = local_handler_path
                LOG.info("(embed) bggreen<Using LOCAL handler file path:> yellow<{}>".format(HANDLER))
                return HANDLER
        # if no break
        else:
            LOG.debug("(embed) Checking for default handler file in: yellow<{}>".format(default_handler_path))
            if os.path.exists(default_handler_path):
                HANDLER = default_handler_path
                LOG.info("(embed) bggreen<Using DEFAULT handler file path:> yellow<{}>".format(HANDLER))
                return HANDLER
            else:
                HANDLER = None
                LOG.info("(embed) No handler file found.")
                return True

    def find_screen_dirs(self):
        dirs = next(os.walk(self.SCREENDIR))[1]
        return dirs

    def find_panel_dirs(self):
        dirs = next(os.walk(self.PANELDIR))[1]
        return dirs

    def find_vismach_files(self):
        tmp = []
        for file in os.listdir(self.VISMACHDIR):
            if file.endswith(".py"):
                if not file in ('__init__.py', 'qt_vismach.py', 'primitives.py'):
                    tmp.append(file)
            elif os.path.isdir(os.path.join(self.VISMACHDIR, file)):
                if 'obj' in file:
                    tmp.append(file)

        return tmp

    def isUsingDefaultHandler(self):
        return bool(self.HANDLER == self._default_handler_path)

    def getQSSPaths(self, addBuiltinStyles = True):
        '''
        Search for qss files in default builtin directories,
        in the configuration expected directory CONFIG DIR/qtvcp/screen/SCREEN NAME, or 
        CONFIG DIR/qtvcp/panel/PANEL NAME or finally the legacy location in the configuration directory.
        Returns two lists of a list of directory/filename pairs. The first list is default 
        builtin paths, the second is local configuration paths
        '''
        local = []
        default = ''
        if self.IS_SCREEN:
            if addBuiltinStyles:
                default = os.path.join(self.SCREENDIR, self.BASEPATH)
            local.append( os.path.join(self.CONFIGPATH))
            local.append( os.path.join(self.CONFIGPATH, 'qtvcp/screens',self.BASEPATH))
            local.append( os.path.join(self.CONFIGPATH, self.BASEPATH))
        else:
            local.append( os.path.join(self.WORKINGDIR, 'qtvcp/panels',self.BASEPATH))
            local.append( os.path.join(self.WORKINGDIR))
            if addBuiltinStyles:
                default = os.path.join(self.PANELDIR, self.BASEPATH)

        temp = []
        for group in ([default],local):
            child = []
            for qsspath in group:
                if not os.path.exists(qsspath):
                    continue
                try:
                    fileNames= [f for f in os.listdir(qsspath) if f.endswith('.qss')]
                    for i in fileNames:
                        child.append([qsspath,i])

                except Exception as e:
                    print(e)
            temp.append(child)

        return temp[0], temp[1]

    def modnamefromFilename(self, fname):
        panel = os.path.splitext(os.path.basename(os.path.basename(fname)))[0]
        base = panel.replace('_handler','')
        module = "{}.{}".format(base,panel)
        return module

    # temporarily adds the screen directory to path
    # so the handler can be imported to be used for subclassing
    def importDefaultHandler(self, module=None):
        import importlib
        sys.path.insert(0, self.SCREENDIR)
        if module is None:
            module = "{}.{}_handler".format(self.BASEPATH,self.BASEPATH)
        mod = importlib.import_module(module, self.SCREENDIR)
        sys.path.remove(self.SCREENDIR)
        return mod.HandlerClass
