#!/usr/bin/env python3
# -*- coding: utf-8 -*-

#**********************************************************************************
#*                                                                                *
#*                                   Silk Fontend                                 *
#*          ------------------------------------------------------------          *
#*                                                                                *
#**********************************************************************************
#
# Copyright 2025 Antonio Leal, Porto Salvo, Portugal
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# $Id:$

import sys
import os
import subprocess
import configparser

VERSION = '1.0.2' # The version of the program
SILKRC_VERSION = '1.0' # The version of the silkrc file format

# https://stackabuse.com/how-to-print-colored-text-in-python/
ESC = '\033['
NORMAL, BOLD, LIGHT, ITALIC, UNDERLINE, BLINK = [0, 1, 2, 3, 4, 5]
BLACK, RED, GREEN, YELLOW, BLUE, PURPLE, CYAN, WHITE = [30, 31, 32, 33, 34, 35, 36, 37]
def checkcolor(style, foreground, background):
    if style not in [NORMAL, BOLD, LIGHT, ITALIC, UNDERLINE, BLINK]: return False
    if foreground not in [BLACK, RED, GREEN, YELLOW, BLUE, PURPLE, CYAN, WHITE]: return False
    if background != '':
        if background not in [BLACK, RED, GREEN, YELLOW, BLUE, PURPLE, CYAN, WHITE]: return False
    return True
def defcolor(style, foreground, background=''):
    if checkcolor(style, foreground, background):
        if background == '':
            return f'{ESC}{style};{foreground}m'
        else:
            return f'{ESC}{style};{foreground};{background+10}m'
    return ''
def setcolor(style, foreground, background=''):
    print(defcolor(style,foreground,background), end='')
def undefcolor():
    return f'{ESC}0;0m'
def resetcolor():
    print(undefcolor(), end='')
def style2int(style):
    values = { 'NORMAL': 0, 'BOLD': 1, 'LIGHT': 2, 'ITALIC': 3, 'UNDERLINE': 4, 'BLINK': 5 }
    return values[style]
def color2int(color):
    values = { 'BLACK': 30, 'RED': 31, 'GREEN': 32, 'YELLOW': 33, 'BLUE': 34, 'PURPLE': 35, 'CYAN': 36, 'WHITE': 37 }
    return values[color]

def usage(config):
    print (f"Silk {VERSION} is a practical frontend to various slackware package management tools.\n")
    print (f"The following order is defined:")
    aux = []
    for f in FUNCS:
        fsetting = f.__name__.replace('_','-')
        order = config.get('settings', fsetting)
        if order in '1234':
            aux.append(f'{defcolor(NORMAL, RED)}({order}){undefcolor()} {fsetting}')
    lst = sorted(aux)
    for func in lst:
        print(f'    {func}')
    print ()
    print ("Usage: silk command [options] [programs]")
    print ()
    print ("commands:")
    print ("    u, update                    retrieve metadata related to packages and slackbuilds,")
    print ("                                 and upgrade you system")
    print ("    s, search                    search stuff")
    print ("    b, build   [programs]        download package / build slackbuilds ")
    print ("    i, install [programs]        install package / install slackbuilds ")
    print ("    c, clean                     clean caches")
    print ("    r, remove  [programs]        remove packages")
    print ("    l, list                      list packages")
    print ("")
    print ("where [programs] is a list of space separated package names")
    print ("")
    print ("options:")
    print ("    -y                           do not prompt for install/upgrade, assume yes")
    print ("    -o[1-4]                      select which tools (1-4) to run and the order of execution")
    print ("")
    print (f"Please also check ~/.config/silkrc settings to decide which tools you want to run.\n")

def execute(lines):
    #print(lines)
    with open('/tmp/silk', 'w') as file:
        file.writelines(lines)
    os.system('chmod +x /tmp/silk')
    subprocess.call('/tmp/silk')

def slapt_get(style, color, command, options, programs=""):
    localops = ''
    localcmd = ''
    if command in ['u', 'update']:
        localcmd = '-u'
    if command in ['s', 'search']:
        localcmd = '--search'
    if command in ['b', 'build']:
        localcmd = '-d --install'
    if command in ['i', 'install']:
        localcmd = '--install'
    if command in ['c', 'clean']:
        localcmd = '--clean'
    if command in ['r', 'remove']:
        localcmd = '--remove'
    if command in ['l', 'list']:
        localcmd = '--available'
    for op in options.split():
        if op == '-y':
            localops = localops + "-y "
    localops = localops.strip()
    if localcmd != "":
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slapt-get {localops}{localcmd} {programs}{undefcolor()}')
        lines = ['#!/bin/bash\n\n', f'sudo /usr/sbin/slapt-get {localops}{localcmd} {programs}\n']
        if localcmd == '-u':
            print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slapt-get {localops}--upgrade {programs}{undefcolor()}')
            lines.append(f'sudo /usr/sbin/slapt-get {localops}--upgrade {programs}\n')
        execute(lines)
        return True
    else:
        return False

def slapt_src(style, color, command, options, programs=""):
    localops = ''
    localcmd = ''
    if command in ['u', 'update']:
        localcmd = '-u'
    if command in ['s', 'search']:
        localcmd = '--search'
    if command in ['b', 'build']:
        localcmd = '--build'
    if command in ['i', 'install']:
        localcmd = '--install'
    if command in ['c', 'clean']:
        localcmd = '--clean'
    if command in ['r', 'remove']:
        return
    if command in ['l', 'list']:
        localcmd = '--list'
    for op in options.split():
        if op == '-y':
            localops = localops + "-y "
    localops = localops.strip()
    if localcmd != "":
        print(f'{defcolor(style, color)}Silk> sudo /usr/bin/slapt-src {localops}{localcmd} {programs}{undefcolor()}')
        lines = ['#!/bin/bash\n\n', f'sudo /usr/bin/slapt-src {localops}{localcmd} {programs}\n']
        if localcmd == '-u':
            print(f'{defcolor(style, color)}Silk> sudo /usr/bin/slapt-src {localops}--upgrade-all {programs}{undefcolor()}')
            lines.append(f'sudo /usr/bin/slapt-src {localops}--upgrade-all {programs}\n')
        execute(lines)
        return True
    else:
        return False

def sbopkg(style, color, command, options, programs=""):
    if command in ['u', 'update']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -r{undefcolor()}')
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -c{undefcolor()}')
        lines = ['#!/bin/bash\n\n',
                 f'sudo /usr/sbin/sbopkg -r\n',
                 f'sudo /usr/sbin/sbopkg -c | sudo tee /tmp/silkout \n',
                 'cat /tmp/silkout | egrep ":$" | cut -d":" -f1 | tr \"\\n\" \" \" > /tmp/silktmp\n',
                 f'sudo /usr/sbin/sbopkg -i "`cat /tmp/silktmp`"\n']
        execute(lines)
        return True
    elif command in ['s', 'search']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -g "{programs}"{undefcolor()}')
        lines = ['#!/bin/bash\n\n', f'sudo /usr/sbin/sbopkg -g "{programs}"\n']
        execute(lines)
        return True
    elif command in ['b', 'build']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -b "{programs}"{undefcolor()}')
        lines = ['#!/bin/bash\n\n', f'sudo /usr/sbin/sbopkg -b "{programs}"\n']
        execute(lines)
        return True
    elif command in ['i', 'install']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -i "{programs}"{undefcolor()}')
        lines = ['#!/bin/bash\n\n', f'sudo /usr/sbin/sbopkg -i "{programs}"\n']
        execute(lines)
        return True
    elif command in ['c', 'clean']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -o{undefcolor()}')
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -P{undefcolor()}')
        lines = ['#!/bin/bash\n\n',
                 f'sudo /usr/sbin/sbopkg -o\n',
                 f'sudo /usr/sbin/sbopkg -P\n']
        execute(lines)
        return True
    elif command in ['r', 'remove']:
        lines = ['#!/bin/bash\n\n']
        for pkg in programs.split():
            print(f'{defcolor(style, color)}Silk>sudo sbin/removepkg {pkg}{undefcolor()}')
            lines.append(f'sudo /sbin/removepkg {pkg}\n')
        execute(lines)
        return True
    elif command in ['l', 'list']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/sbopkg -p | cat{undefcolor()}')
        lines = ['#!/bin/bash\n\n',
                 f'sudo /usr/sbin/sbopkg -p | cat\n']
        execute(lines)
        return True
    else:
        return False

def slackpkg(style, color, command, options, programs=""):
    localops = ''
    for op in options.split():
        if op == '-y':
            localops = localops + "-batch=on -default_answer=y "
    localops = localops.strip()
    if command in ['u', 'update']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}update{undefcolor()}')
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}install-new{undefcolor()}')
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}upgrade-all{undefcolor()}')
        lines = ['#!/bin/bash\n\n',
                 f'sudo /usr/sbin/slackpkg {localops}update\n',
                 f'sudo /usr/sbin/slackpkg {localops}install-new\n',
                 f'sudo /usr/sbin/slackpkg {localops}upgrade-all\n']
        execute(lines)
        return True
    elif command in ['s', 'search']:
        lines = ['#!/bin/bash\n\n']
        for pkg in programs.split():
            print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}search {pkg}{undefcolor()}')
            lines.append(f'sudo /usr/sbin/slackpkg {localops}search {pkg}\n')
        execute(lines)
        return True
    elif command in ['b', 'build']:
        lines = ['#!/bin/bash\n\n']
        for pkg in programs.split():
            print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}download {pkg}{undefcolor()}')
            lines.append(f'sudo /usr/sbin/slackpkg {localops}download {pkg}\n')
        execute(lines)
        return True
    elif command in ['i', 'install']:
        lines = ['#!/bin/bash\n\n']
        for pkg in programs.split():
            print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}install {pkg}{undefcolor()}')
            lines.append(f'sudo /usr/sbin/slackpkg {localops}install {pkg}\n')
        execute(lines)
        return True
    elif command in ['c', 'clean']:
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg {localops}clean-system{undefcolor()}')
        lines = ['#!/bin/bash\n\n',
                 f'sudo /usr/sbin/slackpkg {localops}clean-system\n']
        execute(lines)
        return True
    elif command in ['r', 'remove']:
        lines = ['#!/bin/bash\n\n']
        for pkg in programs.split():
            print(f'{defcolor(style, color)}Silk> sudo sbin/removepkg {pkg}{undefcolor()}')
            lines.append(f'sudo /sbin/removepkg {pkg}\n')
        execute(lines)
        return True
    elif command in ['l', 'list']:
        print(f'{defcolor(style, color)}Silk> sudo rm -rf /etc/slackpkg/templates/silk.template{undefcolor()}')
        print(f'{defcolor(style, color)}Silk> sudo /usr/sbin/slackpkg generate-template silk{undefcolor()}')
        print(f'{defcolor(style, color)}Silk> cat /etc/slackpkg/templates/silk.template{undefcolor()}')
        lines = ['#!/bin/bash\n\n',
                 'sudo rm -rf /etc/slackpkg/templates/silk.template\n',
                 'sudo /usr/sbin/slackpkg generate-template silk\n',
                 'cat /etc/slackpkg/templates/silk.template\n',]
        execute(lines)
        return True
    else:
        return False

def setconfig():
    home = os.path.expanduser('~')
    rc = f'{home}/.config/silkrc'
    config = configparser.ConfigParser()
    createfile=False
    if os.path.isfile(rc):
        config.read(rc)
        if (config.get('settings','version') != SILKRC_VERSION):
            createfile = True
        else:
            print(f'Loaded {home}/.config/silkrc\n')
    else:
        createfile = True
    if createfile:
        setcolor(BOLD, RED)
        print(f'Warning: {home}/.config/silkrc config file is invalid/older, creating a new one...\n')
        resetcolor()
        with open(f'{home}/.config/silkrc', 'w') as file:
            file.writelines('[settings]\n')
            file.writelines('version = ' + str(SILKRC_VERSION) + '\n\n')
            file.writelines('slapt-get-colors = BOLD RED\n')
            file.writelines('slapt-src-colors = BOLD YELLOW\n')
            file.writelines('sbopkg-colors = BOLD GREEN\n')
            file.writelines('slackpkg-colors = BOLD BLUE\n\n')
            file.writelines('# order of execution (write 0 to prevent running):\n')
            file.writelines('slapt-get = 1\n')
            file.writelines('slapt-src = 2\n')
            file.writelines('sbopkg = 0\n')
            file.writelines('slackpkg = 4\n')
        config.read(rc)
    return config

def main():
    os.system('clear')
    config = setconfig()

    if (len(sys.argv[1:]) == 0):
        usage(config)
    else:
        command = sys.argv[1]
        options = ""
        programs = ""
        for arg in sys.argv[2:]:
            if arg[0] == '-':
                options=options + " " + arg
            else:
                programs = programs + " " + arg

        sequence = '1234'
        for x in options.split():
            if x[0:2] == '-o':
                sequence = x[2:]
        for t in sequence:
            for f in FUNCS:
                fsetting = f.__name__.replace('_','-')
                if str(t) == config.get('settings',fsetting):
                    c = config.get('settings', fsetting + '-colors').split()
                    if not f(style2int(c[0]), color2int(c[1]), command, options, programs):
                        usage(config)
                        resetcolor()
                        return
                    print()
                    resetcolor()

if __name__ == '__main__':
    FUNCS = [slapt_get, slapt_src, sbopkg, slackpkg]
    main()


