#!/bin/bash

# Velmi jednoduchý shellový skript pro správu sbírky CD. 
# Copyright (C) 1996-2007 Wiley Publishing Inc.

# Tento program je volně šiřitelným softwarem; můžete jej 
# libovolně distribuovat a/nebo jakkoli upravovat za podmínek 
# GNU General Public License, vydané nadací 
# Free Software Foundation, a to ve verzi 2 této Licence 
# nebo libovolné novější verzi.

# Program distribuujeme v naději, že bude někomu k něčemu
# dobrý, ale je BEZ ZÁRUKY a dokonce i bez předpokládané
# záruky OBCHODOVATELNOSTI nebo VHODNOSTI
# K URČITÉMU ÚČELU. Podrobnější informace najdete 
# v GNU General Public License.

# Spolu s tímto programem byste měli obdržet kopii GNU 
# General Public License; pokud jste ji nedostali, napište na adresu
# Free Software Foundation, Inc., 
# 675 Mass Ave, Cambridge, MA 02139, USA.

menu_choice=""
current_cd=""
title_file="title.cdb"
tracks_file="tracks.cdb"
temp_file=/tmp/cdb.$$
trap 'rm -f $temp_file' EXIT

# Dále nadefinujeme funkce - jak jsme si řekli, ty se musí nacházet ze začátku skriptu, 
# abychom je mohli z dalšího kódu volat. Nejprve nadefinujeme dvě jednoduché utility, 
# díky kterým nebudeme muset stejný kód zapisovat na mnoha místech programu opakovaně.

get_return() {
  echo -e "Stiskněte Enter \c "
  read x
  return 0
}

get_confirm() {
  echo -e "Jste si jist? \c "
  while true
  do
    read x
    case "$x" in
			a | ano | A | Ano | ANO )
				return 0;;
			n | ne | N | Ne | NE )
				echo
				echo "Zrušeno"
				return 1;;
			*) echo "Napište prosím ano nebo ne" ;;
		esac
	done
}

#	Dostáváme se k hlavní funkci pro obsluhu nabídky, set_menu_choice. 
# Konkrétní obsah nabídky se dynamicky mění - pokud je vybrána položka 
# určitého CD, doplní se do ní další volby.
# Nezapomeňte, že příkaz echo -e nemusí být do některých shellů přenositelný.

set_menu_choice() {
	clear
	echo "Volby :-"
	echo
	echo " a) Přidat nové CD"
	echo " f) Hledat CD"
	echo " c) Zjistit počet CD a stop v katalogu"
	if [ "$cdcatnum" != "" ]; then
		echo " l) Vypsat stopy na CD $cdtitle"
		echo " r) Smazat CD $cdtitle"
		echo " u) Aktualizovat informace o stopách na CD $cdtitle"
	fi
	echo " q) Konec"
	echo
	echo -e "Napište prosím písmeno volby a stiskněte Enter \c "
	read menu_choice
	return
}

# Následují ještě dvě velice krátké funkce, insert_title a insert_track, které přidávají 
# informace do databázových souborů. I když někteří lidé takovéto jednořádkové funkce 
# nemají rádi, hodně nám pomáhají zlepšit čitelnost jiných funkcí.
# Jako další v pořadí definujeme výrazně rozsáhlejší funkci add_record_track, 
# která je využívá. Zmíněná funkce nejprve pomocí kontroly shody vzorku ověří, 
# jestli zadaný text neobsahuje čárky (protože ty používáme jako oddělovač polí), 
# a poté pomocí vhodných aritmetických operací zvýší aktuální číslo stopy při přidávání stop:

insert_title() {
  echo $* >> $title_file
  return
}

insert_track() {
  echo $* >> $tracks_file
  return
}

add_record_tracks() {
	echo "Zadejte informace o stopách na tomto CD"
	echo "Po zadání poslední stopy napište q"
	cdtrack=1
	cdttitle=""
	while [ "$cdttitle" != "q" ]
	do
		echo -e "Stopa disku $cdtrack, název stopy? \c "
		read tmp
		cdttitle=${tmp%%,*}
		if [ "$tmp" != "$cdttitle" ]; then
  		echo "Je mi líto, čárky nejsou povoleny"
      continue
    fi
    if [ -n "$cdttitle" ] ; then
      if [ "$cdttitle" != "q" ]; then
        insert_track $cdcatnum,$cdtrack,$cdttitle
      fi
    else
      cdtrack=$((cdtrack-1))
    fi
  cdtrack=$((cdtrack+1))
  done
}

# Funkce add_records umožňuje zadávání hlavních (titulových) informací pro nové CD.

add_records() {
	# Výzva k zadání základních informací 

	echo -e "Zadejte katalogový název \c "
	read tmp
	cdcatnum=${tmp%%,*}

	echo -e "Zadejte titul \c "
	read tmp
	cdtitle=${tmp%%,*}

	echo -e "Zadejte žánr \c "
	read tmp
	cdtype=${tmp%%,*}

	echo -e "Zadejte skladatele nebo interpreta \c "
	read tmp
	cdac=${tmp%%,*}

	# Zjistíme, jestli uživatel skutečně chce zadat informace 

	echo Budu přidávat novou položku 
	echo "$cdcatnum $cdtitle $cdtype $cdac"

	# Po potvrzení přidáme záznam na konec souboru s tituly 

	if get_confirm ; then
		insert_title $cdcatnum,$cdtitle,$cdtype,$cdac
		add_record_tracks
	else
		remove_records
	fi

return
}

# Přecházíme k definici funkce find_cd, která pomocí příkazu grep vyhledává v katalogu
# (souboru s tituly) zadaný název. Zde bychom potřebovali vědět, kolikrát byl požadovaný 
# řetězec nalezen, ale grep vrací jen informaci, jestli byla shoda nalezena nulakrát nebo
# vícekrát. Výsledky hledání musíme proto uložit do souboru, kde bude ke každé shodě jeden
# řádek, a poté zjistit počet řádků tohoto souboru.
# Počet slov zjistíme příkazem wc, který ve svém výstupu mezerami odděluje počet řádků, 
# slov a znaků v souboru. Zápisem $(wc -l $temp_file) načteme z výsledků první parametr 
# a zapíšeme jej do proměnné linesfound. Pokud bychom potřebovali i další parametr, 
# přiřadili bychom výstup z příkazu pomocí konstrukce set do příslušné parametrické 
# proměnné shellu. Do proměnné IFS (Internal Field Separator) musíme zapsat čárku 
# jako požadovaný oddělovač. Alternativou je příkaz cut.

find_cd() {
	if [ "$1" = "n" ]; then
		asklist=n
	else
		asklist=y
	fi
	cdcatnum=""
	echo -e "Zadejte řetězec, který se má vyhledat mezi tituly CD \c "
	read searchstr
	if [ "$searchstr" = "" ]; then
		return 0
	fi

	grep "$searchstr" $title_file > $temp_file

	set $(wc -l $temp_file)
	linesfound=$l

	case "$linesfound" in
	0)  	echo "Je mi líto, nic jsem nenašel"
				get_return
				return 0
		  	;;
	1)    ;;
	2)    echo "Je mi líto, název není jednoznačný."
				echo "Nalezeny záznamy:"
				cat $temp_file
				get_return
				return 0
	esac

	IFS=","
	read cdcatnum cdtitle cdtype cdac < $temp_file
	IFS=" "

	if [ -z "$cdcatnum" ]; then
		echo "Je mi líto, ze $temp_file nemohu načíst pole katalogu"
		get_return
		return 0
	fi

	echo
	echo Katalogové číslo: $cdcatnum
	echo Titul: $cdtitle
	echo Žánr: $cdtype
	echo Skladatel/interpret: $cdac
	echo
	get_return

	if [ "$asklist" = "y" ]; then
		echo -e "Zobrazit stopy tohoto CD? \c "
		read x
		if [ "$x" = "y" ]; then
			echo
			list_tracks
			echo
		fi
	fi
	return 1
}

# Funkce update_cd slouží k aktualizaci, tedy novému zadání informací o CD. Všimněte si,
# že zde pomocí utility grep vyhledáme všechny řádky, které začínají (proto ^) řetězcem 
# $cdcatnum a za ním následuje čárka ,; výraz $cdcatnum musíme zapsat do složených 
# závorek {}, aby mezi jeho hodnotou a čárkou nemusela být při hledání mezera. Do 
# složených závorek {} jsme ve funkci zapsali také skupinu příkazů, které se 
# provádějí, pokud volání get_confirm vrátí true

update_cd() {
	if [ -z "$cdcatnum" ]; then
		echo "Nejprve musíte vybrat CD"
		find_cd n
	fi
	if [ -n "$cdcatnum" ]; then
		echo "Aktuální stopy jsou :-"
		list_tracks
		echo
		echo "Nyní znovu zadáme stopy pro CD $cdtitle"
		get_confirm && {
			grep -v "^${cdcatnum}," $tracks_file > $temp_file
			mv $temp_file $tracks_file
			echo
			add_record_tracks
		}
	fi
	return
}

# Jednoduchá funkce count_cds rychle zjistí počet CD a stop v databázi

count_cds() {
  set $(wc -l $title_file)
  num_titles=$1
  set $(wc -l $tracks_file)
  num_tracks=$1
  echo nalezeno $num_titles CD, na nich celkem $num_tracks stop
  get_return
  return
}

# Funkce remove_records odstraní záznamy z databázových souborů, přičemž příkazem 
# grep -v vyhledá (a poté odstraní) všechny shodné řetězce. Na tomto místě musíme
# použít dočasný soubor; kdybychom zkusili napsat
# grep -v "^$cdcatnum" > $title_file
# pak by se soubor $title_file díky přesměrování > okamžitě smazal, 
# ještě před spuštěním procesu grep - a ten by tím pádem četl z prázdného souboru

remove_records() {
  if [ -z "$cdcatnum" ]; then
		echo Nejprve musíte vybrat CD
    find_cd n
  fi
  if [ -n "$cdcatnum" ]; then
		echo "Nyní odstraníte CD $cdtitle"
    get_confirm && {
      grep -v "^${cdcatnum}," $title_file > $temp_file
      mv $temp_file $title_file
      grep -v "^${cdcatnum}," $tracks_file > $temp_file
      mv $temp_file $tracks_file
      cdcatnum=""
			echo Položka odstraněna
    }
    get_return
  fi
  return
}

#	Také funkce list_tracks volá utilitu grep a hledá s ní požadované řádky; 
# poté příkazem cut ořízne potřebná pole a příkazem more zajistí stránkovaný 
# výstup. Pokud si teď představíte, jak rozsáhlý program by namísto těchto 
# 20 řádků bylo nutné napsat v C, určitě pochopíte, jakým je shell skvělým 
# nástrojem pro programování

list_tracks() {
  if [ "$cdcatnum" = "" ]; then
    echo není vybráno žádné CD
    return
  else
    grep "^${cdcatnum}," $tracks_file > $temp_file
    num_tracks=$(wc -l $temp_file)
    if [ "$num_tracks" = "0" ]; then
			echo pro CD $cdtitle nebyly nalezeny žádné stopy
    else { 
      echo
      echo "$cdtitle :-"
      echo 
      cut -f 2- -d , $temp_file 
      echo 
    } | ${PAGER:-more}
    fi
  fi
  get_return
  return
}

# Tím jsme nadefinovali všechny funkce a konečně se dostáváme k hlavnímu programu.
# Prvních několik řádků upraví veškeré soubory do známého stavu; poté vyvoláme 
# funkci set_menu_choice a zařídíme se podle jejích výsledků.
# Po výběru volby quit smažeme dočasný soubor, vypíšeme zprávu a skončíme skript ve stavu úspěšného ukončení

rm -f $temp_file
if [ ! -f $title_file ]; then
  touch $title_file
fi
if [ ! -f $tracks_file ]; then
  touch $tracks_file
fi

# Nyní následuje vlastní kód aplikace

clear
echo
echo
echo "Mini CD manager"
sleep 1

quit=n
while [ "$quit" != "y" ];
do
  set_menu_choice
  echo $menu_choice;
  case "$menu_choice" in
    a) add_records;;
    r) remove_records;;
    f) find_cd y;;
    u) update_cd;;
    c) count_cds;;
    l) list_tracks;;
    b) 
      echo
      more $title_file
      echo
      get_return;;
    q | Q ) quit=y;;
    *) echo "Je mi líto, volba není platná";;
  esac
done

# Uklidit a skončit 

rm -f $temp_file
echo "Konec"

exit 0
