#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# (c) Copyright 2012-2020 HP Development Company, L.P.
#
# 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.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
#
# Author: Amarnath Chitumalla
#

__version__ = '1.0'
__title__ = 'Self Diagnse Utility and Healing Utility'
__mod__ = 'hp-doctor'
__doc__ = """Tool checks for the deprecated, plug-in, dependencies, queues, permission issues and provides self diagnose steps"""


# global import
import getopt
import os
import sys
import getpass

#local import
from base.g import *
from base.strings import *
try:
    from base import utils, tui, module,queues, os_utils, services, smart_install
except ImportError as e:
    if 'cupsext' in e.args[0] :
        check_extension_module_env('cupsext')
    else:
        log.exception("")
        sys.exit(1)
        
from installer.core_install import *
from check import DependenciesCheck

USAGE = [(__doc__, "", "name", True),
         ("Usage: %s [OPTIONS]" % __mod__, "", "summary", True),
         utils.USAGE_SPACE,
         utils.USAGE_MODE,
         ("Run in interactive mode:", "-i or --interactive (Default)", "option", False),
#         ("Run in graphical UI mode:", "-u or --gui (future use)", "option", False),
         utils.USAGE_SPACE,
         utils.USAGE_OPTIONS,
         utils.USAGE_HELP,
         utils.USAGE_LOGGING1, utils.USAGE_LOGGING2, utils.USAGE_LOGGING3,
#         ("Non-interactive mode:","-n(Without asking permissions)(future use)","option",False),
#         ("Perform the task for the given device id:","-d<device id>(future use)","option",False),
#         ("Take options from the file instead of command line:","-f<file> (future use)","option",False)

        ]

##########################global variables ##########################3
MODE = INTERACTIVE_MODE
DEVICE_URI = None
PERFORM_IN_NON_INTERACTIVE_MODE=False
LOG_LEVEL=None
VALID_AUTHENTICATION = False
IS_RESTART_REQ = False
DONOT_CLOSE_TERMINAL=False
SUMMARY_ONLY = False

#################################### functions #########################
def usage(typ='text'):
    if typ == 'text':
        utils.log_title(__title__, __version__)

    utils.format_text(USAGE, typ, __title__, __mod__, __version__)
    clean_exit(2)


def append_options(cmd):
    if MODE == INTERACTIVE_MODE:
        cmd += " -i "
    elif MODE == GUI_MODE:
        cmd += " -u "

    if PERFORM_IN_NON_INTERACTIVE_MODE:
        cmd += " -n "

    if LOG_LEVEL:
        cmd += " -l%s"%LOG_LEVEL

    # Adding quiet mode option..
    cmd += " -s "
    return cmd


def authenticate(core):
    global VALID_AUTHENTICATION
    if not services.running_as_root() and VALID_AUTHENTICATION == False:
        ###TBD
        # if MODE == GUI_MODE:
        #    GUI passwrd query..
        # else:
        if core.passwordObj.getAuthType() == "sudo":
            tui.title("ENTER SUDO PASSWORD")
        else:
            tui.title("ENTER ROOT/SUPERUSER PASSWORD")

        VALID_AUTHENTICATION = core.check_password()
    else:
        VALID_AUTHENTICATION = True

    if not VALID_AUTHENTICATION:
        log.error("3 incorrect attempts. (or) Insufficient permissions(i.e. try with sudo user).\nExiting.")
        clean_exit(3)

    return VALID_AUTHENTICATION


def install_plugin(core):
    plugin_sts = core.get_plugin_status()
    if plugin_sts == PLUGIN_VERSION_MISMATCH:
        ok,user_input =tui.enter_choice("Found Plugin version mismatch. Press 'y' to re-install the plugin(y=yes*, n=no):",['y', 'n'], 'y')
    elif plugin_sts == PLUGIN_FILES_CORRUPTED:
        ok,user_input =tui.enter_choice("Plugins corrupted. Press 'y' to re-install the plugin(y=yes*, n=no):",['y', 'n'], 'y')
    elif plugin_sts == PLUGIN_NOT_INSTALLED:
        ok,user_input =tui.enter_choice("Plugin's are missing. Press 'y' to install the plugin(y=yes*, n=no):",['y', 'n'], 'y')
    elif plugin_sts == PLUGIN_INSTALLED:
        log.info("Plugin's already installed")
        return True
    else:
        log.info("No plug-in printers are configured.")
        return True

    if ok and user_input == 'y':
#        authenticate(core)
        cmd='hp-plugin'
        cmd = append_options(cmd)
        sts = os_utils.execute(cmd)
        if sts == 0:
            return True
        else:
            log.info(log.bold("Failed to install Plugin. Please run 'hp-plugin' command to install plugin manually"))
    return False


def deprecated_check(core):
    if core.validate_distro_version():
        log.debug("This distro is supported.")
        log.info("No Deprecated items are found")
    else:
        log.error("This distro (i.e %s  %s) is either deprecated or not yet supported."%(core.distro_name, core.distro_version))
        ok,user_input =tui.enter_choice(log.red("The diagnosis is limited on unsupported platforms. Do you want to continue?(y=yes*, n=no):"),['y', 'n'], 'y')
        if not ok or user_input !='y':
            clean_exit(2)


def display_missing_dependencies(required_dependencies=[],optional_dependencies=[], missing_cmd=[]):
    if len(required_dependencies):
        log.info(log.bold("Missing Required Dependencies"))
        log.info(log.bold('-'*len("Missing Required Dependencies")))
        for packages_to_install in required_dependencies:
           if 'cups' in packages_to_install:
               log.error("'%s' package is missing or '%s' service is not running."%(packages_to_install,'cups'))
           else:
               log.error("'%s' package is missing/incompatible "%packages_to_install)

    if len(optional_dependencies):
        log.info(log.bold("Missing Optional Dependencies"))
        log.info(log.bold('-'*len("Missing Optional Dependencies")))
        for packages_to_install in optional_dependencies:
            log.error("'%s' package is missing/incompatible "%packages_to_install)

    if len(missing_cmd):
        log.info(log.bold("Missing Commands"))
        log.info(log.bold('-'*len("Missing Commands")))
        for cmd in missing_cmd:
            log.error("'%s' is missing"%cmd)


def clean_exit(exit_code=0):
    mod.unlockInstance()

    if DONOT_CLOSE_TERMINAL:
        log.info("\n\nPlease close this terminal manually. ")
        try:
            while 1:
                pass
        except KeyboardInterrupt:
            pass

    sys.exit(exit_code)


#################################### Main #########################
log.set_module(__mod__)
try:
    mod = module.Module(__mod__, __title__, __version__, __doc__, USAGE,
                    (INTERACTIVE_MODE, GUI_MODE),
                    (UI_TOOLKIT_QT3, UI_TOOLKIT_QT4, UI_TOOLKIT_QT5), True)

    opts, device_uri, printer_name, mode, ui_toolkit, loc = \
               mod.parseStdOpts('hl:gnid:f:w', ['summary-only','help', 'help-rest', 'help-man', 'help-desc', 'interactive', 'gui', 'lang=','logging=', 'debug'],
                     handle_device_printer=False)

except getopt.GetoptError as e:
    log.error(e.msg)
    usage()

if os.getenv("HPLIP_DEBUG"):
    log.set_level('debug')
    LOG_LEVEL = 'debug'

for o, a in opts:
    if o == '-n':
        MODE = NON_INTERACTIVE_MODE
        PERFORM_IN_NON_INTERACTIVE_MODE = True
        log.warn("NON_INTERACTIVE mode is not yet supported.")
        #TBD
        usage()
    elif o == '-d':
        DEVICE_URI=a
    elif o in ('-u', '--gui'):
        log.warn("GUI is not yet supported.")
        #TBD
        usage()
    elif o == '-f':
        log.warn("Option from file is not yet supported")
        #TBD
        usage()
    elif o in ('-l', '--logging'):
        LOG_LEVEL = a.lower().strip()
        if not log.set_level(LOG_LEVEL):
            usage()
    elif o == '-w':
        DONOT_CLOSE_TERMINAL = True

    elif o == '--summary-only':
        SUMMARY_ONLY = True


try:
    if os.geteuid() == 0:
        log.error("%s %s"  %(__mod__, queryString(ERROR_RUNNING_AS_ROOT)))
        sys.exit(1)

    mod.lockInstance('')
    mod.quiet= False
    mod.showTitle()
    log_file = os.path.normpath('%s/hp-doctor.log'%prop.user_dir)

    if os.path.exists(log_file):
        try:
            os.remove(log_file)
        except OSError:
            pass

    log.set_logfile(log_file)
    log.set_where(log.LOG_TO_CONSOLE_AND_FILE)

    log.debug("Upgrade log saved in: %s" % log.bold(log_file))
    log.debug("")

    if PERFORM_IN_NON_INTERACTIVE_MODE and os.geteuid() != 0:
        log.error("Non Interactive mode should be run in root mode.")
        clean_exit(1)

    ui_toolkit = sys_conf.get('configure','ui-toolkit')

    dep =  DependenciesCheck(MODE_CHECK,INTERACTIVE_MODE,ui_toolkit)
    dep.core.init()
    log.info(log.bold("\n\nChecking for Deprecated items...."))

    deprecated_check(dep.core)

    log.info(log.bold("\n\nChecking for HPLIP updates...."))
    upgrade_cmd = utils.which('hp-upgrade',True)
    if upgrade_cmd:
        #checking for latest version of HPLIP.
        upgrade_cmd = append_options(upgrade_cmd)
        sts = os_utils.execute(upgrade_cmd)
        if sts != 0:
            log.error("Failed to upgrade latest HPLIP. Is hp-upgrade already running (i.e. foreground or background)?")
    else:
        log.error("Failed to locate hp-upgrade utility")

    ### Dependency check
    log.info(log.bold("\n\nChecking for Dependencies...."))
    if SUMMARY_ONLY:
        num_errors, num_warns = dep.validate(DEPENDENCY_RUN_AND_COMPILE_TIME, True)
    else:
        num_errors, num_warns = dep.validate(DEPENDENCY_RUN_AND_COMPILE_TIME, False)

    if num_errors or num_warns:

        if dep.get_required_deps() or dep.get_optional_deps() or dep.get_cmd_to_run():
            display_missing_dependencies(dep.get_required_deps(),dep.get_optional_deps(), dep.get_cmd_to_run())
            authenticate(dep.core)
            dep.core.install_missing_dependencies(INTERACTIVE_MODE,dep.get_required_deps(),dep.get_optional_deps(), dep.get_cmd_to_run())

        log.info(log.bold("\n\nChecking Permissions...."))
#        if not core.get_missing_user_grps() and not core.get_disable_selinux_status():
        # if not core.get_disable_selinux_status():
        #     log.info("Permissions are correct.")

#        if core.get_missing_user_grps():
#            log.info(log.bold("Missing User Groups"))
#            log.info(log.bold('-'*len("Missing User Groups")))
#            log.info("%s"%core.get_missing_user_grps())
#            authenticate(core)
#            if core.add_groups_to_user(core.get_missing_user_grps(), core.get_user_grp_cmd()):
#                IS_RESTART_REQ = True

        # if core.get_disable_selinux_status():
        #     log.info(log.bold("SELinux Status"))
        #     log.info(log.bold('-'*len("SELinux Status")))
        #     log.info("SELinux is enabled. Needs to be disabled")
        #     authenticate(core)
        #     if core.disable_SELinux():
        #         IS_RESTART_REQ = True

    log.info(log.bold("\n\nChecking for Configured Queues...."))
    queues.main_function(dep.core.passwordObj, MODE,ui_toolkit, False, DEVICE_URI)

    log.info(log.bold("\n\nChecking for HP Properitery Plugin's...."))
    ### Check for Plugin Printers
    install_plugin(dep)

    smart_ins_dev_list = smart_install.get_smartinstall_enabled_devices()
    if smart_ins_dev_list:
        log.info(log.bold("\n\nChecking for 'CD-ROM'/'Smart Install' Detected Devices...."))
        url, tool_name = smart_install.get_SmartInstall_tool_info()
        for printer in smart_ins_dev_list:
            log.error("Smart Install is Enabled in '%s' Printer. This needs to be disabled."%printer)
        log.info(log.bold("\nRefer link '%s' to disable Smart Install manually.\n"%(url)))

    comm_err_dev = dep.get_communication_error_devs()
    if comm_err_dev:
        log.info(log.bold("\n\nChecking for Printer Status...."))
        for printer in comm_err_dev:
            log.error("'%s' Printer is either Powered-OFF or Failed to communicate."%printer)
            log.info(log.bold("Turn On Printer and re-run %s"%__mod__))

    if IS_RESTART_REQ:
        log.info(log.bold("\nPlease reboot the system before performing any function."))

    log.info(log.bold("\nDiagnose completed...\n"))
    log.info("")
    log.info("")
    log.info("More information on Troubleshooting,How-To's and Support is available on http://hplipopensource.com/hplip-web/index.html")
        
    clean_exit(0)


except KeyboardInterrupt:
    log.error("User exit")
    clean_exit(1)

