#!/bin/sh

REPOSITORY="${HOME}/.collections"
mkdir -p "$REPOSITORY"
test -f "${REPOSITORY}/current" && . "${REPOSITORY}/current"

if [ -n "$CONTEXT" ]
then
	REPO="${REPOSITORY}/${CONTEXT}/"
	cd "$REPO"
	test ! -d ".git" && git init
else
	printf 'No current collection in use\n'
fi

# return if an item exists
# $1 identifier
exists() {
    cd "$REPO"
    ls */"$1" >/dev/null 2>&1
    return $?
}

# displays the values of an identifier
# $1 identifier
show() {
    cd "$REPO"
    if exists "$1"
    then
	    SEEN=0
	    for attribute in *
	    do
		if [ -f "${attribute}/${1}" ]
		then
		    if [ "$SEEN" -eq 0 ]
		    then
			printf "%s:\n" "$1"
			SEEN=1
		    fi
			printf "%15s: %s\n" "$attribute" "$(cat "${attribute}/${1}")"
		fi
	    done
	    exit 0
    else
        printf '%s is not in the library.\n' "$1"
        exit 1
    fi
}

# displays the list of values per attributes
show_attributes_values() {
    cd "$REPO"
    for attribute in *
    do
	    printf "%s:\n" "$attribute"
	    awk '{ print }' "${attribute}"/* | sort | uniq | sed 's/^/    /'
    done
    exit 0
}

# import data from a csv
# $1 is the file to import
import_csv() {
    git tag "Importing CSV"
    awk -F "," '{
        if(NR==1) {
	    for(i=1;i<=NF;i=i+1) {
	        headers[i] = $i
	    }
        } else {
	    out = $1;
	    for(i=2;i<=NF;i=i+1) {
	        if(! match($i,/^""$/) && $i !="") {
		    out = out " "headers[i]" "$i;
	        }
	    }
	    if(out==$1) {
	        print "empty"
	    } else {
	        out=out "\n"
		print out
		system("dossier "out)
	    }
        }
    }' "$1"
}

# export the data in csv format "data","data","data"
# we assume it'll works with the dataset
export_csv() {
    cd "$REPO"

    # display header
    printf '"identifier"'
    find . -name '.git' -prune -o -type f -print | cut -d '/' -f 2 | sort | uniq | while read attr
    do
        printf ',"%s"' $attr
    done
    printf '\n'

    # print database
    find . -name '.git' -prune -o -type f -print | cut -d '/' -f 3 | sort | uniq | while read id
    do
        printf '"%s",' "$id"
	FIRST=0
        find . -name '.git' -prune -o -type f -print | cut -d '/' -f 2 | sort | uniq | while read attr
        do
	    if [ "$FIRST" -eq 0 ]
	    then
		    FIRST=1
	    else
		    printf ","
	    fi
	    # for faster processing, we do not check existence of file before
            awk '{ printf "\"%s\"",$0}' "${attr}/${id}" 2>/dev/null  \
                || printf '""'
        done
        printf '\n'
    done
    IFS=$OLDIFS
    exit 0
}

# delete identifier from attributes
# $1 identifier
delete() {
    cd "$REPO"
    SEEN=0
    for attribute in *
    do
        if [ -f "${attribute}/${1}" ]
        then
	    git rm "${attribute}/${1}"
	    git commit -m "Delete ${attribute} ${1}" "${attribute}/${1}"
            rmdir "$attribute" 2> /dev/null
            SEEN=1
        fi
    done

    # did we find it?
    if [ "$SEEN" -eq 0 ]
    then
        printf "%s is not in the library!\n" "$1"
        exit 1
    else
        exit 0
    fi
}

# displays list of identifiers
show_list() {
    cd "$REPO"
    find . -name '.git' -prune -o -type f -print | cut -d '/' -f 3 | sort | uniq -c | \
        awk '{ for(i=2;i<=NF;i=i+1) { printf "%s ", $i }
               printf "(%i)\n", $1
        }'
    exit 0
}

# displays attributes used
show_attributes() {
    cd "$REPO"
    find . -name '.git' -prune -o -type f -print | cut -d '/' -f 2 | sort | uniq -c | \
        awk '{ for(i=2;i<=NF;i=i+1) { printf "%s ", $i }
                   printf "(%i)\n", $1
        }'
    exit 0
}

# add/modify a value
# $@ identifier / attr / value / attr / value / ....
# shift to have attr / value again and again
add_value() {
    cd "$REPO"
    ID="$1"
    shift

    while [ "$#" -gt 1 ]
    do
        ATTRIBUTE="$1"
        VALUE="$2"
        shift 2
        
        mkdir -p "$ATTRIBUTE"
        printf '%s' "$VALUE" > "${ATTRIBUTE}/${ID}"
	git add "${ATTRIBUTE}/${ID}"
	git commit -m "Modify ${ATTRIBUTE} on ${ID}" "${ATTRIBUTE}/${ID}"
    done
    exit 0
}

# returns identifiers having attribute=value
# $1 attribute
# $2 value
search_value() {
    cd "$REPO"
    shift

    RESULT=$(mktemp /tmp/dossier.XXXXXXXXXXXX)
    COUNT=0
    if [ -f "$RESULT" ]
    then
	    while [ "$#" -gt 1 ]
	    do
		ATTRIBUTE="$1"
		NEGATE=""
		if [ "${ATTRIBUTE#!}" -ne "${ATTRIBUTE}" ]
		then
			ATTRIBUTE="${ATTRIBUTE#!}"
			NEGATE=v
		fi
		VALUE="$2"
		shift 2
		if [ ! -d "$ATTRIBUTE" ]
		then
			printf 'The attribute %s do not exists\n' "$ATTRIBUTE"
			exit 5
		fi
		grep "-rl${NEGATE}" "$VALUE" "$ATTRIBUTE" | cut -d '/' -f 2 >> "$RESULT"
		COUNT=$(( COUNT + 1 ))
	    done
	    sort "$RESULT" | uniq -c | \
		    awk -v count=$COUNT \
		    '{ if($1==count) {
	                $1=""               # remove uniq result
			gsub(/^[ ]+/,"",$0) # remove leading space due to uniq
			print
		    }}'
    else
	    printf 'Cannot create a temporary file in /tmp\n'
	    exit 6
    fi

    exit 0
}

# returns list of identifiers in a attribute
# $1 attribute
list() {
    cd "$REPO"
    grep -r . "$1" | cut -d '/' -f 2- | sort
    exit 0
}

# displays usage
usage() {
    printf '%s\n' \
	   "Get help" \
           ": dossier help" \
	   "" \
	   "Export data as CSV" \
           ": dossier export" \
	   "" \
	   "Import data from CSV" \
           ": dossier import file.csv" \
	   "" \
	   "Show collections, register collections, switch current collection" \
           ": dossier collections [register path name] [name]" \
	   "" \
	   "Show items and display informations about an item" \
           ": dossier show [attributes] [identifier]" \
	   "" \
	   "Look at attributes, search items having some values" \
           ": dossier search [attribute [value]] ... [attribute [value]] ..." \
	   "" \
	   "Add / Modify attributes values on an item" \
           ": dossier identifier attribute value ... attribute value ..."
    exit 0   
}

switch() {
	if [ ! -L "${REPOSITORY}/${1}" ]
	then
		printf 'Collection %s is not registered\n' "$1"
		exit 9
	else
		printf 'Switching to collection %s\n' "$1"
		printf 'CONTEXT=%s\n' $1 > "${REPOSITORY}/current"
		exit $?
	fi
}

collections() {
	ls "$REPOSITORY" | grep -v 'current' | sed "s/^${CONTEXT}$/& */"
	exit 0
}

# create symlink to register a collection
# $1 absolute path to collection
# $2 name of collection
register() {
	if [ -d "$1" ]
	then
		if ! expr "$1" : '^/' >/dev/null
		then
			printf 'Aborting, the path of the collection must be an absolute path. %s is not valid\n' "$1"
		fi
		test -L "${REPOSITORY}/${2}" && rm "${REPOSITORY}/${2}"
		ln -s "$1" "${REPOSITORY}/${2}"
		printf "%s registered. Use it as default with\n\t%s collections %s\n" "$2" "$0" "$2"
		exit 0
	else
		printf 'Aborting, %s is not a directory\n' "$2"
		exit 8
	fi
}


# commands not requiring a repository set
if [ "$1" = "help" ]                 ; then usage ; fi

if [ "$1" = "collections" ]; then
	if [ "$#" -eq 1 ]; then collections ; fi
	if [ "$#" -eq 2 ]; then switch "$2" ; fi
	if [ "$2" = "register" ] && [ "$#" -eq 4 ]; then register "$3" "$4" ; fi
fi

# quit if CONTEXT is not set
test -n "$CONTEXT" || exit 10


if [ "$1" = "import" ] && [ -f "${OLDPWD}/${2}" ]; then import_csv "${OLDPWD}/${2}" ; fi
if [ "$1" = "export" ] ; then export_csv ; fi
if [ "$1" = "rm" ] && [ "$#" -eq 2 ] ; then delete "$2" ; fi

# dealing with identifiers
if [ "$1" = "show" ]
then
    if [ "$#" -eq 1 ]; then show_list ; fi
    if [ "$#" -eq 2 ]; then
	    if [ "$2" = "attributes" ]
	    then
		    show_attributes_values
	    else
		    show "$2"
	    fi
    fi
fi

# dealing with attributes
if [ "$1" = "search" ];
then
    if [ "$#" -eq 1 ]; then show_attributes        ; fi
    if [ "$#" -eq 2 ]; then list "$2"              ; fi
    if [ "$#" -ge 3 ]; then search_value "$@" ; fi
fi

if [ "$#" -ge 3 ]; then add_value "$@" ; fi

# no command, maybe it's an item, try it
if [ "$#" -eq 1 ] && exists "$1" ; then show "$1" ; fi

usage
