#!/bin/sh

########## ####      ####
########## ####      ####
##      ## ##  ##  ##  ##
##      ## ##  ##  ##  ##
########## ##    ##    ## - PACKAGE MANAGER FOR SIMPLE LINUX
########## ##    ##    ## - AUTHOR -- TOLA MIRONCENKO
##         ##          ##
##         ##          ##
##         ##          ##
##         ##          ##

#---------------- variables --------------------------
version="1.0.0"
export rootdir=/
repofile=$rootdir/etc/pm/repo
packagesqueryfile=$rootdir/usr/share/pm/query
reposquerydir=$rootdir/usr/share/pm/repos
cachedpkgdir=$rootdir/var/cache/pm/pkg
installedpackagesdir=$rootdir/usr/share/pm/packages
command=""
packages=""
archives=""
#-----------------------------------------------------

#----- colors -------
RESET="\033[0m"
GREEN="\033[0;32m"
RED="\033[0;31m"
BRED="\033[1;31m"
YELLOW="\033[1;33m"
BWHITE="\033[1;37m"
BBLUE="\033[1;34m"
BGREEN="\033[1;32m"
#--------------------

#------------ check status function ------------
check() {
    [ $1 -ne 0 ] \
        && printf "$BBLUE**$BWHITE $2 [$BRED ERROR $BWHITE]\n$RESET" \
        && exit $1
    printf "$BBLUE**$BWHITE $2 [$BGREEN SUCCESS $BWHITE]\n$RESET"
}
#-----------------------------------------------

#---------------- check root priveleges function ------------------------
checkroot() {
    [[ $(id -u) != 0 ]] \
        && printf "$BBLUE**$BWHITE You must be root [$BRED ERROR $BWHITE]\n$RESET" \
        && exit 1
}
#------------------------------------------------------------------------

# check non root priveleges function
checknonroot() {
    [[ $(id -u) == 0 ]] \
        && printf "$BBLUE**$BWHITE You must be non root [$BRED ERROR $BWHITE]\n$RESET" \
        && exit 1
}
# ----------------------------------

#----------------- add(install) package function ------------------------
add() {
    [[ "$packages" == "" ]] \
        && help \
        && exit 0
    down
    for i in $packages; do
        archives="$archives $(echo $cachedpkgdir/$i*.pkg.gz)"
    done
    unpack
}
a() {
    add
}
#------------------------------------------------------------------------

#-------------------- download package without install function ---------
down() {
    [[ "$packages" == "" ]] \
        && help \
        && exit 0
    for k in $packages; do
        downloaded=n
        servers=$(/usr/bin/cat $repofile)
        check $? "Read repositories"
        for i in $servers; do
            serverdir=$(echo $i | sed -e "/http:\/\//s///")
            serverdir=$(echo $serverdir | sed -e "/ftp:\/\//s///")
            repoquery=$(/usr/bin/cat $reposquerydir/$serverdir/query | sed -e '/.pkg.gz/s///')
            for j in $repoquery; do
                if [[ "$(get_pkgname $j)" == "$k" ]]; then
                    if [ ! -f $cachedpkgdir/$j.pkg.gz ]; then
                        printf "$YELLOW**$RESET Downloading $YELLOW$serverdir: $Bwhite$j\n$RESET"
                        echo $i/$j.pkg.gz
                        wget $i/$j.pkg.gz -P $cachedpkgdir
                        check $? "Download package"
                    else
                        printf "$YELLOW**$GREEN successful downloaded $k\n$RESET"
                        downloaded=y
                    fi
                    downloaded=y
                fi
            done
        done
        if [ "$downloaded" == "n" ]; then
            printf "$BBLUE**$BWHITE Can't find package $k [$BRED ERROR $BWHITE]\n$RESET"
        fi
        continue
    done
}
download() {
    down
}
#------------------------------------------------------------------------

#-------------------- unpack local package archive ----------------------
unpack() {
    [[ "$archives" == "" ]] \
        && printf "$BBLUE**$BWHITE Specify package name [$BRED ERROR $BWHITE]\n$RESET" \
        && exit 1
    for i in $archives; do
        if [ ! -f $i ]; then
            printf "$BBLUE**$BWHITE File $i not found [$BRED ERROR $BWHITE]\n$RESET" \
            && exit 1
        fi
        packagename=$(echo $i | sed -e "/.gz/s///")
        packagename=${packagename#*pkg/}
        printf "$YELLOW**$GREEN Installing ${packagename%.pkg*}\n$RESET"
        [ ! -f $packagesqueryfile ] \
            && printf "$BBLUE**$BWHITE Can't find $packagesqueryfile [$BRED ERROR $BWHITE]\n$RESET" \
            && exit 1
        installed=false
        for i in $(/usr/bin/cat $packagesqueryfile); do
            [ "$i" = "${packagename%.pkg*}" ] \
                && export installed=true \
                && break
        done
        [[ "$installed" == "true" ]] \
            && printf "$YELLOW**$RESET Package already installed:$YELLOW reinstalling\n$RESET"
        tar -xf $cachedpkgdir/$packagename.gz -C $rootdir/tmp
        cd $rootdir/tmp/$packagename
        [ -f pre_install ] \
            && /usr/bin/sh -c ./pre_install \
            && rm -v pre_install &> /dev/null
        if [ -f deps ]; then
            printf "$YELLOW**$GREEN Checking deps\n$RESET"
            deps=$(/usr/bin/cat deps)
            for dep in $deps; do
                have=false
                for pack in $(/usr/bin/cat $packagesqueryfile); do
                    if [ $pack = $dep ]; then
                        have=yes
                        break
                    fi
                done
                if [ "$have" = "false" ]; then
                    pkgnow=$packagename
                    add "" $dep
                    unpack $cachedpkgdir/$pkgnow.gz
                    return
                fi
            done
            mkdir $installedpackagesdir/$packagename &> /dev/null
            mv -v deps $installedpackagesdir/$packagename &> /dev/null
        fi
        mkdir $installedpackagesdir/$packagename &> /dev/null
        mv -v list $installedpackagesdir/$packagename &> /dev/null
        [ -f pre_delete ] \
            && mv -v pre_delete $installedpackagesdir/$packagename &> /dev/null
        [ -f post_delete ] \
            && mv -v post_delete $installedpackagesdir/$packagename &> /dev/null
        cp -r ./* $rootdir/
        [ -f $rootdir/post_install ] \
            && rm $rootdir/post_install
        [ -f $rootdir/tmp/$packagename/post_install ] \
            && printf "$YELLOW**$GREEN post_install script ${packagename%.pkg*}\n$RESET" \
            && /usr/bin/sh -c $rootdir/tmp/$packagename/post_install &> /dev/null
        [[ "$installed" == "false" ]] \
            && echo ${packagename%.pkg*} >> $packagesqueryfile
        rm -rv $rootdir/tmp/$packagename &> /dev/null
        printf "$YELLOW**$GREEN Installed ${packagename%.pkg*} successful\n$RESET"
        cd - &> /dev/null
    done
}
u() {
    unpack
}
#------------------------------------------------------------------------

#------------------ delete package function -----------------------------
del() {
    printf "$YELLOW**$GREEN deleting\n$RESET"
    for i in $packages; do
        printf "$YELLOW**$GREEN deleting $i\n$RESET"
        [ ! -f $installedpackagesdir/$i*.pkg/list ] \
            && printf "$BBLUE**$BWHITE package not installed ($i) [$BRED ERROR $BWHITE]\n$RESET" \
            && exit 1
        [ -f $installedpackagesdir/$i*.pkg/pre_delete ] \
            && /usr/bin/sh -c $installedpackagesdir/$i*.pkg/pre_delete
        for file in $(/usr/bin/cat $installedpackagesdir/$i*.pkg/list); do
            rm -v $rootdir/$file
        done
        rm -rv $installedpackagesdir/$i*.pkg &> /dev/null
        packs=$(cat $packagesqueryfile)
        rm $packagesqueryfile
        for pack in $packs; do
            if [ "$(get_pkgname $pack)" = "$i" ]; then
                continue
            fi
            echo $pack >> $packagesqueryfile
        done
        [ -f $installedpackagesdir/$i*.pkg/post_delete ] \
            && /usr/bin/sh -c $installedpackagesdir/$i*.pkg/post_delete
        printf "$YELLOW**$GREEN delete $i successful\n$RESET"
    done
}
d() {
    del
}
#------------------------------------------------------------------------

#------------------- list files in package function ---------------------
list() {
    if [[ "$packages" == "" ]]; then
        for i in $(/usr/bin/cat $packagesqueryfile); do
            cd $installedpackagesdir
            pkgname=$(echo $(find . -name "$i*") | sed -e "/.\//s///" | sed -e "/.pkg/s///")
            cd - &>/dev/null
            if [[ "$(/usr/bin/cat $packagesqueryfile | grep $i)" == "" ]]; then
                printf "$BBLUE**$BWHITE Package "$i" is not installed [$BRED ERROR $BWHITE]\n$RESET"
                continue
            fi
            filelist=$(/usr/bin/cat $installedpackagesdir/$pkgname*.pkg/list)
            for j in $filelist; do
                printf "$YELLOW$(get_pkgname $pkgname) $BGREEN$(get_pkgver $pkgname)-$(get_pkgrel $pkgname): $BWHITE$j$RESET\n"
            done
            unset pkgname
        done
        exit 0
    fi
    for i in $packages; do
        cd $installedpackagesdir
        pkgname=$(echo $(find . -name "$i*") | sed -e "/.\//s///" | sed -e "/.pkg/s///")
        cd - &>/dev/null
        if [[ "$(/usr/bin/cat $packagesqueryfile | grep $i)" == "" ]]; then
            printf "$BBLUE**$BWHITE Package "$i" is not installed [$BRED ERROR $BWHITE]\n$RESET"
            continue
        fi
        filelist=$(/usr/bin/cat $installedpackagesdir/"${pkgname}".pkg/list)
        for j in $filelist; do
            printf "$YELLOW$(get_pkgname $pkgname) $BGREEN$(get_pkgver $pkgname)-$(get_pkgrel $pkgname): $BWHITE$j$RESET\n"
        done
        unset pkgname
    done
}
l() {
    list
}
#------------------------------------------------------------------------
get_pkgrel() {
    echo $(echo $1 | awk -F'-' '{ print $NF }')
}

get_pkgver() {
    echo $(echo $1 | awk -F'-' '{ print $(NF-1) }')
}

get_pkgname() {
    echo $( echo $(echo $1 | awk -F'-' '{ for (i=NF-2; i>=1; i--) print $i }') | awk -F' ' '{ if (NF==1) { print $NF } else { for (i=NF; i >= 1; i--) { if (i-1 >= 1) { printf $i "-" } else { printf $i } } } }')
}

printpkg() {
    printf "$BWHITE$(get_pkgname $1) $BGREEN$(get_pkgver $1)-$(get_pkgrel $1)\n$RESET"
}

#------------------- show installed packages function -------------------
query() {
    packagesquery=$(/usr/bin/cat $packagesqueryfile)
    [[ "$packagesquery" == "" ]] \
        && printf "$YELLOW**$BWHITE No installed packages\n$RESET" \
        && exit 0
    for i in $packagesquery; do
        printpkg $i
    done
}
q() {
    query
}
#------------------------------------------------------------------------

#--------------------- show help function -------------------------------
help() {
    printf "
        $YELLOW**$GREEN pm usage$RESET :
        $BWHITE add, a [package name] - download and install from repository
         unpack, u [/path/to/package/archive] - unpack(install) from local package archive
         down, download [package name] - download package from repository without install
         del, d [package name] - delete package
         list, l [package name] - list files in package
         search, ss [package name] - search package in repository
         query, q - show installed packages
         help - this help message
         clear - clear all package archives from cached packages directory
         sync, s - synchronize repository
         deps [package name] - show package dependencies
         build - build package (./ must contain PMBUILD)
    \n$RESET"
}
#------------------------------------------------------------------------

#------------------- sync repo function ---------------------------------
sync() {
    servers=$(/usr/bin/cat $repofile)
    for i in $servers; do
        printf "$YELLOW**$GREEN Sync $BWHITE$i\n$RESET"
        serverdir=$(echo $i | sed -e "/http:\//s///")
        serverdir=$(echo $serverdir | sed -e "/ftp:\//s///")
        mkdir -p $reposquerydir/$serverdir &> /dev/null
        wget $i/query -O $reposquerydir/$serverdir/query &> /dev/null
        check $? "Sync $i"
    done
}
s() {
    sync
}
#------------------------------------------------------------------------

#----------------- search package in repo function ----------------------
search() {
    servers=$(/usr/bin/cat $repofile)
    if [[ ! $1 ]]; then
        for i in $servers; do
            serverdir=$(echo $i | sed -e "/http:\/\//s///")
            serverdir=$(echo $serverdir | sed -e "/ftp:\/\//s///")
            repoquery=$(/usr/bin/cat $reposquerydir/$serverdir/query | sed -e '/.pkg.gz/s///')
            for j in $repoquery; do
                installed=false
                for inst in $(/usr/bin/cat $packagesqueryfile); do
                    [ "$(get_pkgname $inst)" = "$(get_pkgname $j)" ] \
                        && export installed=true \
                        && break
                done
                printf "$YELLOW$serverdir: $BWHITE$(get_pkgname $j) $BGREEN$(get_pkgver $j)-$(get_pkgrel $j) $RESET"
                [[ "$installed" == "true" ]] \
                    && printf "$BBLUE[installed]\n$RESET" \
                    || echo ""
            done
        done
        exit 0
    fi
    found=false
    for i in $servers; do
        serverdir=$(echo $i | sed -e "/http:\/\//s///")
        serverdir=$(echo $serverdir | sed -e "/ftp:\/\//s///")
        repoquery=$(/usr/bin/cat $reposquerydir/$serverdir/query | sed -e '/.pkg.gz/s///')
        for j in $repoquery; do
            if [[ $j =~ $1 ]]; then
                printf "$YELLOW$serverdir: $BWHITE$j\n$RESET"
                found=true
            fi
        done
    done
    [ "$found" = "false" ] && printf "$YELLOW**$RED error:$RESET can't find package ($1)\n"
}
ss() {
    search $1
}
#------------------------------------------------------------------------

#------------------- clear cached packages directory --------------------
clear() {
    rm -v $cachedpkgdir/*
}
#------------------------------------------------------------------------

#--- show package dependencies function ---
deps() {
    if [[ "$packages" == "" ]]; then
        for i in $(/usr/bin/cat $packagesqueryfile); do
            cd $installedpackagesdir
            pkgname=$(echo $(find . -name "$i*") | sed -e "/.\//s///" | sed -e "/.pkg/s///")
            cd - &>/dev/null
            printf "$YELLOW$(get_pkgname $pkgname) $BGREEN$(get_pkgver $pkgname)-$(get_pkgrel $pkgname)$BWHITE deps: \n$RESET"
            [ ! -f $installedpackagesdir/${pkgname}.pkg/deps ] \
                && printf "\t$YELLOW**$BWHITE No deps\n$RESET" \
                && continue
            for j in $(cat $installedpackagesdir/${pkgname}.pkg/deps); do
                printf "\t"
                printpkg $j
            done
            unset pkgname
        done
        exit 0
    fi
    for i in $packages; do
        cd $installedpackagesdir
        pkgname=$(echo $(find . -name "$i*") | sed -e "/.\//s///" | sed -e "/.pkg/s///")
        cd - &>/dev/null
        if [ "$pkgname" = "" ]; then
            printf "$BBLUE**$BWHITE Package $i not found [$BRED ERROR $BWHITE]\n$RESET"
            continue
        fi
        printf "$YELLOW$(get_pkgname $pkgname) $BGREEN$(get_pkgver $pkgname)-$(get_pkgrel $pkgname)$BWHITE deps: \n$RESET"
        [ ! -f $installedpackagesdir/${pkgname}.pkg/deps ] \
            && printf "\t$YELLOW**$BWHITE No deps\n$RESET" \
            && continue
        for j in $(cat $installedpackagesdir/${pkgname}.pkg/deps); do
            printf "\t"
            printpkg $j
        done
        unset pkgname
    done
}
#------------------------------------------

#--- build package uses PMBUILD file function ---
buildpkg() {
    if [ ! -f ./PMBUILD ]; then
        if [ "$1" != "" ]; then
            source $1
        else
            printf "$BBLUE**$BWHITE Can't find PMBUILD [$BRED ERROR $BWHITE]\n$RESET"
            exit 1
        fi
    else
        source ./PMBUILD
    fi
     export buildroot=$(pwd)
    if [ -f $buildroot/$pkgname-$pkgver-$pkgrel.pkg.gz ]; then
        if [ "$1" != "-r" ]; then
            printf "$BBLUE**$BWHITE $pkgname-$pkgver-$pkgrel.pkg.gz already exists please use -r to rebuild [$YELLOW WARNING $BWHITE]\n$RESET"
            exit 0
        else
            [ -d pkg ] && rm -rf pkg
            [ -d src ] && rm -rf src
            [ -f $pkgname-$pkgver-$pkgrel.pkg.gz ] \
                && rm -rf $pkgname-$pkgver-$pkgrel.pkg.gz
        fi
    fi
    [ ! -d src ] && mkdir -p src
    [ ! -d pkg/$pkgname-$pkgver-$pkgrel.pkg ] \
        && mkdir -p pkg/$pkgname-$pkgver-$pkgrel.pkg
    export pkgdir=$buildroot/pkg/$pkgname-$pkgver-$pkgrel.pkg
    [ "$srcdir" = "" ] && export srcdir=$buildroot/src/$pkgname
    [ "$gitsource" != "" ] \
        && printf "$BBLUE**$BWHITE Downloading sources\n$RESET" \
        && git clone $gitsource $srcdir \
        && check $? "Download sources"
    if [ "$source" != "" ]; then
        printf "$BBLUE**$BWHITE Downloading sources\n$RESET"
        [ ! -d $srcdir ] && mkdir -p $srcdir
        cd $srcdir
        [ ! -f $pkgname-$pkgver.tar.* ] && wget $source
        cd -
    fi
    if [[ $(type -t configure) = function ]]; then
        printf "$BBLUE**$BWHITE Configuring package\n$RESET"
        configure
        check $? "Configure"
    fi
    if [[ $(type -t build) = function ]]; then
        printf "$BBLUE**$BWHITE Building package\n$RESET"
        build
        check $? "Build"
    else
        echo "no build"
    fi
    if [[ $(type -t package) == function ]]; then
        printf "$BBLUE**$BWHITE Packaging package\n$RESET"
        package
        check $? "Package"
    else
        echo "no package"
    fi
    printf "$BBLUE**$BWHITE Stripping unneded symbols\n$RESET"
    STRIP=$(which strip)
    if [ -n "$CROSS_COMPILE" ]; then
        STRIP=$CROSS_COMPILE-strip
    fi
    for execfile in $(find $pkgdir -executable -type f); do
        $STRIP $execfile
    done
    printf "$BBLUE**$BWHITE Strip unneded symbols [$BGREEN SUCCESS $BWHITE]\n$RESET"
    cd $pkgdir
    find -type f > $buildroot/list
    find -type l >> $buildroot/list
    sed -i "s/.\///" $buildroot/list
    sed -i 's/usr\/sbin//g' $buildroot/list
    sed -i 's/usr\/lib64//g' $buildroot/list
    sed -i 's/usr\/lib32//g' $buildroot/list
    cd $buildroot
    mv list $pkgdir/list
    if [ "$deps" != "" ]; then
        for i in $deps; do
            echo $i >> $pkgdir/deps
        done
    fi
    cd $pkgdir
    printf "$BBLUE**$BWHITE Archiving package\n$RESET"
    tar -czf $buildroot/$pkgname-$pkgver-$pkgrel.pkg.gz .. &> /dev/null
    check $? "Archive package"
    cd $buildroot
    unset pkgdir srcdir buildroot
}
#-----------------------------------------------------
parse_command() {
    while [ $1 ]; do
        case "$1" in
            add|a|del|d)
                command=$1
                shift
                packages=$@
                break;
                ;;
            s|sync|clear|down|download)
                command=$1
                shift
                packages=$@
                break;
                ;;
            unpack|u)
                command=$1
                shift
                archives=$@
                break;
                ;;
            query|q|search|ss|list|l|deps)
                command=$1
                shift
                packages=$@
                break
                ;;
            build)
                checknonroot
                buildpkg $@
                ;;
            *)
                shift
                ;;
        esac
    done
}
parse_opts() {
    while [ $1 ]; do
        case "$1" in
            -h|--help)
                help
                exit 0
                ;;
            -r|--rootdir)
                rootdir=$2
                shift 2
                ;;
            *)
                if [ "${1#--}" != "$1" ]; then
                    echo "Invalid option: $1" >&2
                    help
                    exit 1
                fi
                shift
                ;;
        esac
    done
}

#--- main ---
main() {
    parse_command "$@"
    parse_opts "$@"
    if [ -z "$command" ]; then
        help
        exit 1
    fi
    $command
}
#------------

main $@
