#!/usr/local/bin/python3.12
# -*- coding: utf-8 -*-
#
# (c) Copyright @2015 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
#


# Std Lib
import sys
import os.path
import re
import os

# Local
from .g import *
from . import utils, tui
from base import password, validation
from base.codes import *
from base.strings import *


##### Global variables ###
HPLIP_INFO_SITE ="http://hplip.sourceforge.net/hplip_web.conf"



########### methods ###########


def get_usb_details(vid_pid):
    result_cnt = 0
    param_result = {"idVendor":'', "iProduct":'',  "bNumInterfaces":'', "bInterfaceClass":''}
    param_search = {"idVendor": re.compile(r"""\s*idVendor\s*([0-9a-fx]{1,})\s*.*""", re.I),
                    "iProduct" : re.compile(r"""\s*iProduct\s*[0-9a-fx]{1,}\s*(.*)""", re.I),
                    "bNumInterfaces" : re.compile(r"""\s*bNumInterfaces\s*(\d{1,})\s*.*""", re.I),
                    "bInterfaceClass" : re.compile(r"""\s*bInterfaceClass\s*(\d{1,})\s*.*""", re.I)  }

    lsusb_cmd = utils.which('lsusb',True)
    if lsusb_cmd:
        sts,out = utils.run("%s -d %s -v"%(lsusb_cmd, vid_pid), passwordObj = None, pswd_msg='', log_output=False)
        if sts == 0:
            for l in out.splitlines():
                for s in param_search:
                    if s in l:
                        result_cnt += 1
                        if param_search[s].match(l):
                            param_result[s] = param_search[s].match(l).group(1)
                        else:
                            log.warn("TBD... Shouldn't have entered into this condition. key[%s]"%s)

                        if "idVendor" ==  s and param_result[s].lower() != "0x03f0":  # if non-HP vendor, ignoring usb parsing.
                            return False, {}
                        elif "iProduct" == s and param_result[s] == "":
                            return False, {}

                        break

                if result_cnt == len(param_result):  # To avoid extra parsing...
                     break

    return True, param_result


# get_smartinstall_enabled_devices function checks CD-ROM enabled devices.
#Input:
#       None
# Output:
#       smartinstall_dev_list (list) --> Returns CD-ROM enabled device list.
#
def get_smartinstall_enabled_devices():
    smartinstall_dev_list=[]
    lsusb_cmd = utils.which('lsusb',True)

    if not lsusb_cmd:
        log.error("Failed to find the lsusb command")
        return smartinstall_dev_list

    try:
        sts,out = utils.run(lsusb_cmd)
        if sts !=  0:
            log.error("Failed to run the %s command"%lsusb_cmd)
            return smartinstall_dev_list

        for d in out.splitlines():
            usb_dev_pat = re.compile(r""".*([0-9a-f]{4}:([0-9a-f]{4}))\s*""", re.I)

            if usb_dev_pat.match(d):
                vid_pid = usb_dev_pat.match(d).group(1)

                bsts, usb_params = get_usb_details(vid_pid)
                if not bsts:
                    continue    # These are not HP-devices

                log.debug("Product['%s'],Interfaces[%s],InterfaceClass[%s]"%(usb_params["iProduct"], usb_params["bNumInterfaces"],usb_params["bInterfaceClass"]))
                if usb_params["bNumInterfaces"] == '1' and usb_params["bInterfaceClass"] == '8' and "laserjet" in usb_params["iProduct"].lower():    #'8' is MASS STORAGE
                    smartinstall_dev_list.append(usb_params["iProduct"])

            else:
                log.warn("Failed to find vid and pid for USB device[%s]"%d)

    except KeyError:
        pass

    if smartinstall_dev_list:
        smartinstall_dev_list = utils.uniqueList(smartinstall_dev_list)

    return smartinstall_dev_list


def check_SmartInstall():
    devices = get_smartinstall_enabled_devices()
    if devices:
        return True
    else:
        return False


def get_SmartInstall_tool_info():
    url, file_name = "", ""
    if not utils.check_network_connection():
        log.error("Internet connection not found.")
    else:
        sts, HPLIP_file = utils.download_from_network(HPLIP_INFO_SITE)
        if sts == 0:
            hplip_si_conf = ConfigBase(HPLIP_file)
            url = hplip_si_conf.get("SMART_INSTALL","reference","")
            if url:
                file_name = 'SmartInstallDisable-Tool.run'
            else:
                log.error("Failed to download %s."%HPLIP_INFO_SITE)
        else:
            log.error("Failed to download %s."%HPLIP_INFO_SITE)

    return url, file_name

def validate(mode, smart_install_run, smart_install_asc, req_checksum=''):

    #Validate Checksum
    calc_checksum = utils.get_checksum(open(smart_install_run, 'r').read())
    log.debug("File checksum=%s" % calc_checksum)

    if req_checksum and req_checksum != calc_checksum:
        return ERROR_FILE_CHECKSUM, queryString(ERROR_CHECKSUM_ERROR, 0, plugin_file)

    #Validate Digital Signature
    gpg_obj = validation.GPG_Verification()
    digsig_sts, error_str = gpg_obj.validate(smart_install_run, smart_install_asc)

    return digsig_sts, smart_install_run, smart_install_asc, error_str



def download(mode, passwordObj):
    if not utils.check_network_connection():
        log.error("Internet connection not found.")
        return ERROR_NO_NETWORK, "" , "" ,queryString(ERROR_NO_NETWORK)

    else:
        sts, HPLIP_file = utils.download_from_network(HPLIP_INFO_SITE)
        if sts == 0:
            hplip_si_conf = ConfigBase(HPLIP_file)
            source = hplip_si_conf.get("SMART_INSTALL","url","")
            if not source:
                log.error("Failed to download %s."%HPLIP_INFO_SITE)
                return ERROR_FAILED_TO_DOWNLOAD_FILE, "" , "", queryString(ERROR_FAILED_TO_DOWNLOAD_FILE, 0, HPLIP_INFO_SITE)

        sts, smart_install_run = utils.download_from_network(source)
        if sts:
            log.error("Failed to download %s."%source)
            return ERROR_FAILED_TO_DOWNLOAD_FILE, "" , "", queryString(ERROR_FAILED_TO_DOWNLOAD_FILE, 0, source)

        sts, smart_install_asc = utils.download_from_network(source+'.asc')
        if sts:
            log.error("Failed to download %s."%(source+'.asc'))
            return ERROR_FAILED_TO_DOWNLOAD_FILE, "" , "", queryString(ERROR_FAILED_TO_DOWNLOAD_FILE, 0, source + ".asc")

        digsig_sts, smart_install_run, smart_install_asc, error_str = validate(mode, smart_install_run, smart_install_asc)

        return digsig_sts, smart_install_run, smart_install_asc, error_str


def disable(mode, ui_toolkit='qt4', dialog=None, app=None, passwordObj = None):

    dev_list = get_smartinstall_enabled_devices()
    if not dev_list:
        log.debug("No Smart Install Device found")
        return ERROR_NO_SI_DEVICE, queryString(ERROR_NO_SI_DEVICE)

    return_val = ERROR_FAILED_TO_DISABLE_SI
    return_error_str = queryString(ERROR_FAILED_TO_DISABLE_SI)
    url, file_name = get_SmartInstall_tool_info()
    printer_names  = utils.list_to_string(dev_list)

    try:
        if mode == GUI_MODE:
            if ui_toolkit == 'qt3':
                try:
                    from ui.setupform import FailureMessageUI
                except ImportError:
                    log.error("Smart Install is enabled in %s device(s).\nAuto Smart Install disable is not supported in QT3.\nPlease refer link \'%s\' to disable manually"%(printer_names,url))
                else:
                    FailureMessageUI("Smart Install is enabled in %s device(s).\n\nAuto Smart Install disable is not supported in QT3.\nPlease refer link \'%s\' to disable manually"%(printer_names,url))

            else: #qt4
                if not utils.canEnterGUIMode4():
                    log.error("%s requires GUI support . Is Qt4 installed?" % __mod__)
                    return ERROR_FAILED_TO_DISABLE_SI, queryString(ERROR_FAILED_TO_DISABLE_SI)

                if dialog and app:  # If QT app already opened, re-using same object
                    dialog.init(printer_names, "", QUEUES_SMART_INSTALL_ENABLED)
                else:   # If QT object is not created, creating QT app
                    try:
                        if ui_toolkit == "qt4":
                            from ui4.queuesconf import QueuesDiagnose
                        elif ui_toolkit == "qt5":
                            from ui5.queuesconf import QueuesDiagnose    
                    except ImportError:
                        log.error("Unable to load Qt4/Qt5 support. Is it installed?")
                    else:       #  app = QApplication(sys.argv)   # caller needs to inoke this, if already QApplication object is not created.
                        dialog = QueuesDiagnose(None, printer_names ,"",QUEUES_SMART_INSTALL_ENABLED)

                log.debug("Starting GUI loop...")
                dialog.exec_()

                if check_SmartInstall():
                    dialog.showMessage("Failed to disable smart install.\nPlease refer link \'%s\' for more information" %url)
                else:
                    dialog.showSuccessMessage("Smart install disabled successfully.")


        #Interaction mode
        else: 
            log.error("Smart Install is enabled in %s device(s). "%printer_names)
            response, value = tui.enter_choice("Do you want to download and disable smart install?(y=yes*, n=no):",['y', 'n'], 'y')

            if not response or value != 'y':   #User exit
                return_val = ERROR_FAILED_TO_DISABLE_SI
                return_error_str = queryString(ERROR_FAILED_TO_DISABLE_SI)

            else:
                sts, smart_install_run, smart_install_asc, error_str = download(mode, passwordObj)

                disable_si = False
                return_val = sts

                if sts == ERROR_SUCCESS:
                    disable_si = True

                elif sts in (ERROR_UNABLE_TO_RECV_KEYS, ERROR_DIGITAL_SIGN_NOT_FOUND):
                    response, value = tui.enter_yes_no("Digital Sign verification failed, Do you want to continue?")
                    if not response or not value:
                        sys.exit(0)
                    else:   # Continue without validation succes.
                        disable_si = True
                else:
                    return_error_str = queryString(sts)

                if disable_si: 
                    sts, out = utils.run("sh %s"%smart_install_run)

                    # Once smart install disabler installation completed, cross verifying to ensure no smart install devices found
                    if sts or check_SmartInstall():
                        log.error("Failed to disable smart install .")
                        log.error("Please refer link \'%s\' to disable manually"%url)
                        return_val = ERROR_FAILED_TO_DISABLE_SI
                        return_error_str = queryString(ERROR_FAILED_TO_DISABLE_SI)
                    else:
                        log.info("Smart install disabled successfully.")
                        return_val = ERROR_SUCCESS
                        return_error_str = ""

    except KeyboardInterrupt:
        log.error("User exit")
        sys.exit(0)

    return return_val ,return_error_str

